"""OTel initialization — called at app startup (U1: OTel now required).""" import logging from opentelemetry import trace, metrics from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor from opentelemetry.sdk.metrics import MeterProvider from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader from opentelemetry.sdk.resources import Resource from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import OTLPMetricExporter from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor logger = logging.getLogger(__name__) def setup_telemetry(app, config: dict | None = None): """Initialize OpenTelemetry if configured. U1: opentelemetry-* deps now required (pyproject.toml). ImportError fallbacks removed — a missing package is a hard install error. The `enabled=False` config switch remains the supported way to disable. Args: app: FastAPI application instance config: Telemetry configuration dict with keys: - enabled (bool): Whether to enable telemetry - service_name (str): Service name for OTel resource - otlp_endpoint (str): OTLP gRPC endpoint URL - export_traces (bool): Whether to export traces - export_metrics (bool): Whether to export metrics """ if not config or not config.get("enabled", False): logger.info("Telemetry disabled") return service_name = config.get("service_name", "fischer-agentkit") resource = Resource.create({"service.name": service_name}) # Tracing setup if config.get("export_traces", True): endpoint = config.get("otlp_endpoint", "http://localhost:4317") provider = TracerProvider(resource=resource) provider.add_span_processor( BatchSpanProcessor(OTLPSpanExporter(endpoint=endpoint, insecure=True)) ) trace.set_tracer_provider(provider) logger.info(f"Tracing enabled, exporting to {endpoint}") # Metrics setup if config.get("export_metrics", True): endpoint = config.get("otlp_endpoint", "http://localhost:4317") reader = PeriodicExportingMetricReader(OTLPMetricExporter(endpoint=endpoint, insecure=True)) # ponytail: OTel SDK 1.16+ 将 readers kwarg 改名为 metric_readers; # 旧代码用 readers=[...] 是已存在 bug,被 ImportError fallback 掩盖。 provider = MeterProvider(resource=resource, metric_readers=[reader]) metrics.set_meter_provider(provider) logger.info(f"Metrics enabled, exporting to {endpoint}") # FastAPI auto-instrumentation FastAPIInstrumentor.instrument_app(app, excluded_urls="health,metrics") logger.info("FastAPI auto-instrumentation enabled")