Esta página ainda não foi traduzida: mostrando a versão em inglês.
Analytics
Tudo o que precisa ser contado depois, e não visto agora. Declare um evento de telemetria tipado, emita, e ele chega junto com os eventos da própria plataforma: uma fase concluída, uma etapa de funil, um evento econômico, a duração da sessão, um abandono no tutorial. Este módulo emite; ele mesmo não lê, não agrega e não envia nada para lugar nenhum. Para onde um lote vai é decisão do roteador, em Extensibility.
Quando usar
- Algo precisa ser contado depois: uma etapa de funil (funnel), uma fase concluída, um evento econômico, a duração da sessão.
- A comparação precisa sobreviver a novos builds do jogo: o tipo carrega uma versão de esquema, então um funil de um ano atrás não mistura em silêncio dois significados do mesmo campo.
- O volume é alto, e perder uma linha é aceitável se você declarou isso: a telemetria é o único lugar do contrato em que a perda declarada é legítima.
- Dispensável quando alguém precisa reagir. Um evento de telemetria não tem assinante nenhum; um fato que outros precisam ouvir é um evento de jogo.
Quem faz o quê
| Ator | Pode | Não pode |
|---|---|---|
qualquer ator | declarar tipos no esquema; emitir em nome próprio, um por vez ou em lote; ler os tipos declarados | preencher o contexto; ler, consultar ou agregar o que foi emitido |
backend-service | o mesmo, e também emitir em nome de um jogador por delegação | ler a telemetria: não existe permissão de leitura, porque não existe operação de leitura |
Resumo
BossDefeated: campos nomeados e tipados em vez de um blob JSON[Event("boss_defeated")]
public class BossDefeated
{
public string BossId = "";
public int PartySize;
public float FightSeconds;
}
PlayServ.Analytics.Emit(new BossDefeated { BossId = "hydra", PartySize = 4, FightSeconds = 212f });@Event('boss_defeated')
export class BossDefeated {
bossId = '';
partySize = 0;
fightSeconds = 0;
}
PlayServ.analytics.emit(new BossDefeated({ bossId: 'hydra', partySize: 4, fightSeconds: 212 }));@event("boss_defeated")
class BossDefeated:
boss_id: str = ""
party_size: int = 0
fight_seconds: float = 0.0
playserv.analytics.emit(BossDefeated(boss_id="hydra", party_size=4, fight_seconds=212.0))Ainda não está decidido como declarar com atributos em Go (O-1). Os exemplos chegam quando a forma de escrita for escolhida.
USTRUCT(PSEvent = (Name = "boss_defeated"))
struct FBossDefeated
{
GENERATED_BODY()
UPROPERTY() FString BossId;
UPROPERTY() int32 PartySize;
UPROPERTY() float FightSeconds;
};
// declarations compile into the same pushed model — playserv push from the UE project or CI
// the declared type becomes a generated member under the Emit node
Client->Analytics->Emit->BossDefeated({ TEXT("hydra"), /*PartySize*/ 4, /*FightSeconds*/ 212.f });
// co_await support ships later: a built-in SDK coroutine wrapper that respects Unreal's GC and threading.[Event("boss_defeated")]
public class BossDefeated
{
public string BossId = "";
public int PartySize;
public float FightSeconds;
}
PlayServ.Analytics.Emit(new BossDefeated { BossId = "hydra", PartySize = 4, FightSeconds = 212f });A definição faz parte do esquema, então o que chega traz campos nomeados e tipados, e não um blob JSON. Ela é declarada como um tipo próprio, e não como um evento de jogo com uma flag.
O modelo
O que um tipo de evento de telemetria declara.
| Declara | O que é |
|---|---|
name | o nome do próprio tipo |
fields | tipados pelo sistema de tipos da plataforma; uma máscara de campos se aplica a eles como em qualquer outro lugar |
versão do esquema | obrigatória, e não derivada da versão do SDK: um funil compara eventos coletados em builds diferentes do jogo, e sem versão a comparação mistura em silêncio o que não é comparável |
sampling | que fração dos eventos deste tipo passa. É declarada no tipo, nunca escolhida pela implementação conforme a carga: uma fração que mudasse sozinha tornaria os funis incomparáveis de um dia para o outro |
tolerância a perdas | se este tipo tolera perdas |
comportamento na exclusão | como a exclusão de um jogador chega a este tipo: apagando ou anonimizando. O estúdio declara a política; o módulo a executa |
O que vale para todo evento de telemetria.
| Sempre | O que é |
|---|---|
nenhum destino de endereçamento | nenhum destinatário, nenhum grupo, nenhuma assinatura. Querer endereçar alguém é sinal de que o que você precisa é de um evento de jogo |
o contexto | é da plataforma: ela adiciona o ator ou uma marca de anonimato, a sessão, o ambiente, a versão do build e o momento pelo relógio declarado. Quem chama não pode preencher o contexto: se tentar trocar o ator ou a versão do build, recebe os valores derivados no lugar dos que passou |
a fração de amostragem | vai junto com o evento: sem ela, não dá para reconstruir o número absoluto a partir do que chegou |
a perda | pode ser observada no agregado: a fração não entregue num período fica disponível para quem consome os dados; não há promessa de observar cada item, porque, no volume da telemetria, uma mensagem por perda viraria ela mesma um fluxo |
a emissão | não é idempotente: duas chamadas são dois fatos, e ela não aceita chave de idempotência, porque suprimir a segunda perderia dados. Não existe como saber o resultado de uma emissão perdida, e nem se quer isso: a tolerância a perdas é declarada de antemão, para todas as chamadas de uma vez |
os eventos | são o histórico: o módulo não guarda nenhum histórico próprio |
Erros
- Um tipo não declarado e um campo que não bate com o esquema do tipo são recusas de validação; nenhum dos dois é surpresa em runtime, porque um tipo chega ao console de administração a partir da sua declaração.
- Um evento grande demais é uma recusa de validação; os campos nunca são cortados em silêncio.
- A frequência excedida responde na categoria de limite de frequência, com o momento antes do qual não adianta tentar de novo.
- O descarte por amostragem não é um erro, e uma perda admissível também não. A chamada foi executada, e o descarte é um comportamento declarado; reportar qualquer um dos dois como falha tornaria o comportamento declarado indistinguível de um defeito.
- Um lote é tratado inteiro ou por elemento, e qual dos dois é declarado, nunca “o que acontecer”.
Limites
Os números chegam com o capítulo de limites da plataforma; o que acontece em cada teto já está definido.
- Frequência de eventos por ator: recusa por limite de frequência, com prazo. Exceder a frequência nunca descarta em silêncio: ou é essa recusa, ou é um descarte por amostragem declarado.
- Tamanho de um evento: recusa de validação, nunca campos cortados em silêncio.
- Tamanho do lote: rejeitado antes do envio, em vez de aplicado em parte.
- Tipos declarados por projeto: uma nova declaração é rejeitada no deploy, não em runtime.
- Campos num tipo: o mesmo, no deploy.
- Período de retenção: passado o período declarado, o evento deixa de estar disponível.