Core concepts
span
A span is a traceable unit of execution that records a name, start/end times, attributes, and parent-child relationships. VeADK builds a tree of spans for each request, covering nodes such as agent runs, model calls, and tool executions, and annotates them per the generative-AI semantic conventions with attributes likegen_ai.operation.name and gen_ai.span.kind.
The tracer OpentelemetryTracer
OpentelemetryTracer is the unified tracing entry point. It holds a list of exporters, wires each one into the tracing pipeline on initialization, and automatically attaches an in-memory exporter for local retention and dumping.
exporter
An exporter sends span data to a specific backend platform. Each exporter targets one backend and can be used alone or combined. VeADK ships the following exporters:Attaching a tracer to an agent
Complete model configuration first. This example stores traces locally and does not require an external observability backend. Running it prints a model response and the path to a JSON trace fileapp.py
Tracer parameters
OpentelemetryTracer accepts the following fields:
InMemoryExporter is managed automatically by OpentelemetryTracer and retains completed, sampled spans. Do not add it to the exporters list manually, or initialization fails.Reusing a preconfigured global TracerProvider
By default,OpentelemetryTracer creates and sets the global TracerProvider during initialization. If a global TracerProvider already exists at that point (for example, set by another library or the application itself), VeADK reuses it instead of overriding it.
When a global provider already exists, the APMPlusExporter object remains in the exporter list, but its span processor is not registered by this tracer. Cozeloop, TLS, and in-memory exporters are still attached. This also applies to exporters created with ENABLE_APMPLUS=true
apmplus_managed_externally only indicates that a provider already existed at initialization. It does not inspect that provider’s destination or confirm delivery to APMPlus. If your application already configures OpenTelemetry, configure the APMPlus destination there and verify the Trace ID in the backend
Enabling exporters via environment variables
Besides constructing exporters explicitly,Agent attaches the matching exporter at runtime based on the following environment variables (enabled when set to true). If the agent provides no tracers, an OpentelemetryTracer is created automatically:
Content tracing
By default, spans record the input and output content of the agent, model, and tools. In scenarios involving sensitive data, you can disable content capture and reduce content captured by VeADK. This is controlled byOpenTelemetryConfig.trace_content.
Local dumping
The in-memory exporter built intoOpentelemetryTracer retains spans by session_id. Call dump to export the current session’s spans to a local JSON file for offline analysis:
span_id, trace_id, start/end times, attributes, and parent span. See In-memory exporter for details.
Local cache limits
The in-memory exporter retains the most recent 1024 spans by default, with an estimated data cap of 16 MiB. When either limit is reached, the oldest span is evicted. Adjust these limits with the following environment variables:tracer.dump() writes an empty array. Multiple tracers under the same TracerProvider share one local cache budget. See In-memory exporter for details.
Request spans and streaming TTFT
VeADK uses native OpenTelemetry span start/end times to describe execution boundaries. VeADK AgentKit/Harness HTTP applications create anhttp_request server span at ASGI ingress, before body parsing, and end it when the application finishes. Direct VeADK Runner execution creates a runner_request span; a Runner invoked inside the HTTP request reuses that request scope. These boundaries exclude client/network/gateway delays before the application receives the request.
Each LiteLLM Chat or Ark Responses SDK request creates a model_request client span under the owning model span. Its native start time is the same local SDK-request timestamp used to calculate TTFT; it is not provider inference start. VeADK-issued retries/fallbacks create separate spans. Hidden provider/LiteLLM retries remain within the observed SDK call.
The first nonempty text, reasoning, or tool-call delta records TTFT once. Metadata, empty deltas, usage, heartbeats, and completion-only aggregates do not count. Non-streaming, no-output, or uninstrumented paths omit TTFT; unknown SDK mode is not inferred from Runner configuration. One chunk can contain multiple tokens, so this is an SDK-observed duration, not a provider-side per-token timestamp.
The same value is recorded once in the
gen_ai.chat_completions.streaming_time_to_first_token Histogram, unit s, using the existing global MeterProvider. Dimensions are gen_ai.request.model and gen_ai.operation.name=chat. Metrics do not depend on token usage or trace sampling; export requires a configured metrics pipeline. Negative wall-clock intervals are omitted with a diagnostic; genuine measured zero is valid.
Failed model requests set native Span Status to ERROR and error.type to llm_error, timeout, or cancelled. Request spans use request_error, timeout, or cancelled; HTTP 5xx responses use http_error. Explicit generator closure is not an error. Already observed TTFT survives interruption, and exception text is not added by this instrumentation.
This instrumentation replaces the previous custom timing fields. It no longer exports custom
veadk.request.* or veadk.model.* attributes or a custom first-token event, without compatibility aliases. Client-render timing and TPOT histogram reporting remain outside this feature.