Skip to main content

OpenTelemetry export

Nora can export its agent telemetry under the OpenTelemetry GenAI semantic conventions (gen_ai.*), so per-agent token usage, estimated cost, and runtime resource metrics flow into the Datadog / Grafana / Langfuse / Honeycomb stack you already operate — no Nora-specific agent or scraper required. It is disabled by default and fail-open: a collector outage or misconfiguration never affects chat or any other request path.

What gets exported

Spans (OTLP only): one chat span per recorded LLM exchange, with gen_ai.operation.name=chat, gen_ai.request.model, gen_ai.system (provider), gen_ai.usage.input_tokens / output_tokens, gen_ai.conversation.id (session), and nora.agent.id / nora.runtime.family / nora.sandbox.profile / nora.source. The span is bracketed around the runtime call, so its duration reflects real latency. Metrics (OTLP and/or Prometheus):
InstrumentTypeNotes
gen_ai.client.token.usagehistogramTokens per exchange, split by gen_ai.token.type (input / output)
nora.agent.cost.usdcounterEstimated spend, attributed by agent + model, using the same model-aware pricing as /app/cost
nora.agent.cpu.percentgaugeLatest sampled container CPU per running agent
nora.agent.memory.percentgaugeLatest sampled container memory percent per running agent
nora.agent.memory.usagegaugeLatest sampled container memory (MB) per running agent
Nora observes telemetry at the exchange granularity it actually receives from the runtimes. Per-LLM-call and per-tool-call sub-spans depend on event streams OpenClaw and Hermes do not currently expose to the control plane, and are tracked as a future enhancement. A2A Agent Cards are likewise on the roadmap.

Enable it

Set the master switch and at least one exporter, then restart the backend:
NORA_OTEL_ENABLED=true

# OTLP/HTTP push — metrics AND spans (an OpenTelemetry Collector, Grafana Alloy,
# or a vendor OTLP endpoint). Auth headers are read natively by the exporters.
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318
# OTEL_EXPORTER_OTLP_HEADERS=authorization=Bearer%20<token>
OTEL_SERVICE_NAME=nora-control-plane

# Prometheus pull — metrics only (0 or empty disables). Defaults to loopback;
# the scrape surface is unauthenticated and exposes agent/model/provider labels,
# so widen the bind only behind an internal network or firewall.
NORA_OTEL_PROMETHEUS_PORT=9464
NORA_OTEL_PROMETHEUS_HOST=127.0.0.1
You can run either exporter or both. Spans are OTLP-only — Prometheus carries metrics, not traces. With the Prometheus exporter on, scrape http://<backend-host>:9464/metrics.

Cost accuracy

The nora.agent.cost.usd counter is emitted unrounded per exchange (sub-cent values accumulate accurately), using COST_PER_1K_TOKENS and the optional per-model COST_MODEL_RATES_JSON map — see environment variables. Configure those rates to match your providers for meaningful cost dashboards.

Verify

With Prometheus enabled:
curl -s http://localhost:9464/metrics | grep -E 'gen_ai_client_token_usage|nora_agent_cost_usd'
Drive one agent chat, then re-scrape — the token histogram and cost counter will carry your agent, model, runtime family, and sandbox profile labels. For a NemoClaw smoke, deploy an OpenClaw agent with sandbox_profile=nemoclaw; the export should show nora.runtime.family=openclaw and nora.sandbox.profile=nemoclaw without any API-key labels.