For AI agents: a documentation index is available at the root level at /llms.txt and /llms-full.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.
Copy to LLMGithubGo to App
DocumentationIntegrationsAgent OptimizationSelf-hosting OpikSDK & API referenceOpik University
DocumentationIntegrationsAgent OptimizationSelf-hosting OpikSDK & API referenceOpik University
  • Getting Started
    • Home
    • Quickstart
    • Quickstart notebook
    • Roadmap
    • FAQ
    • Changelog
  • Observability
    • Concepts
    • Log traces
    • Log conversations
    • Log user feedback
    • Log media & attachments
    • Cost tracking
    • Opik Assist
      • SDK configuration
      • Log Agent Graphs
      • Log distributed traces
      • Offline fallback and message replay
  • Evaluation
    • Overview
    • Concepts
    • Manage datasets
    • Evaluate single prompts
    • Evaluate your agent
    • Evaluate agent trajectories
    • Evaluate multimodal traces
    • Evaluate multi-turn agents
    • Manually logging experiments
    • Re-running an existing experiment
    • Annotation Queues
  • Prompt engineering
    • Prompt management
    • Prompt Playground
    • Prompt Generator and Improver
    • Opik's MCP server
  • Testing
    • Pytest integration
  • Production
    • Production monitoring
    • Online Evaluation rules
    • Gateway
    • Guardrails
    • Anonymizers
    • Alerts
    • Dashboards
  • Administration
    • Overview
    • Roles and Permissions
  • Contributing
    • Contribution Overview
LogoLogo
Copy to LLMGithubGo to App
On this page
  • Using the distributed_headers Context Manager
ObservabilityAdvanced

Log distributed traces

Was this page helpful?
Previous

Offline fallback and message replay

Next
Built with

When working with complex LLM applications, it is common to need to track a traces across multiple services. Opik supports distributed tracing out of the box when integrating using function decorators using a mechanism that is similar to how OpenTelemetry implements distributed tracing.

For the purposes of this guide, we will assume that you have a simple LLM application that is made up of two services: a client and a server. We will assume that the client will create the trace and span, while the server will add a nested span. In order to do this, the trace_id and span_id will be passed in the headers of the request from the client to the server.

Distributed Tracing

The Python SDK includes some helper functions to make it easier to fetch headers in the client and ingest them in the server:

client.py
1from opik import track, opik_context
2
3@track()
4def my_client_function(prompt: str) -> str:
5 headers = {}
6
7 # Update the headers to include Opik Trace ID and Span ID
8 headers.update(opik_context.get_distributed_trace_headers())
9
10 # Make call to backend service
11 response = requests.post("http://.../generate_response", headers=headers, json={"prompt": prompt})
12 return response.json()

On the server side, you can pass the headers to your decorated function:

server.py
1from opik import track
2from fastapi import FastAPI, Request
3
4@track()
5def my_llm_application():
6 pass
7
8app = FastAPI() # Or Flask, Django, or any other framework
9
10
11@app.post("/generate_response")
12def generate_llm_response(request: Request) -> str:
13 return my_llm_application(opik_distributed_trace_headers=request.headers)

The opik_distributed_trace_headers parameter is added by the track decorator to each function that is decorated and is a dictionary with the keys opik_trace_id and opik_parent_span_id.

Using the distributed_headers Context Manager

As an alternative to passing opik_distributed_trace_headers as a parameter, you can use the distributed_headers() context manager for more explicit control over distributed header handling. This approach provides automatic cleanup, error handling, and optional data flushing.

server.py
1from opik import track
2from opik.decorator.context_manager import distributed_headers
3from fastapi import FastAPI, Request
4
5@track()
6def my_llm_application():
7 pass
8
9app = FastAPI() # Or Flask, Django, or any other framework
10
11
12@app.post("/generate_response")
13def generate_llm_response(request: Request) -> str:
14 # Extract distributed headers from the request
15 headers = {
16 "opik_trace_id": request.headers.get("opik_trace_id"),
17 "opik_parent_span_id": request.headers.get("opik_parent_span_id"),
18 }
19
20 # Use the context manager to handle distributed headers
21 with distributed_headers(headers, flush=False):
22 result = my_llm_application()
23
24 return result

The distributed_headers() context manager accepts two parameters:

  • headers: A dictionary containing the distributed trace headers (opik_trace_id and opik_parent_span_id)
  • flush (optional): Whether to flush the Opik client data after the root span is processed. Defaults to False. Set to True if you want to ensure immediate data transmission.

The context manager automatically creates a root span with the provided headers, handles any errors that occur during execution, and cleans up the context when complete.

For more details and additional examples, see the distributed_headers context manager API reference.