Tracing in the OpenAI Agents SDK provides comprehensive observability into agent runs. Think of tracing as a "flight recorder" or "audit log" that captures everything that happens during an agent execution - from the initial input to the final output, including all model calls, tool executions, handoffs, and more. This is essential for debugging, monitoring, and understanding agent behavior.
Core Concepts
What is Tracing?
Tracing is the systematic recording of events that occur during an agent run. It captures:
Timing - When each operation occurred
Duration - How long each operation took
Inputs/Outputs - What data was passed (unless sensitive)
Relationships - How operations relate to each other
Analogy: Think of it like a tree where the Trace is the trunk and Spans are branches.
Trace Class
Python
@dataclassclassTrace:
id: str"""Unique identifier for the trace."""
workflow_name: str"""Name of the workflow being traced."""
group_id: str | None"""Group ID for linking related traces."""
metadata: dict[str, Any]
"""Additional metadata about the trace."""
spans: list[Span]
"""All spans in this trace."""
state: TraceState
"""State of the trace (in_progress, completed, etc.)."""
Span Class
Python
@dataclassclassSpan:
id: str"""Unique identifier for the span."""
parent_id: str | None"""ID of the parent span (if any)."""
name: str"""Name of the operation."""
start_time: datetime
"""When the span started."""
end_time: datetime | None"""When the span ended (None if in progress)."""
data: SpanData
"""Data associated with the span."""
error: SpanError | None"""Error if the span failed."""
Span Types
Agent Span
Represents an agent's execution:
Python
from agents import agent_span, AgentSpanData
with agent_span(name="my_agent", agent=agent) as span:
# Agent executionpass
AgentSpanData includes:
Agent name
Agent instructions
Input items
Output items
Tool calls
Handoffs
Generation Span
Represents a model generation:
Python
from agents import generation_span, GenerationSpanData
with generation_span(name="llm_call") as span:
response = await model.get_response(...)
GenerationSpanData includes:
Model name
System instructions
Input items
Output items
Token usage
Tool calls
Function Span
Represents a function execution:
Python
from agents import function_span, FunctionSpanData
with function_span(name="my_function") as span:
result = my_function()
FunctionSpanData includes:
Function name
Arguments
Return value
Duration
Guardrail Span
Represents a guardrail execution:
Python
from agents import guardrail_span, GuardrailSpanData
with guardrail_span(name="input_guardrail") as span:
result = await guardrail.run(...)
GuardrailSpanData includes:
Guardrail name
Guardrail type (input/output/tool)
Input data
Output data
Tripwire triggered
Handoff Span
Represents a handoff between agents:
Python
from agents import handoff_span, HandoffSpanData
with handoff_span(name="to_specialist") as span:
await handoff.on_invoke_handoff(...)
HandoffSpanData includes:
From agent name
To agent name
Handoff arguments
Handoff result
Custom Span
Represents a custom operation:
Python
from agents import custom_span, CustomSpanData
with custom_span(name="my_operation", data={"key": "value"}) as span:
# Custom operationpass
Tool Span
Represents a tool execution:
Python
from agents import tool_span
with tool_span(name="my_tool", tool=tool) as span:
result = await tool.execute(...)
MCP Tools Span
Represents MCP tool operations:
Python
from agents import mcp_tools_span, MCPListToolsSpanData
with mcp_tools_span(name="mcp_list_tools") as span:
tools = await mcp_server.list_tools()
Tracing Configuration
RunConfig Tracing Settings
Configure tracing for a run:
Python
from agents import RunConfig
config = RunConfig(
tracing_disabled=False, # Enable tracing
trace_include_sensitive_data=True, # Include sensitive data
workflow_name="My workflow",
trace_id="custom-trace-id",
group_id="conversation-123",
trace_metadata={"user_id": "user-456"},
)
Global Tracing Settings
Set global tracing defaults:
Python
from agents import set_tracing_disabled, set_tracing_export_api_key
# Disable tracing globally
set_tracing_disabled(True)
# Set API key for trace export
set_tracing_export_api_key("your-api-key")
Environment Variables
Configure tracing via environment:
Bash
# Disable tracingexport OPENAI_AGENTS_TRACING_DISABLED=true# Include sensitive data in tracesexport OPENAI_AGENTS_TRACE_INCLUDE_SENSITIVE_DATA=true
Trace Processors
TracingProcessor Interface
Custom trace processors allow you to handle traces:
Python
from agents import TracingProcessor, Trace
classMyProcessor(TracingProcessor):
asyncdefprocess_trace(self, trace: Trace) -> None:
"""Process a completed trace."""# Send to your observability platformawait send_to_platform(trace)
Adding Trace Processors
Add processors to handle traces:
Python
from agents import add_trace_processor
processor = MyProcessor()
add_trace_processor(processor)
from agents.tracing.processors import ConsoleProcessor
add_trace_processor(ConsoleProcessor())
File Processor
Save traces to files:
Python
from agents.tracing.processors import FileProcessor
add_trace_processor(FileProcessor(directory="/traces"))
OpenAI Processor
Send traces to OpenAI:
Python
from agents.tracing.processors import OpenAIProcessor
add_trace_processor(OpenAIProcessor(api_key="your-key"))
Manual Tracing
Creating Traces Manually
Create traces for custom operations:
Python
from agents import trace, Trace
with trace(workflow_name="custom_workflow") as trace_obj:
# Manual operationswith custom_span(name="step1"):
do_step1()
with custom_span(name="step2"):
do_step2()
# Access the traceprint(trace_obj.id)
with custom_span(name="risky_operation") as span:
try:
risky_operation()
except Exception as e:
# Error is automatically captured in spanraise
Manual Error Recording
Manually record errors:
Python
from agents import SpanError
with custom_span(name="my_operation") as span:
try:
do_operation()
except Exception as e:
span.error = SpanError(
message=str(e),
data={"exception_type": type(e).__name__},
)
raise
Trace Export
OpenAI Trace Export
Export traces to OpenAI:
Python
from agents import set_tracing_export_api_key
set_tracing_export_api_key("your-openai-api-key")
# Traces are automatically sent to OpenAI
result = await Runner.run(agent, input)
defcalculate_trace_duration(trace: Trace) -> float:
"""Calculate total trace duration."""ifnot trace.spans:
return0.0
start = min(span.start_time for span in trace.spans)
end = max(span.end_time for span in trace.spans if span.end_time)
return (end - start).total_seconds()
Analyzing Token Usage
Aggregate token usage across spans:
Python
defaggregate_token_usage(trace: Trace) -> Usage:
"""Aggregate token usage from all generation spans."""
total = Usage(request_tokens=0, response_tokens=0, total_tokens=0)
for span in trace.spans:
ifisinstance(span.data, GenerationSpanData):
total += span.data.usage
return total
Analyzing Tool Usage
Count tool executions:
Python
defcount_tool_calls(trace: Trace) -> dict[str, int]:
"""Count tool calls by name."""
counts = {}
for span in trace.spans:
if span.name.startswith("tool_"):
tool_name = span.name.replace("tool_", "")
counts[tool_name] = counts.get(tool_name, 0) + 1return counts
# Good
span.data = CustomSpanData(
operation="file_processing",
file_path="/workspace/data.txt",
file_size=1024,
)
# Avoid
span.data = CustomSpanData() # No context
3. Handle Sensitive Data
Be careful with sensitive data:
Python
# Good - exclude sensitive data
config = RunConfig(
trace_include_sensitive_data=False,
)
# Avoid - leak sensitive data
config = RunConfig(
trace_include_sensitive_data=True,
)
4. Use Appropriate Granularity
Choose the right level of detail:
Python
# Good - appropriate granularitywith agent_span(name="agent_execution"):
with generation_span(name="llm_call"):
...
with tool_span(name="tool_execution"):
...
# Avoid - too granularwith custom_span(name="variable_assignment"):
x = 1# Too detailed
5. Clean Up Old Traces
Implement trace cleanup:
Python
asyncdefcleanup_old_traces(days: int = 30):
"""Clean up traces older than N days."""
cutoff = datetime.now() - timedelta(days=days)
await trace_store.delete_before(cutoff)
Common Tracing Patterns
1. Distributed Tracing
Link traces across services:
Python
config = RunConfig(
group_id="request-123", # Link related traces
trace_metadata={"service": "agent-service"},
)
classErrorTrackingProcessor(TracingProcessor):
asyncdefprocess_trace(self, trace: Trace):
errors = [span.error for span in trace.spans if span.error]
if errors:
await report_errors(trace, errors)
4. Compliance Logging
Maintain compliance logs:
Python
classComplianceProcessor(TracingProcessor):
asyncdefprocess_trace(self, trace: Trace):
# Log for complianceawait compliance_log.store(trace)