Version 0.4.0
All checks were successful
Run linters on applied template / Python 3.13 lint and build (push) Successful in 1m40s
All checks were successful
Run linters on applied template / Python 3.13 lint and build (push) Successful in 1m40s
Changes: - put ObservabilityMiddleware before ExceptionHandlerMiddleware to avoid repetative code - add application startup and last metrics update metrics along with CPU usage metric and threads count - move host and port to new uvicorn section at config along with new reload and forwarded_allow_ips - add request_id and remove trace_id/span_id generation if tracing is disabled - move logging logic from utils to observability - pass trace_id/span_id in HEX form
This commit is contained in:
@@ -2,8 +2,9 @@
|
||||
|
||||
import os
|
||||
from contextlib import asynccontextmanager
|
||||
from typing import NoReturn
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi import FastAPI, Request
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.middleware.gzip import GZipMiddleware
|
||||
from fastapi.openapi.docs import get_swagger_ui_html
|
||||
@@ -14,30 +15,17 @@ from {{project_slug}}.db.connection.manager import PostgresConnectionManager
|
||||
from {{project_slug}}.dependencies import connection_manager_dep, logger_dep, metrics_dep
|
||||
from {{project_slug}}.exceptions.mapper import ExceptionMapper
|
||||
from {{project_slug}}.handlers.debug import DebugException, DebugExceptionWithParams
|
||||
from {{project_slug}}.middlewares.exception_handler import ExceptionHandlerMiddleware
|
||||
from {{project_slug}}.middlewares.exception_handler import ExceptionHandlerMiddleware, HandlerNotFoundError
|
||||
from {{project_slug}}.middlewares.observability import ObservabilityMiddleware
|
||||
from {{project_slug}}.observability.metrics import init_metrics
|
||||
from {{project_slug}}.observability.logging import configure_logging
|
||||
from {{project_slug}}.observability.metrics import setup_metrics
|
||||
from {{project_slug}}.observability.otel_agent import OpenTelemetryAgent
|
||||
from {{project_slug}}.utils.observability import URLsMapper, configure_logging
|
||||
from {{project_slug}}.observability.utils import URLsMapper
|
||||
|
||||
from .handlers import list_of_routers
|
||||
from .version import LAST_UPDATE, VERSION
|
||||
|
||||
|
||||
def _get_exception_mapper(debug: bool) -> ExceptionMapper:
|
||||
mapper = ExceptionMapper()
|
||||
if debug:
|
||||
mapper.register_simple(DebugException, 506, "That's how a debug exception look like")
|
||||
mapper.register_func(
|
||||
DebugExceptionWithParams,
|
||||
lambda exc: JSONResponse(
|
||||
{"error": "That's how a debug exception with params look like", "message": exc.message},
|
||||
status_code=exc.status_code,
|
||||
),
|
||||
)
|
||||
return mapper
|
||||
|
||||
|
||||
def bind_routes(application: FastAPI, prefix: str, debug: bool) -> None:
|
||||
"""Bind all routes to application."""
|
||||
for router in list_of_routers:
|
||||
@@ -84,6 +72,10 @@ def get_app(prefix: str = "/api") -> FastAPI:
|
||||
swagger_css_url="https://unpkg.com/swagger-ui-dist@5.11.7/swagger-ui.css",
|
||||
)
|
||||
|
||||
@application.exception_handler(404)
|
||||
async def handle_404(request: Request, exc: Exception) -> NoReturn:
|
||||
raise HandlerNotFoundError() from exc
|
||||
|
||||
application.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=app_config.app.cors.allow_origins,
|
||||
@@ -99,30 +91,34 @@ def get_app(prefix: str = "/api") -> FastAPI:
|
||||
app_config.observability.logging,
|
||||
tracing_enabled=app_config.observability.jaeger is not None,
|
||||
)
|
||||
metrics = init_metrics()
|
||||
exception_mapper = _get_exception_mapper(app_config.app.debug)
|
||||
metrics = setup_metrics()
|
||||
|
||||
exception_mapper = ExceptionMapper()
|
||||
_register_exceptions(exception_mapper, debug=app_config.app.debug)
|
||||
connection_manager = PostgresConnectionManager(
|
||||
master=app_config.db.master,
|
||||
replicas=app_config.db.replicas,
|
||||
logger=logger,
|
||||
application_name=f"{{project_slug}}_{VERSION}",
|
||||
)
|
||||
urls_mapper = URLsMapper(app_config.observability.prometheus.urls_mapping)
|
||||
urls_mapper = URLsMapper()
|
||||
urls_mapper.add_routes(application.routes)
|
||||
|
||||
connection_manager_dep.init_dispencer(application, connection_manager)
|
||||
metrics_dep.init_dispencer(application, metrics)
|
||||
logger_dep.init_dispencer(application, logger)
|
||||
|
||||
application.add_middleware(
|
||||
ObservabilityMiddleware,
|
||||
ExceptionHandlerMiddleware,
|
||||
debug=app_config.app.debug,
|
||||
exception_mapper=exception_mapper,
|
||||
metrics=metrics,
|
||||
urls_mapper=urls_mapper,
|
||||
errors_metric=metrics.http.errors,
|
||||
)
|
||||
application.add_middleware(
|
||||
ExceptionHandlerMiddleware,
|
||||
debug=[app_config.app.debug],
|
||||
exception_mapper=exception_mapper,
|
||||
ObservabilityMiddleware,
|
||||
metrics=metrics,
|
||||
urls_mapper=urls_mapper,
|
||||
)
|
||||
|
||||
return application
|
||||
@@ -135,13 +131,9 @@ async def lifespan(application: FastAPI):
|
||||
Initializes database connection in pass_services_dependencies middleware.
|
||||
"""
|
||||
app_config: {{ProjectName}}Config = application.state.config
|
||||
logger = logger_dep.obtain(application)
|
||||
logger = logger_dep.from_app(application)
|
||||
|
||||
await logger.ainfo("application is being configured", config=app_config.to_order_dict())
|
||||
|
||||
for middleware in application.user_middleware:
|
||||
if middleware.cls == ExceptionHandlerMiddleware:
|
||||
middleware.kwargs["debug"][0] = app_config.app.debug
|
||||
await logger.ainfo("application is starting", config=app_config.to_order_dict())
|
||||
|
||||
otel_agent = OpenTelemetryAgent(
|
||||
app_config.observability.prometheus,
|
||||
@@ -153,4 +145,17 @@ async def lifespan(application: FastAPI):
|
||||
otel_agent.shutdown()
|
||||
|
||||
|
||||
def _register_exceptions(mapper: ExceptionMapper, debug: bool) -> None:
|
||||
if debug:
|
||||
mapper.register_simple(DebugException, 506, "That's how a debug exception look like")
|
||||
mapper.register_func(
|
||||
DebugExceptionWithParams,
|
||||
lambda exc: JSONResponse(
|
||||
{"error": "That's how a debug exception with params look like", "message": exc.message},
|
||||
status_code=exc.status_code,
|
||||
),
|
||||
)
|
||||
return mapper
|
||||
|
||||
|
||||
app = get_app()
|
||||
|
||||
Reference in New Issue
Block a user