Telemetry Cheatsheet
Namespace:Cognesy\\Telemetry\\
TraceContextSpanReferenceObservationTelemetryContinuationInstrumentationProfile
TelemetryTraceRegistryCompositeTelemetryExporter
Telemetrytakesnew TraceRegistry()plus an exporter- use
CompositeTelemetryExporter([...])when you want to fan out to multiple backends - call
flush()after the run to send buffered observations and metrics
packages/metricsowns the metric types —Counter,Gauge,Histogram,Timer(allCognesy\Metrics\Data\*)packages/telemetryowns traces and observations; it does not define a second metric abstractionTelemetry::metric(Metric $metric)accepts a canonical metric and delegates into the metrics layer:
- exporters split by contract:
CanExportObservationsfor traces/logs,CanExportMetricsfor metrics.OtelExporterandLangfuseExporterimplement both; the OTel mapper emits a typed payload per metric type rather than a generic gauge. - metric tags are aggregation dimensions, not span attributes — every tag value must be
low-cardinality (tool names, subagent names, statuses, outcomes, booleans). Per-run identifiers
(
agent.id, execution ids) belong on spans, not tags: one tag value per run means one time series per run in the metrics backend.inference.client.token.usage.*is the single deliberate exception, exempt as a whole — it is correlation-carrying rather than aggregation-friendly, and carries bothinference.execution.idand (from the agents projector)agent.id. SeeMetricNames::TAG_EXECUTION_ID - type policy: event/failure totals ->
Counter, durations ->Timer, point-in-time state ->Gauge, distributions (token counts, steps per run) ->Histogram Cognesy\Telemetry\Domain\Metric\MetricNamesholds the token-usage metric names and theinference.execution.idtag key shared byPolyglotTelemetryProjector,AgentsTelemetryProjectorandLangfusePayloadMapper, so the three cannot drift apart. Metric names used by a single producer (agent.*,inference.embeddings.*) stay private to that producer and are not inMetricNames- full runtime metric catalog, projector by projector:
docs/03-runtime-wiring.md
Live Interop Suite
Run the live backend interop suite from the monorepo root:- tests live under
packages/telemetry/tests/Integration - the suite is opt-in and skips cleanly when disabled
- backend contract tests cover direct exporter write/read interop
- runtime smoke tests cover inference, streaming, agent, and AgentCtrl paths
- inference, streaming, and agent runtime smoke coverage also require
OPENAI_API_KEY - AgentCtrl smoke coverage also requires a usable
codexCLI with working auth/config
Logfire
Basic setup:endpointis the base OTLP URL, not the full/v1/tracespathLogfireExporterrequires eitherLogfireConfigor a custom transport- practical examples:
examples/A03_Troubleshooting/TelemetryLogfire/run.phpexamples/D05_AgentTroubleshooting/TelemetryLogfire/run.phpexamples/D05_AgentTroubleshooting/SubagentTelemetryLogfire/run.php
Langfuse
Basic setup:- Langfuse traces are sent to
/api/public/otel/v1/traces - request-scoped traces fall back to request ids as
session.idvalues - practical examples:
examples/A03_Troubleshooting/TelemetryLangfuse/run.phpexamples/D05_AgentTroubleshooting/TelemetryLangfuse/run.phpexamples/D05_AgentTroubleshooting/SubagentTelemetryLangfuse/run.php
Runtime wiring
For runtime packages, telemetry is usually attached to an event bus throughRuntimeEventBridge
and one or more projectors:
- runtime packages own their local projectors and emit serialized
data['telemetry']envelopes - telemetry core rehydrates the envelope and correlates spans centrally
AgentCtrlTelemetryProjectorcorrelatesagent-ctrlbyexecutionIdagent_ctrl.session_idis continuation metadata, not the primary trace key- request-scoped traces fall back to request ids as
session.idvalues for Langfuse - use the Integration suite when you need live backend proof, not just local payload inspection
Cognesy\\Telemetry\\Adapters\\OTelCognesy\\Telemetry\\Adapters\\LogfireCognesy\\Telemetry\\Adapters\\Langfuse