⚡ New — Kimi K3 is live: bring your own Moonshot key →
Documentation

Logs & tracing

The console Logs tab is a request & trace explorer — one row per request, newest first. It answers “what did this call do, how long did it take, what did it cost, and can I correlate it end-to-end?” without ever weakening BharatRouter’szero-retention default.

Two layers, two postures. Metadata (model, provider, status, latency, tokens, ₹ cost, residency, cached/BYOK flags, trace id) is recorded for every request and always browsable. Request/response bodies are notstored unless your org explicitly turns on content logging.

The explorer

Filter by model, status (OK 2xx / errors) and atime window (24 h / 7 / 30 / 90 days), or paste a trace id to pin a single request. Members see their own keys’ traffic; owners/admins (or holders ofusage:org:view) see the whole org. Click any row to expand its trace details.

The same rows are available as JSON — the console reads exactly this endpoint:

GET /me/activity/events?from=2026-08-01&to=2026-08-03&model=llama-3.1-8b-instruct&status=error&limit=50
→ { "events": [
      { "id": 91242, "at": "2026-08-03T08:14:22Z",
        "model": "llama-3.1-8b-instruct", "provider": "krutrim",
        "status": 200, "latency_ms": 612,
        "prompt_tokens": 180, "completion_tokens": 74, "total_tokens": 254,
        "cache_read_tokens": 0, "cost_inr": 0.019, "byok": false, "stream": true,
        "residency": "india", "agent_id": null,
        "trace_id": "4f1c8e2a9b7d6c5f0e3a2b1c9d8e7f60", "key_name": "prod" }
    ],
    "next_before": 91191 }

Filters: status=ok|error, model=,key_id=, workspace_id=, trace_id= (32 lowercase hex), plus thefrom/to IST date range. Paginate with before=<last id>(the response’s next_before).

Trace correlation

Every request carries a W3C Trace Context id. An inbound traceparentheader continues the caller’s trace; otherwise the gateway mints a fresh root. That id is threaded onto the usage row (above) and, when an OTLP endpoint is configured, exported asmetadata-only spans — route, model, provider, residency, status, latency, failover reason, never prompt or response content. So tracing is safe by construction and needs no per-org switch. The full OTel waterfall / span-tree UI is a follow-up; today the console surfaces the trace id for correlation in your own collector.

SIEM / OTLP export

Beyond the in-console trace id, an org can push gateway telemetry to its own SIEM — Datadog, Splunk, Grafana, or any collector that accepts OTLP/HTTP ingest. You register one or more per-org destinations; a background worker then streams new request records to each. Owners/admins manage destinations (isManager-gated and audited); the surface is reachable with a console session or a managementbr- key, so an agent can provision it headlessly.

Metadata only, residency-gated, fail-open. v1 exports otlp-traces — route, model, provider, residency, status, latency, tokens, ₹ cost — and neverprompt or response content. A per-destination residency allowlist decides which records may leave, the auth secret is encrypted at rest and never returned, and a broken destination is auto-disabled — it never blocks or slows a request.

Create a destination (owner/admin). export_residency is the allowlist of buckets whose records may egress (india / global / unknown; default["india"] — an empty list is rejected). auth_kind: "bearer" needs asecret; it is stored AES-256-GCM and only its mask is ever returned.

POST /me/siem-exports
{
  "name": "datadog-prod",
  "url": "https://http-intake.logs.datadoghq.com/api/v2/otlp/v1/traces",
  "format": "otlp-traces",          // only value in v1
  "auth_kind": "bearer",            // or "none"
  "secret": "dd-api-key-…",          // required for bearer; encrypted, never returned
  "header_name": "authorization",   // header the secret is sent in (default: authorization)
  "headers": { "DD-OTLP-Source": "bharatrouter" },   // optional static headers
  "export_residency": ["india"],    // allowlist: india | global | unknown
  "redact": true                    // strip any incidental identifiers
}
→ 201 { "id": 7, "name": "datadog-prod", "url": "https://…", "format": "otlp-traces",
        "auth_kind": "bearer", "mask": "dd-…7f2c", "header_name": "authorization",
        "headers": { "DD-OTLP-Source": "bharatrouter" },
        "export_residency": ["india"], "redact": true, "enabled": true,
        "failure_count": 0, "disabled_reason": null, "last_success_at": null,
        "created_at": "…", "updated_at": "…" }

A new destination exports now-forward only — it never back-fills history.

EndpointWhat it does
GET /me/siem-exportsList destinations (secrets masked).
GET /me/siem-exports/:idOne destination.
POST /me/siem-exportsCreate a destination (owner/admin).
PATCH /me/siem-exports/:idUpdate name, url, allowlist, headers, or re-enable (owner/admin).
POST /me/siem-exports/:id/rotateReplace the bearer secret (owner/admin).
POST /me/siem-exports/:id/testShip one synthetic metadata span to validate URL + auth, without touching the cursor.
DELETE /me/siem-exports/:idRemove a destination (owner/admin).

If a destination fails repeatedly the worker sets enabled: false with adisabled_reason; fix it and PATCH enabled: true to resume (this clears the failure count and picks up from the current tip — it does not re-ship the gap). Exporting request/response bodies (otlp-logs, with redaction) is a gated follow-up: the format is rejected at create today.

Inspecting request/response bodies

Because inference is zero-retention, bodies are only inspectable when an owner/admin turns on the content-logging tier — a deliberate, bounded, audited departure from the default (see the toggle at the top of the Logs tab, orPUT /me/org/content-logging). When on, request/response pairs land in aphysically separate store, stamped with an expiry, and are hard-deleted once the retention window lapses.

The drill-in fetches a stored body by trace id — owner/admin only:

GET /me/logs/content?trace_id=4f1c8e2a9b7d6c5f0e3a2b1c9d8e7f60
// content logging OFF (the default) — NOT an error:
→ { "content_logging": false, "fleet_enabled": true, "reason": "opt_out" }
// content logging ON, body found:
→ { "content_logging": true, "found": true,
    "entry": { "trace_id": "...", "model": "...", "status": 200,
               "request_body": { ... }, "response_body": { ... },
               "created_at": "...", "expires_at": "..." } }

With content logging off, the console shows a clear affordance to enable it — not a failure. A member (non-manager) never sees bodies.

What v1 does not do

  • No OTel trace waterfall / span visualization — spans are exported over OTLP; view them in your collector. The console shows the trace id only.
  • No saved views or shareable filter permalinks.
  • No full-text search over content — filtering is on metadata; content is fetched per trace on drill-in.