[feat] wire observability into app
This commit is contained in:
parent
741e63e978
commit
0c55329769
4 changed files with 20 additions and 19 deletions
|
|
@ -4,7 +4,8 @@ from pathlib import Path
|
|||
|
||||
from adapter.config.loader import load_config
|
||||
from adapter.config.model import AppConfig
|
||||
from adapter.otel.bootstrap import OtelRuntime, setup_otel
|
||||
from adapter.observability.factory import build_observability
|
||||
from adapter.observability.runtime import ObservabilityRuntime
|
||||
from repository.user import InMemoryUserRepository
|
||||
from usecase.user import GetUser
|
||||
|
||||
|
|
@ -22,7 +23,7 @@ class AppUsecases:
|
|||
@dataclass(slots=True)
|
||||
class AppContainer:
|
||||
config: AppConfig
|
||||
observability: OtelRuntime
|
||||
observability: ObservabilityRuntime
|
||||
repositories: AppRepositories
|
||||
usecases: AppUsecases
|
||||
_is_shutdown: bool = field(default=False, init=False, repr=False)
|
||||
|
|
@ -51,7 +52,7 @@ def build_container(
|
|||
environ=environ,
|
||||
)
|
||||
|
||||
observability = setup_otel(app_config)
|
||||
observability = build_observability(app_config)
|
||||
|
||||
user_repository = InMemoryUserRepository()
|
||||
repositories = AppRepositories(user=user_repository)
|
||||
|
|
|
|||
|
|
@ -13,6 +13,6 @@ def create_app(config: AppConfig | None = None) -> FastAPI:
|
|||
app_config = load_config() if config is None else config
|
||||
app = FastAPI(title=app_config.app.name, lifespan=app_lifespan)
|
||||
setattr(app.state, APP_CONFIG_STATE, app_config)
|
||||
register_middleware(app)
|
||||
register_middleware(app, app_config)
|
||||
app.include_router(v1_router, prefix=API_V1_PREFIX)
|
||||
return app
|
||||
|
|
|
|||
|
|
@ -19,11 +19,13 @@ async def app_lifespan(app: FastAPI) -> AsyncIterator[None]:
|
|||
setattr(app.state, APP_CONTAINER_STATE, container)
|
||||
|
||||
try:
|
||||
FastAPIInstrumentor.instrument_app(
|
||||
app,
|
||||
tracer_provider=container.observability.tracer_provider,
|
||||
)
|
||||
instrumented = True
|
||||
tracer_provider = container.observability.tracer_provider
|
||||
if tracer_provider is not None:
|
||||
FastAPIInstrumentor.instrument_app(
|
||||
app,
|
||||
tracer_provider=tracer_provider,
|
||||
)
|
||||
instrumented = True
|
||||
yield
|
||||
finally:
|
||||
if instrumented:
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
from time import perf_counter
|
||||
|
||||
from adapter.config.model import AppConfig
|
||||
from adapter.http.fastapi.dependencies import get_container
|
||||
from fastapi import FastAPI, Request, Response
|
||||
|
||||
|
|
@ -7,7 +8,7 @@ REQUEST_COUNT = 'http.server.request.count'
|
|||
REQUEST_DURATION = 'http.server.request.duration'
|
||||
|
||||
|
||||
def register_middleware(app: FastAPI) -> None:
|
||||
def register_middleware(app: FastAPI, config: AppConfig) -> None:
|
||||
@app.middleware('http')
|
||||
async def request_logging_middleware(
|
||||
request: Request,
|
||||
|
|
@ -33,6 +34,9 @@ def register_middleware(app: FastAPI) -> None:
|
|||
},
|
||||
)
|
||||
|
||||
if not config.metrics.enabled:
|
||||
return
|
||||
|
||||
@app.middleware('http')
|
||||
async def metrics_middleware(
|
||||
request: Request,
|
||||
|
|
@ -48,9 +52,11 @@ def register_middleware(app: FastAPI) -> None:
|
|||
finally:
|
||||
duration_ms = (perf_counter() - start) * 1000
|
||||
container = get_container(request)
|
||||
route = request.scope.get('route')
|
||||
path = getattr(route, 'path', None)
|
||||
attrs: dict[str, str | int] = {
|
||||
'http.method': request.method,
|
||||
'http.path': _metric_path(request),
|
||||
'http.path': path if isinstance(path, str) and path else 'unmatched',
|
||||
'http.status_code': status_code,
|
||||
}
|
||||
container.observability.metrics.increment(REQUEST_COUNT, attrs=attrs)
|
||||
|
|
@ -59,11 +65,3 @@ def register_middleware(app: FastAPI) -> None:
|
|||
duration_ms,
|
||||
attrs=attrs,
|
||||
)
|
||||
|
||||
|
||||
def _metric_path(request: Request) -> str:
|
||||
route = request.scope.get('route')
|
||||
path = getattr(route, 'path', None)
|
||||
if isinstance(path, str) and path:
|
||||
return path
|
||||
return 'unmatched'
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue