Distributed Tracing with OpenTelemetry
Agenta provides built-in OpenTelemetry instrumentation to simplify distributed tracing in your applications. This guide explains how to implement and manage distributed tracing using the Agenta SDK, and how to integrate external tracing setups with Agenta.
Using OpenTelemetry with Agenta
Agenta supports distributed tracing out of the box when using the provided SDK functions:
1. Sending Requests (Propagation)
When making requests to other services or sub-systems, use agenta.tracing.inject()
to inject necessary headers:
method = "POST"
url = "https://example-service/api"
params = {}
headers = agenta.tracing.inject() # automatically injects 'Authorization', 'Traceparent', 'Baggage'
body = {"key": "value"}
response = requests.request(
method=method,
url=url,
params=params,
headers=headers,
json=body,
)
The agenta.tracing.inject()
function returns headers containing:
Authorization
: Authentication informationTraceparent
: Identifies the current trace and spanBaggage
: Contains application-specific context
These headers can be modified before sending them as part of the request if needed.
2. Receiving Requests (Extraction)
Agenta simplifies receiving and handling incoming trace contexts:
- If you're using
ag.route()
andag.instrument()
, extraction is automatic. - For manual extraction, use
agenta.tracing.extract()
:
traceparent, baggage = agenta.tracing.extract() # includes 'Traceparent', 'Baggage'
# Use traceparent and baggage to set up your OpenTelemetry context
# (Implementation depends on your specific use case)
extract()
does not provide Authorization
because there are many authentication methods (apikey, bearer, secret, access tokens), each requiring different handling. The middlewares and decorators in the Agenta SDK handle this automatically when you use ag.route()
and ag.instrument()
.
OpenTelemetry Tracing without Agenta SDK
If you're working with systems that don't use the Agenta SDK, you can still integrate with Agenta's tracing infrastructure using standard OpenTelemetry.
1. Setup Requirements
Install dependencies:
pip install opentelemetry-api opentelemetry-sdk opentelemetry-exporter-otlp
2. Configure Environment Variables
# OTEL_PROPAGATORS = unset or "tracecontext,baggage"
# OTEL_EXPORTER_OTLP_COMPRESSION = unset or "gzip"
# OTEL_EXPORTER_OTLP_ENDPOINT = "https://cloud.agenta.ai/api/otlp"
# OTEL_EXPORTER_OTLP_HEADERS = "authorization=ApiKey xxx"
# OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = "https://cloud.agenta.ai/api/otlp/v1/traces"
# OTEL_EXPORTER_OTLP_TRACES_HEADERS = "authorization=ApiKey xxx"
3. Setup in Code
from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator
from opentelemetry.baggage.propagation import W3CBaggagePropagator
from opentelemetry.sdk.trace import TracerProvider, Span
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter, Compression
# Configuration
endpoint = "https://cloud.agenta.ai/api/otlp/v1/traces"
compression = Compression.Gzip
headers = {
"traceparent": "00-xxx-xxx-01",
"baggage": "ag.refs.application.id=xxx",
"authorization": "ApiKey xxx",
}
# Set up provider, processor, and tracer
provider = TracerProvider()
processor = BatchSpanProcessor(
OTLPSpanExporter(
endpoint=endpoint,
headers={"authorization": headers["authorization"]},
compression=compression,
)
)
provider.add_span_processor(processor)
tracer = provider.get_tracer("agenta.tracer")
# Extract incoming trace context
carrier = {"traceparent": headers["traceparent"]}
context = TraceContextTextMapPropagator().extract(carrier=carrier, context=None)
carrier = {"baggage": headers["baggage"]}
context = W3CBaggagePropagator().extract(carrier=carrier, context=context)
# Create and use spans
with tracer.start_as_current_span(name="agenta", context=context) as span:
span: Span
print(hex(span.get_span_context().trace_id))
print(hex(span.get_span_context().span_id))
print(span.name)
Using an OTEL Collector
If you're using an OpenTelemetry collector, you can configure it to export traces to Agenta.
Here's a sample configuration (otel-collector-config.yml
):
receivers:
otlp:
protocols:
http:
endpoint: 0.0.0.0:4318
processors:
batch: {}
exporters:
otlphttp/agenta:
endpoint: "https://cloud.agenta.ai/api/otlp"
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [otlphttp/agenta]
With this configuration:
- The collector receives traces via OTLP/HTTP on port 4318
- It batches the spans for efficiency
- It exports them to Agenta's OTLP endpoint
Span Attributes
When using OpenTelemetry without the Agenta SDK, you need to manually set the appropriate attributes on your spans to integrate properly with Agenta's ecosystem.
Namespace Convention
Agenta uses the ag.*
namespace for its attributes. Here are the key namespaces:
ag.refs.*
: References to Agenta entities (applications, etc.)ag.data.*
: Input, internal, and output dataag.metrics.*
: Performance metrics and costs
Examples
# Reference to Agenta application
span.set_attribute("ag.refs.application.id", AGENTA_APPLICATION_ID)
# Data attributes
span.set_attribute("ag.data.inputs.key", "Hello,")
span.set_attribute("ag.data.internals.key", "(Leo)")
span.set_attribute("ag.data.outputs.key", "World!")
# Metrics - unit values
span.set_attribute("ag.metrics.unit.some_key", 3)
span.set_attribute("ag.metrics.acc.some_key", 15)
# Cost and token metrics
span.set_attribute("ag.metrics.unit.costs.total", 1)
span.set_attribute("ag.metrics.unit.tokens.total", 100)
Apart from these custom attributes, standard OpenTelemetry events, links, status, and exceptions work as usual.