Coverage for netrun_errors / middleware.py: 100%
26 statements
« prev ^ index » next coverage.py v7.12.0, created at 2025-12-15 18:37 +0000
« prev ^ index » next coverage.py v7.12.0, created at 2025-12-15 18:37 +0000
1"""
2Error logging middleware for FastAPI applications.
4Provides request/response logging with correlation ID injection,
5performance tracking, and structured logging integration.
6"""
8import logging
9import time
10from typing import Callable
12from fastapi import Request, Response
13from starlette.middleware.base import BaseHTTPMiddleware
15from .base import NetrunException
17logger = logging.getLogger(__name__)
20class ErrorLoggingMiddleware(BaseHTTPMiddleware):
21 """
22 Middleware for request/response logging with correlation IDs.
24 Features:
25 - Automatic correlation ID generation and injection
26 - Request/response logging with timing
27 - Structured logging with request context
28 - Performance tracking
29 """
31 async def dispatch(self, request: Request, call_next: Callable) -> Response:
32 """
33 Process request with correlation ID and logging.
35 Args:
36 request: FastAPI request object
37 call_next: Next middleware/endpoint in chain
39 Returns:
40 Response from downstream handlers
41 """
42 # Generate correlation ID
43 correlation_id = NetrunException._generate_correlation_id()
45 # Add correlation ID to request state for downstream access
46 request.state.correlation_id = correlation_id
48 # Start timing
49 start_time = time.time()
51 # Log request
52 logger.info(
53 f"Request started: {request.method} {request.url.path}",
54 extra={
55 "correlation_id": correlation_id,
56 "method": request.method,
57 "path": request.url.path,
58 "query_params": dict(request.query_params),
59 "client_host": request.client.host if request.client else None,
60 },
61 )
63 try:
64 # Process request
65 response = await call_next(request)
67 # Calculate duration
68 duration_ms = (time.time() - start_time) * 1000
70 # Log response
71 logger.info(
72 f"Request completed: {request.method} {request.url.path} - {response.status_code}",
73 extra={
74 "correlation_id": correlation_id,
75 "method": request.method,
76 "path": request.url.path,
77 "status_code": response.status_code,
78 "duration_ms": round(duration_ms, 2),
79 },
80 )
82 # Inject correlation ID into response headers
83 response.headers["X-Correlation-ID"] = correlation_id
85 return response
87 except Exception as exc:
88 # Calculate duration
89 duration_ms = (time.time() - start_time) * 1000
91 # Log exception
92 logger.error(
93 f"Request failed: {request.method} {request.url.path}",
94 extra={
95 "correlation_id": correlation_id,
96 "method": request.method,
97 "path": request.url.path,
98 "duration_ms": round(duration_ms, 2),
99 "exception_type": type(exc).__name__,
100 },
101 exc_info=True,
102 )
104 # Re-raise for exception handlers
105 raise
108def install_error_logging_middleware(app) -> None:
109 """
110 Install error logging middleware on a FastAPI application.
112 Usage:
113 from fastapi import FastAPI
114 from netrun_errors import install_error_logging_middleware
116 app = FastAPI()
117 install_error_logging_middleware(app)
119 Args:
120 app: FastAPI application instance
121 """
122 app.add_middleware(ErrorLoggingMiddleware)
123 logger.info("Error logging middleware installed successfully")