99from fastapi import Depends , FastAPI
1010from fastapi_limiter import FastAPILimiter
1111from fastapi_pagination import add_pagination
12+ from prometheus_client import make_asgi_app
1213from starlette .middleware .authentication import AuthenticationMiddleware
1314from starlette .middleware .cors import CORSMiddleware
1415from starlette .staticfiles import StaticFiles
15- from starlette .types import ASGIApp
1616from starlette_context .middleware import ContextMiddleware
1717from starlette_context .plugins import RequestIdPlugin
1818
3333from backend .utils .demo_site import demo_site
3434from backend .utils .health_check import ensure_unique_route_names , http_limit_callback
3535from backend .utils .openapi import simplify_operation_ids
36+ from backend .utils .otel import init_otel
3637from backend .utils .serializers import MsgSpecJSONResponse
3738from backend .utils .snowflake import snowflake
39+ from backend .utils .trace_id import OtelTraceIdPlugin
3840
3941
4042@asynccontextmanager
@@ -76,22 +78,7 @@ async def register_init(app: FastAPI) -> AsyncGenerator[None, None]:
7678def register_app () -> FastAPI :
7779 """注册 FastAPI 应用"""
7880
79- class MyFastAPI (FastAPI ):
80- if settings .MIDDLEWARE_CORS :
81- # Related issues
82- # https://github.com/fastapi/fastapi/discussions/7847
83- # https://github.com/fastapi/fastapi/discussions/8027
84- def build_middleware_stack (self ) -> ASGIApp :
85- return CORSMiddleware (
86- super ().build_middleware_stack (),
87- allow_origins = settings .CORS_ALLOWED_ORIGINS ,
88- allow_credentials = True ,
89- allow_methods = ['*' ],
90- allow_headers = ['*' ],
91- expose_headers = settings .CORS_EXPOSE_HEADERS ,
92- )
93-
94- app = MyFastAPI (
81+ app = FastAPI (
9582 title = settings .FASTAPI_TITLE ,
9683 version = __version__ ,
9784 description = settings .FASTAPI_DESCRIPTION ,
@@ -111,6 +98,9 @@ def build_middleware_stack(self) -> ASGIApp:
11198 register_page (app )
11299 register_exception (app )
113100
101+ if settings .GRAFANA_METRICS :
102+ register_metrics (app )
103+
114104 return app
115105
116106
@@ -164,15 +154,29 @@ def register_middleware(app: FastAPI) -> None:
164154 app .add_middleware (AccessMiddleware )
165155
166156 # ContextVar
157+ plugins = [OtelTraceIdPlugin ()] if settings .GRAFANA_METRICS else [RequestIdPlugin (validate = True )]
167158 app .add_middleware (
168159 ContextMiddleware ,
169- plugins = [ RequestIdPlugin ( validate = True )] ,
160+ plugins = plugins ,
170161 default_error_response = MsgSpecJSONResponse (
171162 content = {'code' : StandardResponseCode .HTTP_400 , 'msg' : 'BAD_REQUEST' , 'data' : None },
172163 status_code = StandardResponseCode .HTTP_400 ,
173164 ),
174165 )
175166
167+ # CORS
168+ # https://github.com/fastapi-practices/fastapi_best_architecture/pull/789/changes
169+ # https://github.com/open-telemetry/opentelemetry-python-contrib/issues/4031
170+ if settings .MIDDLEWARE_CORS :
171+ app .add_middleware (
172+ CORSMiddleware ,
173+ allow_origins = settings .CORS_ALLOWED_ORIGINS ,
174+ allow_credentials = True ,
175+ allow_methods = ['*' ],
176+ allow_headers = ['*' ],
177+ expose_headers = settings .CORS_EXPOSE_HEADERS ,
178+ )
179+
176180
177181def register_router (app : FastAPI ) -> None :
178182 """
@@ -218,3 +222,16 @@ def register_socket_app(app: FastAPI) -> None:
218222 socketio_path = '/ws/socket.io' ,
219223 )
220224 app .mount ('/ws' , socket_app )
225+
226+
227+ def register_metrics (app : FastAPI ) -> None :
228+ """
229+ 注册指标
230+
231+ :param app: FastAPI 应用实例
232+ :return:
233+ """
234+ metrics_app = make_asgi_app ()
235+ app .mount ('/metrics' , metrics_app )
236+
237+ init_otel (app )
0 commit comments