Files
fastapi-best-architecture/backend/common/observability/otel.py
T
Wu Clan 7568275126 Add multiple database data source config (#1232)
* Add multiple database data source config

* Fix comments

* Fix deploy env
2026-08-14 17:44:45 +08:00

123 lines
4.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from fastapi import FastAPI
from opentelemetry import _logs, metrics, trace
from opentelemetry.exporter.otlp.proto.grpc._log_exporter import OTLPLogExporter
from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import OTLPMetricExporter
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
from opentelemetry.instrumentation.httpx import HTTPXClientInstrumentor
from opentelemetry.instrumentation.logging import LoggingInstrumentor
from opentelemetry.instrumentation.redis import RedisInstrumentor
from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor
from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler
from opentelemetry.sdk._logs._internal.export import BatchLogRecordProcessor
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from redis.observability.config import OTelConfig
from redis.observability.providers import get_observability_instance
from backend.common.log import log, request_id_filter
from backend.core.conf import settings
from backend.database.db import get_database_engines
from backend.database.redis import redis_client
def init_resource(service_name: str) -> Resource:
"""
初始化资源
:param service_name: 服务名称
:return:
"""
from backend import __version__
return Resource(
attributes={
'service.name': service_name,
'service.version': __version__,
'deployment.environment': settings.ENVIRONMENT,
},
)
def init_tracer(resource: Resource) -> None:
"""
初始化追踪器
:param resource: 遥测资源
:return:
"""
provider = TracerProvider(resource=resource)
exporter = OTLPSpanExporter(endpoint=settings.GRAFANA_OTLP_GRPC_ENDPOINT, insecure=True)
processor = BatchSpanProcessor(span_exporter=exporter)
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)
def init_metrics(resource: Resource) -> None:
"""
初始化指标
:param resource: 遥测资源
:return:
"""
exporter = OTLPMetricExporter(endpoint=settings.GRAFANA_OTLP_GRPC_ENDPOINT, insecure=True)
reader = PeriodicExportingMetricReader(exporter=exporter)
provider = MeterProvider(resource=resource, metric_readers=[reader])
metrics.set_meter_provider(provider)
def init_logging(resource: Resource) -> None:
"""
初始化日志
:param resource: 遥测资源
:return:
"""
provider = LoggerProvider(resource=resource)
exporter = OTLPLogExporter(endpoint=settings.GRAFANA_OTLP_GRPC_ENDPOINT, insecure=True)
processor = BatchLogRecordProcessor(exporter=exporter)
provider.add_log_record_processor(processor)
_logs.set_logger_provider(provider)
otel_logging_handler = LoggingHandler(logger_provider=provider)
log.add(
otel_logging_handler,
level=settings.LOG_STD_LEVEL,
format=settings.LOG_FORMAT,
filter=lambda record: request_id_filter(record),
)
def init_otel(app: FastAPI) -> None:
"""
初始化 OpenTelemetry
:param app: FastAPI 应用实例
:return:
"""
resource = init_resource(settings.GRAFANA_PROMETHEUS_APP_NAME)
init_tracer(resource)
init_metrics(resource)
init_logging(resource)
# Redis 原生指标
redis_otel = get_observability_instance()
redis_otel.init(OTelConfig())
AsyncioInstrumentor().instrument()
HTTPXClientInstrumentor().instrument()
# 禁止自动将 OTel handler 安装到 stdlib root logger
# 避免与上面注册的 LoggingHandlerloguru sink)重复推送。
LoggingInstrumentor().instrument(set_logging_format=True, enable_log_auto_instrumentation=False)
RedisInstrumentor.instrument_client(client=redis_client) # type: ignore
for engine in get_database_engines().values():
SQLAlchemyInstrumentor().instrument(engine=engine.sync_engine)
FastAPIInstrumentor.instrument_app(app)