MemPrepMate / src /utils /tracing.py
Christian Kniep
fix oauth
018ba2e
"""
Jaeger tracing utilities using OpenTelemetry.
Uses OpenTelemetry OTLP HTTP exporter to send traces to Jaeger.
This matches the Go API approach of using HTTP instead of unreliable UDP.
"""
import logging
import os
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.resources import Resource
from opentelemetry.instrumentation.flask import FlaskInstrumentor
from opentelemetry.instrumentation.requests import RequestsInstrumentor
logger = logging.getLogger(__name__)
def is_tracing_enabled() -> bool:
"""
Check if tracing is enabled via ENABLE_TRACING environment variable.
Returns:
True if tracing is enabled (default), False otherwise
"""
return os.getenv("ENABLE_TRACING", "true").lower() in ("true", "1", "yes")
def init_tracer(service_name: str) -> trace.Tracer:
"""
Initialize OpenTelemetry tracer with OTLP HTTP exporter for Jaeger.
Uses HTTP protocol like the Go API (instead of unreliable UDP).
Jaeger >= 1.35 supports OTLP natively on port 4318.
Can be disabled by setting ENABLE_TRACING=false environment variable.
Args:
service_name: Name of the service for tracing
Returns:
Configured tracer instance (or no-op tracer if disabled)
"""
# Check if tracing is enabled BEFORE doing anything
if not is_tracing_enabled():
print(f"[TRACING] Tracing disabled via ENABLE_TRACING environment variable")
logger.info("OpenTelemetry tracing disabled - no exporter or instrumentation will be initialized")
# Return no-op tracer WITHOUT setting up any exporters or instrumentation
# This prevents any connection attempts to Jaeger
return trace.get_tracer(service_name)
# Jaeger OTLP HTTP endpoint (port 4318)
otlp_endpoint = os.getenv("OTEL_EXPORTER_OTLP_ENDPOINT", "http://jaeger:4318")
sampling_rate = float(os.getenv("JAEGER_SAMPLING_RATE", "1.0"))
print(f"[TRACING] Initializing OpenTelemetry with endpoint={otlp_endpoint}")
# Create resource with service name
resource = Resource.create({"service.name": service_name})
# Create tracer provider
provider = TracerProvider(resource=resource)
# Create OTLP HTTP exporter
otlp_exporter = OTLPSpanExporter(
endpoint=f"{otlp_endpoint}/v1/traces",
timeout=2, # 2 second timeout like Go API
)
# Add batch span processor (matches Go API's buffering)
processor = BatchSpanProcessor(
otlp_exporter,
max_queue_size=2048, # Default queue size
max_export_batch_size=512, # Must be <= max_queue_size
schedule_delay_millis=1000, # 1 second flush interval like Go API
)
provider.add_span_processor(processor)
# Set as global tracer provider
trace.set_tracer_provider(provider)
# Get tracer
tracer = trace.get_tracer(service_name)
# Auto-instrument Flask and requests ONLY when tracing is enabled
FlaskInstrumentor().instrument()
RequestsInstrumentor().instrument()
print(f"[TRACING] OpenTelemetry tracer initialized: service={service_name}, endpoint={otlp_endpoint}, sampling={sampling_rate}")
logger.info(
f"OpenTelemetry tracer initialized with OTLP HTTP exporter",
extra={
"service": service_name,
"otlp_endpoint": otlp_endpoint,
"sampling_rate": sampling_rate,
}
)
return tracer