Skip to main content

Telemetry

What it is

The SDK emits OpenTelemetry spans for every capability invocation, LLM call, and tool call it runs — no setup required on your side. Spans follow the OpenTelemetry GenAI semantic conventions (gen_ai.operation.name, gen_ai.request.model, gen_ai.usage.input_tokens, …), so they land cleanly in any OTEL-aware backend. Three helpers are exported from the SDK for instrumenting your own code: Where the spans go depends on where the agent runs:
  • On the Svantic mesh (hosted, or self-hosted): the mesh runtime installs a global TracerProvider at startup and ships all completed spans to the gateway. They show up in the dashboard’s Traces and Usage views.
  • Anywhere else: if the process has no global TracerProvider, the helpers become no-ops — zero runtime cost, nothing to configure.

When to use it

In the common case, you don’t. The SDK already traces:
  • Every capability invocation (execute_tool <capability_name> spans with gen_ai.tool.* attributes)
  • Every LLM call made by smart-agent mode (call_llm <model> spans with gen_ai.request.model, gen_ai.usage.*, gen_ai.response.finish_reasons)
  • Every agent invocation in smart-agent mode (invoke_agent <name> spans with gen_ai.conversation.id, aggregated token totals)
You only need to add spans yourself when you want finer-grained visibility inside a capability — e.g. around a database query, a third-party API call, or a business workflow step.

API

trace_llm(meta, fn)

Wrap any LLM provider call so it shows up as a dedicated child span with the standard gen_ai.* attributes.
The callback returns { value, telemetry? }. The helper attaches gen_ai.usage.input_tokens, gen_ai.usage.output_tokens, and gen_ai.response.finish_reasons from the telemetry object, then resolves the outer promise with value alone — so the caller sees a clean value. Example (OpenAI):
Example (Anthropic):
Errors are recorded as span events with status=ERROR and rethrown unchanged.

trace_tool(meta, fn)

Wrap any tool/side-effect call.
Example:

trace_step(name, fn)

Wrap arbitrary work so it shows up as step.<name> in the waterfall. Use to eliminate “unaccounted time” gaps.
Example:

record_span_error(span, err)

For advanced callers who start their own spans via @opentelemetry/api: mark the span as failed in a way consistent with the helpers above (records the exception, sets status=ERROR, attaches error.message and error.type).

Spans the SDK & mesh emit

Using your own OpenTelemetry backend

To send traces to Datadog, Honeycomb, Grafana Tempo, or any OTLP collector, configure a TracerProvider yourself at process startup — before creating any Agent:
All SDK spans will flow into your pipeline automatically. If the agent is also connected to a Svantic mesh, the mesh’s own provider wins in that process (the mesh calls maybeSetOtelProviders, which is first-write-wins), but the agent-side provider is preserved if it’s the first one registered.

See also