Files
g2s-aggregator/app/runtime/tracing.py
T
Раис Юсупалиев 66beab4682 015 add tracing
2026-03-14 00:28:51 +03:00

76 lines
2.8 KiB
Python

"""Centralized runtime OpenTelemetry tracing bootstrap."""
from fastapi import FastAPI
from opentelemetry import trace
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
from opentelemetry.instrumentation.httpx import HTTPXClientInstrumentor
from opentelemetry.instrumentation.redis import RedisInstrumentor
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from app.config import ObservabilityConfig
_HTTPX_INSTRUMENTOR = HTTPXClientInstrumentor()
_REDIS_INSTRUMENTOR = RedisInstrumentor()
_TRACER_PROVIDER: TracerProvider | None = None
def configure_tracing(app: FastAPI, observability: ObservabilityConfig) -> None:
if not observability.enabled:
return
tracer_provider = _get_or_create_tracer_provider(observability)
_instrument_fastapi_app(app, tracer_provider=tracer_provider)
_instrument_httpx(tracer_provider=tracer_provider)
_instrument_redis(tracer_provider=tracer_provider)
def _get_or_create_tracer_provider(observability: ObservabilityConfig) -> TracerProvider:
global _TRACER_PROVIDER
if _TRACER_PROVIDER is not None:
return _TRACER_PROVIDER
tracer_provider = _build_tracer_provider(observability)
trace.set_tracer_provider(tracer_provider)
_TRACER_PROVIDER = tracer_provider
return tracer_provider
def _build_tracer_provider(observability: ObservabilityConfig) -> TracerProvider:
exporter = _build_span_exporter(observability)
tracer_provider = TracerProvider(resource=_build_resource(observability))
tracer_provider.add_span_processor(BatchSpanProcessor(exporter))
return tracer_provider
def _build_span_exporter(observability: ObservabilityConfig) -> OTLPSpanExporter:
return OTLPSpanExporter(
endpoint=observability.otlp_endpoint,
insecure=observability.otlp_insecure,
)
def _build_resource(observability: ObservabilityConfig) -> Resource:
return Resource.create({"service.name": observability.service_name})
def _instrument_fastapi_app(app: FastAPI, *, tracer_provider: TracerProvider) -> None:
if getattr(app, "_is_instrumented_by_opentelemetry", False):
return
FastAPIInstrumentor.instrument_app(app, tracer_provider=tracer_provider)
def _instrument_httpx(*, tracer_provider: TracerProvider) -> None:
if _HTTPX_INSTRUMENTOR.is_instrumented_by_opentelemetry:
return
_HTTPX_INSTRUMENTOR.instrument(tracer_provider=tracer_provider)
def _instrument_redis(*, tracer_provider: TracerProvider) -> None:
if _REDIS_INSTRUMENTOR.is_instrumented_by_opentelemetry:
return
_REDIS_INSTRUMENTOR.instrument(tracer_provider=tracer_provider)