Skip to content

Observability

The C++ runtime emits traces over OTLP/HTTP when configured. Use Langfuse or another OpenTelemetry backend.

See Enable telemetry for collector configuration, lifecycle spans, trace propagation, baggage, and shutdown.

Configuration model

Tracing is process-wide and disabled until configure_otel(), configure_otel_from_env(), or langfuse() installs a provider. Configure it before creating sessions or starting wire streams so their complete lifetimes are recorded. shutdown_otel() flushes buffered spans and tears down the provider.

The native exporter supports OTLP over HTTP/JSON. ostream provides console output, in_memory supports tests, and none disables export. Standard OTEL_* variables configure endpoints, headers, service metadata, timeouts, and exporter selection.

Emitted spans

Span Activation Recorded data
Action name A valid trace context is present Action name, ID, run/call mode, status, and nested call events
a11.session Provider configured before session creation Session ID, lifetime, and terminal status
a11.wire_stream Provider configured before start or accept Stream ID, terminal status, send events, and endpoint role when defined

Action traces follow application requests. enable_tracing() creates or reuses W3C context on a root action. Nested actions become child spans, and remote calls inject the current context into reserved action headers.

Session and stream spans form independent infrastructure traces. Their stable a11.session.id and a11.stream.id attributes support filtering and correlation. Each a11.wire.send event records action-message count, node-fragment count, and approximate bytes; payload values are omitted.

Baggage and span attributes

enable_tracing(..., baggage={...}) carries W3C baggage through nested and remote actions. baggage_span_attributes selects a bounded set of keys to copy onto every span for backend filtering. Langfuse configuration selects langfuse.session.id and langfuse.user.id by default.

Handlers can update their active action span with set_span_name(), set_span_attribute(), set_span_status(), set_span_input(), and set_span_output(). start_span() creates a standalone parent for work that contains several actions, such as a complete chat turn.

a11.observability

Explicit OpenTelemetry configuration for A11.

Tracing is emitted natively from the C++ runtime and is off until configure_otel (or a backend helper such as langfuse) is called. Spans are exported directly from C++ over OTLP/HTTP (JSON), so telemetry never depends on the Python layer being on the hot path.

Span

Span(native: Any)

A standalone tracing span, e.g. to group work that isn't a single action.

Create one with start_span, pass span.traceparent() to enable_tracing on child actions to nest them, and end() it (or use it as a context manager). Mutators are no-ops when tracing is off.

traceparent

traceparent() -> str

W3C traceparent for parenting child actions/spans to this one.

set_status

set_status(code: str, description: str = '') -> 'Span'

Set the span status. code is "ok", "error" or "unset"; description is used for errors.

start_span

start_span(name: str, *, kind: str = 'internal', parent_traceparent: str | None = None) -> Span

Start a standalone span. When parent_traceparent is given the span continues that trace; otherwise it begins a new root trace. Returns an inactive Span (all no-ops) if tracing is not configured.

configure_otel

configure_otel(*, service_name: str = 'a11', resource_attributes: Mapping[str, str] | None = None, exporter: str = 'otlp_http', endpoint: str = '', headers: Mapping[str, str] | None = None, timeout_millis: int = 10000, use_simple_processor: bool = False, baggage_span_attributes: Sequence[str] | None = None) -> None

Install the global tracer provider.

exporter is one of "otlp_http", "ostream", "in_memory" or "none". For "otlp_http" supply endpoint (a full traces URL) and any auth headers. baggage_span_attributes names W3C baggage keys that are copied onto every span as attributes (e.g. langfuse.session.id) while still propagating downstream. Raises StatusException on error (e.g. an OTLP endpoint on a build without OTLP support).

shutdown_otel

shutdown_otel() -> None

Flush and tear down the global tracer provider.

langfuse_otlp_endpoint

langfuse_otlp_endpoint(host: str = 'https://cloud.langfuse.com') -> str

Return the OTLP traces endpoint for a Langfuse host.

langfuse_auth_header

langfuse_auth_header(public_key: str, secret_key: str) -> str

Return the HTTP Basic auth header value Langfuse expects.

langfuse

langfuse(*, public_key: str, secret_key: str, host: str = 'https://cloud.langfuse.com', service_name: str = 'a11', resource_attributes: Mapping[str, str] | None = None, extra_headers: Mapping[str, str] | None = None, baggage_span_attributes: Sequence[str] | None = None, timeout_millis: int = 10000) -> str

Configure native OTLP/HTTP export to Langfuse's ingestion endpoint.

Langfuse is OTLP-compatible, so this just points the native exporter at the Langfuse traces endpoint with Basic auth. Additional resource_attributes (and extra_headers) let a Langfuse integration attach its own metadata. baggage_span_attributes defaults to LANGFUSE_BAGGAGE_KEYS, so request-scoped values set upstream via the x-otel-baggage header -- e.g. langfuse.session.id -- are promoted to span attributes Langfuse reads, and still propagate across nested/remote actions.

Returns the resolved endpoint.

new_traceparent

new_traceparent(*, sampled: bool = True) -> str

Mint a fresh W3C traceparent value for a brand-new root trace.

For an action with no upstream context: set it as the TRACEPARENT_HEADER before run()/call() (or use enable_tracing).

enable_tracing

enable_tracing(action: 'Action', *, traceparent: str | None = None, tracestate: str | None = None, baggage: Mapping[str, str] | str | None = None) -> 'Action'

Enable tracing on a root action before you run or call it.

Sets the reserved W3C headers so the action's handler run becomes a span (tracing must already be configured). With no traceparent an existing one on the action is reused, otherwise a fresh root trace is minted. baggage -- a mapping such as {"langfuse.session.id": "..."} or a preformatted header string -- rides along and propagates downstream.

Returns the action so it chains: enable_tracing(a).run(). Nested actions are traced automatically and do not need this call.

configure_otel_from_env

configure_otel_from_env(*, service_name: str = 'a11') -> bool

Configure native tracing from standard OpenTelemetry environment vars.

Honors OTEL_SDK_DISABLED, OTEL_TRACES_EXPORTER (otlp | console | none), OTEL_SERVICE_NAME, OTEL_RESOURCE_ATTRIBUTES, and the OTEL_EXPORTER_OTLP_* endpoint, headers and timeout variables (per-signal ..._TRACES_* overrides win). Only OTLP/HTTP (JSON) transport is supported, so a gRPC protocol selection is rejected. Returns True if a provider was installed, False if the environment disabled tracing.

configure_langfuse_from_env

configure_langfuse_from_env(*, host: str | None = None, service_name: str = 'a11') -> bool

Configure native OTLP export to Langfuse from LANGFUSE_* env vars.

Reads LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY and LANGFUSE_HOST (also honoring OTEL_SERVICE_NAME / OTEL_RESOURCE_ATTRIBUTES). Returns True when configured, False when both keys are absent, and raises ValueError if only one of the key pair is set.