import os from opentelemetry import metrics, trace from opentelemetry.sdk.metrics import MeterProvider from opentelemetry.sdk.resources import SERVICE_NAME, Resource 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.exporter.prometheus import PrometheusMetricReader from opentelemetry.instrumentation.httpx import HTTPXClientInstrumentor from opentelemetry.instrumentation.redis import RedisInstrumentor from prometheus_client import start_http_server def setup_telemetry(service_name: str): resource = Resource.create(attributes={SERVICE_NAME: service_name}) processor = BatchSpanProcessor(OTLPSpanExporter()) provider = TracerProvider(resource=resource) provider.add_span_processor(processor) trace.set_tracer_provider(provider) # Pull, not push: Alloy 404s OTLP metrics, so Prometheus scrapes each # service instead. The reader renders current values on every scrape. # It serves on its own port rather than a FastAPI route so /metrics is # never reachable through gateway's public Traefik router, and so the # audit worker (no HTTP app) exposes metrics the same way. reader = PrometheusMetricReader() metrics.set_meter_provider(MeterProvider(resource=resource, metric_readers=[reader])) start_http_server( port=int(os.environ.get("OTEL_EXPORTER_PROMETHEUS_PORT", "9464")), addr=os.environ.get("OTEL_EXPORTER_PROMETHEUS_HOST", "0.0.0.0"), ) # Process-wide patches on the client classes, so they also cover clients # created at import time (gateway's _proxy_client, common.redis_client). HTTPXClientInstrumentor().instrument() RedisInstrumentor().instrument()