Endpoint and authentication
Create the key under Settings → Tracing keys, exactly as in the Tracing quickstart. Spans land in the key’s project.
The word
Bearer must be capitalized exactly like that. If the Authorization header doesn’t start with Bearer , AgentHub falls back to the x-tracing-key header and, if that’s missing too, rejects the export with 401.
Setup
- Python · OpenLLMetry
- Python · OTel
- TypeScript
- Environment variables
- Collector
- Go
- Java
OpenLLMetry auto-instruments the OpenAI, Anthropic, Bedrock, LangChain and LlamaIndex clients you already call.
main.py
Request requirements
Response
AgentHub answers with a standard OTLPExportTraceServiceResponse and HTTP 200, encoded the same way as the request, not with the { data } envelope the rest of the API uses (exporters would log a transport error otherwise).
- Full success: an empty message (
{}for JSON). - Some spans dropped:
partialSuccesswithrejectedSpansand anerrorMessage, for example:
401 UNAUTHORIZED, 400/415 VALIDATION_ERROR) instead.
A span is dropped if it has no usable trace id, no span id, or no valid start and end time. If storing a whole trace fails, all of that trace’s spans are counted as rejected and the rest of the export is still processed.
How OpenTelemetry spans are mapped
AgentHub reads OpenLLMetry (Traceloop), the OpenTelemetry GenAI semantic conventions (gen_ai.*) and OpenInference (llm.*, openinference.*) attributes. It maps attributes, not client libraries, so any instrumentor that emits those conventions works.
Span kind
Checked in this order; the first match wins.Fields
Spans that arrive in several exports
OpenTelemetry exports a span when it ends, on a batch timer, so a trace usually arrives across several requests with its root span last. That’s expected: each export is merged into the same trace, totals are recomputed from all stored spans, and the trace name is corrected once the root span arrives. Exports with more than 500 spans for one trace are split automatically.Session stitching
Many instrumentors start a new trace for every top-level model or tool call unless you wrap the run in a span of your own. To keep one agent run together, AgentHub merges such fragments into one trace when they share a session key and arrive close together:- Session key: the first of
session.id,session_id,gen_ai.conversation.id,conversation.id,thread.id,langfuse.session.id,traceloop.association.properties.session_id,openinference.session.id,agent.run.idorrun.idfound on any span or on the resource. If none is set, the pairservice.nameplusservice.instance.idis used. With neither, no stitching happens. - Window: a fragment joins the session’s first trace if it starts no more than 2 minutes after that trace’s last span ended.
- Cap: a stitched trace stops growing at 2,000 spans; later fragments start a new trace.
- Stitched traces carry a
session:<hash>tag, plusstitchedonce a merge has happened.
with tracer.start_as_current_span("agent_run"):) around the whole run.
Metrics and logs
Traceloop.init() and several OTel SDKs also export metrics and logs to the same base endpoint. AgentHub accepts them at POST /api/v1/metrics and POST /api/v1/logs so your console doesn’t fill with 404 errors, but it discards them: only traces are stored. Both endpoints still require a valid tracing key.