Datadog APM client library providing distributed tracing, continuous profiling, error tracking, test optimization, deployment tracking, code hotspots analysis, and dynamic instrumentation for Python applications.
—
OpenTelemetry API compatibility layer enables seamless interoperability between ddtrace and OpenTelemetry instrumentation while maintaining Datadog-specific features and optimizations. This allows applications to use OpenTelemetry APIs while benefiting from Datadog's advanced APM capabilities.
The main entry point for OpenTelemetry integration, providing OpenTelemetry-compatible tracer instances that use ddtrace as the backend implementation.
class TracerProvider:
def get_tracer(
self,
instrumenting_module_name: str,
instrumenting_library_version: str = None,
schema_url: str = None
) -> Tracer:
"""
Get an OpenTelemetry-compatible tracer instance.
Parameters:
- instrumenting_module_name: Name of the instrumenting module
- instrumenting_library_version: Version of the instrumenting library
- schema_url: Schema URL for telemetry data
Returns:
OpenTelemetry Tracer instance backed by ddtrace
"""
def add_span_processor(self, span_processor) -> None:
"""
Add a span processor to the tracer provider.
Parameters:
- span_processor: OpenTelemetry span processor
"""
def get_active_span_processor(self):
"""
Get the active span processor.
Returns:
Active span processor instance
"""
def shutdown(self) -> bool:
"""
Shutdown the tracer provider and flush pending spans.
Returns:
True if shutdown was successful
"""Enable OpenTelemetry support and configure the TracerProvider for use with ddtrace backend.
import os
# Enable OpenTelemetry support (must be set before importing ddtrace)
os.environ["DD_TRACE_OTEL_ENABLED"] = "true"
# Configure the OpenTelemetry TracerProvider
from opentelemetry.trace import set_tracer_provider
from ddtrace.opentelemetry import TracerProvider
# Set ddtrace as the OpenTelemetry backend
set_tracer_provider(TracerProvider())
# Now OpenTelemetry APIs will use ddtrace backend
from opentelemetry import trace
tracer = trace.get_tracer(__name__)Combine OpenTelemetry and ddtrace APIs seamlessly within the same application.
import os
os.environ["DD_TRACE_OTEL_ENABLED"] = "true"
from opentelemetry.trace import set_tracer_provider
from ddtrace.opentelemetry import TracerProvider
from opentelemetry import trace
import ddtrace
# Setup
set_tracer_provider(TracerProvider())
otel_tracer = trace.get_tracer(__name__)
# Mixed usage example
with otel_tracer.start_as_current_span("otel-parent") as parent_span:
# Set OpenTelemetry attributes
parent_span.set_attribute("service.name", "mixed-service")
parent_span.set_attribute("operation.type", "data-processing")
# Create ddtrace child span within OpenTelemetry parent
with ddtrace.tracer.trace("ddtrace-child") as child_span:
child_span.set_tag("component", "business-logic")
child_span.set_tag("user.id", "12345")
# Both spans are part of the same trace
process_business_logic()
# Back to OpenTelemetry span
parent_span.set_attribute("result.status", "success")Use standard OpenTelemetry span APIs with ddtrace backend providing the implementation.
from opentelemetry import trace
tracer = trace.get_tracer(__name__)
# Context manager usage
with tracer.start_as_current_span("http-request") as span:
# Set standard OpenTelemetry attributes
span.set_attribute("http.method", "GET")
span.set_attribute("http.url", "https://api.example.com/users")
span.set_attribute("http.status_code", 200)
# Add events
span.add_event("request.started")
response = make_http_request()
span.add_event("request.completed", {
"response.size": len(response.content)
})
# Manual span management
span = tracer.start_span("database-operation")
try:
span.set_attribute("db.system", "postgresql")
span.set_attribute("db.statement", "SELECT * FROM users")
result = execute_database_query()
span.set_attribute("db.rows_affected", len(result))
span.set_status(trace.Status(trace.StatusCode.OK))
except Exception as e:
span.set_status(trace.Status(trace.StatusCode.ERROR, str(e)))
span.record_exception(e)
raise
finally:
span.end()Use OpenTelemetry decorators for automatic span creation.
from opentelemetry import trace
tracer = trace.get_tracer(__name__)
@tracer.start_as_current_span("user-authentication")
def authenticate_user(username, password):
# Function automatically wrapped in a span
span = trace.get_current_span()
span.set_attribute("user.name", username)
span.set_attribute("auth.method", "password")
try:
user = validate_credentials(username, password)
span.set_attribute("auth.success", True)
span.set_attribute("user.id", user.id)
return user
except AuthenticationError as e:
span.set_attribute("auth.success", False)
span.set_attribute("error.type", "authentication_failed")
span.record_exception(e)
raise
# Usage
user = authenticate_user("john_doe", "password123")Understanding how OpenTelemetry attributes map to Datadog tags enables effective use of both APIs.
with tracer.start_as_current_span("mapped-operation") as span:
# OpenTelemetry attributes become Datadog tags
span.set_attribute("service.name", "payment-service") # -> service.name tag
span.set_attribute("http.method", "POST") # -> http.method tag
span.set_attribute("user.id", "12345") # -> user.id tag
span.set_attribute("custom.business_metric", "high_value") # -> custom.business_metric tag
# OpenTelemetry span kind maps to Datadog span.kind
span.set_attribute("span.kind", "client") # -> span.kind tag
# OpenTelemetry status maps to Datadog error state
span.set_status(trace.Status(trace.StatusCode.ERROR, "Payment failed"))Configure service information through OpenTelemetry Resource API or ddtrace configuration.
from opentelemetry.sdk.resources import Resource
from opentelemetry.semconv.resource import ResourceAttributes
# OpenTelemetry resource configuration
resource = Resource.create({
ResourceAttributes.SERVICE_NAME: "payment-processor",
ResourceAttributes.SERVICE_VERSION: "2.1.0",
ResourceAttributes.DEPLOYMENT_ENVIRONMENT: "production",
"custom.team": "payments",
"custom.region": "us-east-1"
})
# TracerProvider with resource configuration
provider = TracerProvider(resource=resource)
set_tracer_provider(provider)
# Alternatively, use ddtrace configuration
import ddtrace
ddtrace.config.service = "payment-processor"
ddtrace.config.version = "2.1.0"
ddtrace.config.env = "production"
ddtrace.config.tags = {
"team": "payments",
"region": "us-east-1"
}OpenTelemetry automatic instrumentation works seamlessly with ddtrace backend.
import os
os.environ["DD_TRACE_OTEL_ENABLED"] = "true"
# OpenTelemetry auto-instrumentation
from opentelemetry.instrumentation.requests import RequestsInstrumentor
from opentelemetry.instrumentation.psycopg2 import Psycopg2Instrumentor
# Auto-instrument libraries with OpenTelemetry
RequestsInstrumentor().instrument()
Psycopg2Instrumentor().instrument()
# Set ddtrace as backend
from opentelemetry.trace import set_tracer_provider
from ddtrace.opentelemetry import TracerProvider
set_tracer_provider(TracerProvider())
# Now requests and psycopg2 calls are automatically traced
import requests
import psycopg2
# HTTP request traced via OpenTelemetry instrumentation -> ddtrace backend
response = requests.get("https://api.example.com/data")
# Database query traced via OpenTelemetry instrumentation -> ddtrace backend
conn = psycopg2.connect("dbname=mydb")
cursor = conn.cursor()
cursor.execute("SELECT * FROM users")OpenTelemetry context propagation works with ddtrace trace context.
from opentelemetry import trace, propagate
from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator
tracer = trace.get_tracer(__name__)
# Inject trace context into HTTP headers
with tracer.start_as_current_span("parent-service") as span:
headers = {}
# Extract current context and inject into headers
propagate.inject(headers)
# Headers now contain trace context for downstream services
response = requests.get(
"https://downstream-service.com/api",
headers=headers
)
# Extract trace context from incoming request
def handle_request(request_headers):
# Extract context from incoming headers
ctx = propagate.extract(request_headers)
# Start span with extracted context as parent
with tracer.start_as_current_span("downstream-operation", context=ctx) as span:
span.set_attribute("service.role", "downstream")
return process_request()from opentelemetry import trace
from opentelemetry.trace import Link
tracer = trace.get_tracer(__name__)
# Create span with links to related spans
with tracer.start_as_current_span("batch-processor") as batch_span:
batch_span.set_attribute("batch.size", 100)
item_spans = []
for i in range(5): # Process sample items
with tracer.start_as_current_span(f"process-item-{i}") as item_span:
item_span.set_attribute("item.index", i)
item_spans.append(item_span.get_span_context())
# Create summary span linked to all item spans
links = [Link(span_context) for span_context in item_spans]
with tracer.start_as_current_span("batch-summary", links=links) as summary_span:
summary_span.set_attribute("summary.type", "batch_completion")with tracer.start_as_current_span("file-processing") as span:
span.add_event("file.opened", {
"file.name": "data.csv",
"file.size": 1024000
})
data = read_file("data.csv")
span.add_event("file.read", {
"rows.count": len(data),
"processing.duration": 0.5
})
results = process_data(data)
span.add_event("processing.completed", {
"results.count": len(results),
"success.rate": 0.95
})OpenTelemetry integration with ddtrace maintains high performance while providing API compatibility.
# Efficient span creation
with tracer.start_as_current_span("high-frequency-operation") as span:
# Minimize attribute operations in hot paths
span.set_attribute("operation.id", operation_id)
# Batch attribute setting when possible
span.set_attributes({
"service.component": "data-processor",
"operation.type": "transform",
"batch.size": batch_size
})
result = perform_operation()
# Set result attributes
span.set_attribute("result.status", "success")Migrate existing OpenTelemetry applications to use ddtrace backend with minimal code changes.
# Before: Pure OpenTelemetry setup
# from opentelemetry.sdk.trace import TracerProvider
# from opentelemetry.sdk.trace.export import BatchSpanProcessor
# from opentelemetry.exporter.jaeger.thrift import JaegerExporter
# After: OpenTelemetry with ddtrace backend
import os
os.environ["DD_TRACE_OTEL_ENABLED"] = "true"
from opentelemetry.trace import set_tracer_provider
from ddtrace.opentelemetry import TracerProvider
# Replace OpenTelemetry SDK with ddtrace backend
set_tracer_provider(TracerProvider())
# Rest of the application code remains unchanged
from opentelemetry import trace
tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("migrated-operation") as span:
span.set_attribute("migration.status", "completed")
# Existing OpenTelemetry code works without changesOpenTelemetry concepts map to Datadog concepts as follows:
This mapping ensures that OpenTelemetry instrumentation produces Datadog-compatible traces with all semantic information preserved.
Install with Tessl CLI
npx tessl i tessl/pypi-ddtrace