Skip to main content

Traces and Spans

RDK uses a hierarchical tracing model based on two core concepts:

Traces

A trace represents a complete operation in your application, such as handling a user request or processing a task. Each trace has:
  • A unique ID
  • A name (from your @observe decorator or trace() context manager)
  • A start time and optional end time
  • A collection of spans
  • Optional metadata (tags, user_id, session_id, version)

Spans

A span represents a single operation within a trace, such as an LLM call or tool execution. Each span has:
  • A unique ID
  • A reference to its parent trace
  • A type (LLM, CHAIN, TOOL, FUNCTION)
  • Input and output data
  • Timing information
  • Token usage (for LLM spans)
  • Status (RUNNING, SUCCESS, ERROR)

Span Types

RDK categorizes spans into four types:

Auto-instrumentation

When RDK initializes (automatically on the first @observe call), it patches supported LLM SDKs to capture calls. This means you don’t need to modify your existing LLM calls — RDK intercepts them and creates spans automatically.
BAML is not auto-instrumented. You must call b = instrument_baml(b) after init(). See BAML Integration.

How It Works

  1. RDK patches the SDK’s request methods
  2. When you call an LLM, RDK creates a span before the call
  3. The original call executes normally
  4. RDK captures the response, token usage, and timing
  5. The span is queued for batching

Creating Traces

With trace() (for scripts and notebooks)

Decorator Options

Manual Spans

For custom code that isn’t automatically captured, use span():
See span() and the Manual Tracing guide.

Batching and Transport

RDK batches spans to reduce network overhead:
Configure batching with:

Thread Safety

RDK uses contextvars for thread-safe trace context:
  • Each thread/task has its own trace context
  • Async operations preserve context correctly
  • You can safely use RDK in multi-threaded applications