Dedicated telemetry #

The load simulator sends its clients’ telemetry to a dedicated telemetry backend. This page builds on Getting started.

Target a telemetry backend #

Point pragmaAddress, operatorAddress, and partnerAddress at a shard that has a dedicated telemetry backend enabled. Each client looks up the telemetry backend from its own gateway’s /v1/info, so no telemetry address is configured in the load simulator.

To develop a scenario locally, run the backend with pragma run --backendType ALL and set telemetryHost and telemetryPort on each gateway config so /v1/info advertises the telemetry backend.

Set the telemetry mode #

dedicatedTelemetryMode decides whether clients use the advertised telemetry backend and which session token opens the connection to it. It mirrors the SDK’s DedicatedTelemetryMode.

dedicatedTelemetryMode: USE_SOCIAL_TOKEN
ValueBehavior
OFFNo dedicated telemetry. Telemetry goes to the game or social backend the events belong to.
USE_GAME_TOKEN (default)Telemetry goes to the dedicated telemetry backend, authenticated with the game token. The backend records events under the player id.
USE_SOCIAL_TOKENTelemetry goes to the dedicated telemetry backend, authenticated with the social token. The backend records events under the social id.

The load simulator defaults to USE_GAME_TOKEN. Set OFF to model a fleet running the SDK’s default, and quote it (dedicatedTelemetryMode: "OFF"), because YAML reads a bare OFF as false.

When the mode isn’t OFF but the shard doesn’t advertise a telemetry backend, telemetry falls back to the game or social backend the events belong to.

Send telemetry from a step #

Send a player’s events through ClientWrapper.telemetryService, naming the backend the events belong to. With dedicated telemetry, events for both destinations travel over the dedicated connection; without it, they go to the named backend.

import pragma.clients.TelemetryDestination
import pragma.loadsimulator.ClientWrapper
import pragma.loadsimulator.ICustomStepTracker
import pragma.loadsimulator.LoadSimulatorContext
import pragma.loadsimulator.Step
import pragma.telemetry.TelemetryRpc.TelemetryEvent
import pragma.utils.toUUIDString

//...

class RecordTelemetryStep(context: LoadSimulatorContext, playerCount: Int) : Step("RecordTelemetryStep", context, playerCount) {
    override suspend fun runStep(players: List<ClientWrapper>, tracker: ICustomStepTracker) {
        players.forEach { player ->
            val event = TelemetryEvent.newBuilder()
                .setName("gold_acquired")
                .setJson("""{"playerId": "${player.playerId.toUUIDString()}", "gold": 100}""")
                .build()

            // For events that belong to the social backend, use TelemetryDestination.SOCIAL.
            player.telemetryService.sendEventsOrThrow(TelemetryDestination.GAME, listOf(event), tracker)
        }
    }
}

sendEventsOrThrow fails the step when the batch fails. sendEvents takes the same arguments and returns false instead of throwing. Both wait a random human delay before sending; pass humanDelay = false to skip it.

Sending a PlayerEventsV1Request with player.game.send bypasses this routing and always goes to the game backend.

Send telemetry as a game server or operator #

The partner and operator clients have their own telemetryService. A game server or operator reports for many players, so each event is a SourcedEvent that names its own source. This snippet runs inside a step’s runStep, for one of its players.

import pragma.clients.TelemetryDestination
import pragma.telemetry.TelemetryRpc.SourcedEvent
import pragma.telemetry.TelemetryRpc.TelemetryEvent
import pragma.utils.toUUIDString

//...

val event = SourcedEvent.newBuilder()
    .setSourceId(player.playerId.toUUIDString())
    .setEvent(TelemetryEvent.newBuilder().setName("match_completed").setJson("""{"placement": 1}"""))
    .build()

// For operator telemetry, use loadSimulatorContext.getOperatorClient().
loadSimulatorContext.getPartnerClient().telemetryService.sendEventsOrThrow(TelemetryDestination.GAME, listOf(event), tracker)

The partner client exists only when partnerGameToken and partnerSocialToken are configured. Partner telemetry is sent without a human delay.

Confirm where telemetry went #

The overview at the start of the report records the mode and where each kind of client sent its telemetry:

scenarioOverview:
  dedicatedTelemetryMode: "USE_GAME_TOKEN"
  telemetryRouting: "players: dedicated http://localhost:12000, operators: dedicated http://localhost:12200, partners: dedicated http://localhost:12100"

A client kind without dedicated telemetry shows named backend (no dedicated telemetry), and partners are left out when no partner tokens are configured.

Each step reports its telemetry batches under the request name: PlayerEventsV1Request for players, EventsPartnerV1Request for partners, and EventsOperatorV1Request for operators.

Plan for the extra connection #

A client that uses a dedicated telemetry backend holds a third connection, to the telemetry gateway, alongside its game and social connections. Players heartbeat it like their other connections.

If the telemetry connection drops, the client disconnects as it would for any dropped connection, so telemetry backend failures surface as connection errors in the report. Size the machines running the load simulator for three connections per player instead of two.