OpenTelemetry¶

Burr has two integrations with OpenTelemetry:

  1. Burr can log traces to OpenTelemetry

  2. Burr can capture any traces logged within an action and log them to OpenTelemetry

See the following resources for more information:

Reference for the various useful methods:

class burr.integrations.opentelemetry.OpenTelemetryBridge(
tracer_name: str = None,
tracer: Tracer = None,
streaming_telemetry: StreamingTelemetryMode = StreamingTelemetryMode.SINGLE_SPAN,
)¶

Lifecycle adapter that maps Burr execution events to OpenTelemetry spans and events.

How it works

The bridge implements Burr lifecycle hooks to create a span hierarchy that mirrors the execution structure:

  1. pre_run_execute_call / post_run_execute_call — creates a top-level method span for the application method being called (e.g. step, astream_result).

  2. pre_run_step / post_run_step — creates an action span as a child of the method span. For streaming actions, behavior depends on the streaming_telemetry mode.

  3. pre_start_span / post_end_span — creates sub-action spans for user-defined visibility spans (via TracerFactory / __tracer).

  4. do_log_attributes — sets OTel attributes on the current span.

  5. pre_stream_generate / post_stream_generate — for streaming actions, optionally creates per-yield chunk spans and/or accumulates timing data for a summary event.

All spans are managed via a ContextVar-based token stack (token_stack) to correctly handle nesting across sync and async execution.

Usage

# replace with instructions from your preferred vendor
my_vendor_library_or_tracer_provider.init()

app = (
    ApplicationBuilder()
    .with_entrypoint("prompt")
    .with_state(chat_history=[])
    .with_graph(graph)
    .with_hooks(OpenTelemetryBridge())
    .build()
)

app.run()  # will log to OpenTelemetry

Streaming telemetry modes

The streaming_telemetry parameter controls how streaming actions are instrumented. Non-streaming actions are unaffected — they always produce a single action span.

  • StreamingTelemetryMode.SINGLE_SPAN (default): A single action span covers the full generator lifetime (including consumer wait time). Streaming attributes are set on the span with the generation/consumer timing breakdown:

    • stream.generation_time_ms — time spent inside the generator producing items

    • stream.consumer_time_ms — time the consumer spent processing yielded items

    • stream.iteration_count — number of items yielded

    • stream.first_item_time_ms — time to first item (TTFT)

  • StreamingTelemetryMode.EVENT: No action span. A stream_completed (or stream_error) span event is added to the method span with the timing summary (including stream.total_time_ms since there is no action span to carry duration).

  • StreamingTelemetryMode.CHUNK_SPANS: No action span. A child span ({action}::chunk_{N}) is created for each generator yield under the method span. Each chunk span measures only generation time (excludes consumer processing time).

  • StreamingTelemetryMode.SINGLE_AND_CHUNK_SPANS: Combines SINGLE_SPAN and CHUNK_SPANS — the action span (with streaming attributes) plus per-yield chunk spans as its children.

do_log_attributes(
*,
attributes: Dict[str, Any],
**future_kwargs: Any,
)¶

Sets key-value attributes on the current OTel span.

Values are serialized via convert_to_otel_attribute() to ensure they are OTel-compatible types (str, bool, int, float, or homogeneous sequences thereof).

post_end_span(
*,
span: ActionSpan,
**future_kwargs: Any,
)¶

Closes a sub-action span opened by pre_start_span().

post_run_execute_call(*, exception: Exception | None, **future_kwargs)¶

Closes the top-level method span opened by pre_run_execute_call().

post_run_step(*, exception: Exception, **future_kwargs: Any)¶

Closes the action span and, for streaming actions, emits summary telemetry.

Behavior depends on mode:

  • SINGLE_SPAN / SINGLE_AND_CHUNK_SPANS: Sets streaming attributes on the action span, then closes it.

  • EVENT: Emits a stream_completed (or stream_error) span event on the method span (the action span was skipped). Resets the skipped flag.

  • CHUNK_SPANS: The action span was skipped; just resets the flag.

post_stream_generate(
*,
item: Any,
item_index: int,
exception: Exception | None,
**future_kwargs: Any,
)¶

Called just after each __next__() / __anext__() returns (or raises).

For modes with accumulation (SINGLE_SPAN, EVENT, SINGLE_AND_CHUNK_SPANS), accumulates generation time and updates the iteration count. When item is not None, the item is counted; a None item signals generator exhaustion (StopIteration).

In CHUNK_SPANS or SINGLE_AND_CHUNK_SPANS mode, closes the chunk span opened by pre_stream_generate(), setting an error status if exception is provided.

pre_run_execute_call(
*,
method: ExecuteMethod,
**future_kwargs: Any,
)¶

Opens the top-level method span (e.g. step, astream_result).

This is the outermost span in the Burr trace hierarchy. Action spans and chunk spans are nested under it.

pre_run_step(*, action: Action, **future_kwargs: Any)¶

Opens an action span for the step about to execute.

For streaming actions in EVENT or CHUNK_SPANS mode, the action span is skipped. In SINGLE_SPAN and SINGLE_AND_CHUNK_SPANS modes, the action span is created normally.

For all modes except CHUNK_SPANS, a _StreamingAccumulator is initialized to collect timing data across generator yields.

pre_start_span(
*,
span: ActionSpan,
**future_kwargs: Any,
)¶

Opens a sub-action span for a user-defined visibility span.

These are created by the TracerFactory (__tracer) context manager inside actions, and are nested under the current action span.

pre_stream_generate(
*,
action: str,
item_index: int,
**future_kwargs: Any,
)¶

Called just before each __next__() / __anext__() on the generator.

For modes with accumulation (SINGLE_SPAN, EVENT, SINGLE_AND_CHUNK_SPANS), records the start of generation time and accumulates consumer time (the gap between the previous post_stream_generate and now).

In CHUNK_SPANS or SINGLE_AND_CHUNK_SPANS mode, opens a child span named {action}::chunk_{item_index}.

class burr.integrations.opentelemetry.StreamingTelemetryMode(*values)¶

Controls how streaming actions are instrumented by the OpenTelemetryBridge.

  • SINGLE_SPAN: A single action span covers the full generator lifetime (default).

  • EVENT: A single action span plus a stream_completed summary span event.

  • CHUNK_SPANS: No action span. Per-yield child spans under the method span.

  • SINGLE_AND_CHUNK_SPANS: Action span with summary event plus per-yield child spans.

CHUNK_SPANS = 'chunk_spans'¶
EVENT = 'event'¶
SINGLE_AND_CHUNK_SPANS = 'single_and_chunk_spans'¶
SINGLE_SPAN = 'single_span'¶
burr.integrations.opentelemetry.init_instruments(
*instruments: Literal['openai', 'anthropic', 'cohere', 'google_generativeai', 'mistral', 'ollama', 'transformers', 'together', 'bedrock', 'replicate', 'vertexai', 'groq', 'watsonx', 'alephalpha', 'pinecone', 'qdrant', 'chroma', 'milvus', 'weaviate', 'lancedb', 'marqo', 'redis', 'langchain', 'llama_index', 'haystack', 'requests', 'httpx', 'urllib', 'urllib3'],
init_all: bool = False,
) None¶

Instruments the specified libraries, or all that are installed if it is enabled.

This will check if any libraries are available in the current environment and initialize if they are. See the INSTRUMENTS_SPECS field for the list of available libraries.

Parameters:
  • instruments – Name of libraries to instrument (e.g., requests, openai)

  • init_all – If True, initialize all available instruments for imported packages.

Returns: