first commit
This commit is contained in:
88
docs/gaming/games/controller/src/telemetry/telemetry.md
Normal file
88
docs/gaming/games/controller/src/telemetry/telemetry.md
Normal file
@@ -0,0 +1,88 @@
|
||||
# `telemetry` — OpenTelemetry instruments
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Owns the OpenTelemetry instruments emitted by `@suaveplan/controller`:
|
||||
two counters tracking input and state-change throughput per device, and
|
||||
one histogram for the pattern engine's match-attempt duration. Both
|
||||
counters are exercised by `BaseController` via the `recordInput` and
|
||||
`recordStateChange` helpers; the histogram is reserved for the pattern
|
||||
matcher landing in Chunk B/C.
|
||||
|
||||
## Features
|
||||
|
||||
- Lazy-bound meter — instruments resolve against the globally registered
|
||||
`MeterProvider` on first import and fall back to a no-op meter when
|
||||
none is registered. Production callers pay zero cost for OTel.
|
||||
- `controller_inputs_total` counter with `device` + `input` attributes
|
||||
for fine-grained per-input throughput.
|
||||
- `controller_state_changes_total` counter with the `device` attribute.
|
||||
- `controller_pattern_match_duration_ms` histogram (unit `ms`) for the
|
||||
pattern engine.
|
||||
- Typed attribute bundles (`InputCounterAttributes`,
|
||||
`StateCounterAttributes`) prevent string-typo bugs at the call site.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { recordInput, recordStateChange } from "@suaveplan/controller";
|
||||
|
||||
recordInput({ device: "keyboard", input: "up" });
|
||||
recordStateChange({ device: "keyboard" });
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import { metrics } from "@opentelemetry/api";
|
||||
import {
|
||||
AggregationTemporality,
|
||||
InMemoryMetricExporter,
|
||||
MeterProvider,
|
||||
PeriodicExportingMetricReader,
|
||||
} from "@opentelemetry/sdk-metrics";
|
||||
import { recordInput } from "@suaveplan/controller";
|
||||
|
||||
const exporter = new InMemoryMetricExporter(AggregationTemporality.CUMULATIVE);
|
||||
const reader = new PeriodicExportingMetricReader({
|
||||
exporter,
|
||||
exportIntervalMillis: 60_000,
|
||||
});
|
||||
const provider = new MeterProvider({ readers: [reader] });
|
||||
metrics.setGlobalMeterProvider(provider);
|
||||
|
||||
recordInput({ device: "gamepad", input: "a" });
|
||||
await provider.forceFlush();
|
||||
const points = exporter.getMetrics();
|
||||
```
|
||||
|
||||
The same pattern is exercised in the package's polyfill setup; see
|
||||
`tests/setup/polyfills.ts` for the canonical wire-up used by the
|
||||
in-memory MeterProvider assertions.
|
||||
|
||||
## API Reference
|
||||
|
||||
- `inputsCounter: Counter` — OTel counter `controller_inputs_total`.
|
||||
- `stateChangesCounter: Counter` —
|
||||
`controller_state_changes_total`.
|
||||
- `patternMatchDurationHistogram: Histogram` —
|
||||
`controller_pattern_match_duration_ms`.
|
||||
- `recordInput({ device, input }): void` — single-call helper.
|
||||
- `recordStateChange({ device }): void` — single-call helper.
|
||||
- `recordPatternMatchDuration(durationMs): void` — histogram helper.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The instruments are module-scoped so the meter is resolved exactly once
|
||||
per process. Tests inject their `MeterProvider` via
|
||||
`metrics.setGlobalMeterProvider` BEFORE the source module is imported —
|
||||
the package's `tests/setup/polyfills.ts` runs as a setup file and
|
||||
guarantees the binding order. Switching to a deferred-resolve pattern
|
||||
would require every adapter to plumb a meter object through its
|
||||
constructor; the current shape keeps the device-adapter APIs free of
|
||||
observability boilerplate while still allowing override via OTel's
|
||||
`setGlobalMeterProvider` contract.
|
||||
Reference in New Issue
Block a user