CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-ddtrace

Datadog APM client library providing distributed tracing, continuous profiling, error tracking, test optimization, deployment tracking, code hotspots analysis, and dynamic instrumentation for Python applications.

Pending
Overview
Eval results
Files

opentelemetry-integration.mddocs/

OpenTelemetry Integration

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.

Capabilities

TracerProvider

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
        """

Configuration and Setup

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__)

Mixed API Usage

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")

OpenTelemetry Span Operations

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()

Span Decorator Usage

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")

Attribute and Tag Mapping

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"))

Resource and Service Configuration

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"
}

Instrumentation Integration

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")

Context Propagation

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()

Advanced OpenTelemetry Features

Span Links

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")

Span Events

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
    })

Performance Considerations

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")

Migration from Pure OpenTelemetry

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 changes

Data Mapping

OpenTelemetry concepts map to Datadog concepts as follows:

  • trace_idtraceID
  • span_idspanID
  • parent_span_idparentID
  • nameresource
  • kindmeta["span.kind"]
  • start_time_unix_nanostart
  • end_time_unix_nanoduration (derived)
  • attributes[<key>]meta[<key>]
  • links[]meta["_dd.span_links"]
  • statuserror (derived)
  • events[]meta["events"]

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

docs

application-security.md

automatic-instrumentation.md

configuration-settings.md

core-tracing.md

index.md

opentelemetry-integration.md

profiling.md

tile.json