- 添加 .env.example 环境变量配置示例 - 添加 .gitignore 忽略文件配置 - 添加 core/config.py 配置管理模块 - 添加 deployments/k8s/configmap.yaml Kubernetes 配置 - 添加 core/database.py 数据库连接管理模块 - 添加 core/dependencies.py 全局依赖模块 - 添加 DEPENDENCIES_UPDATED.md 依赖更新记录 - 添加 deployments/k8s/deployment.yaml Kubernetes 部署配置- 添加 deployments/swarm/docker-compose.swarm.yml Docker Swarm 部署配置 - 添加 deployments/docker/docker-compose.yml Docker 部署配置 - 添加 deployments/docker/Dockerfile 应用镜像构建文件 - 添加 middleware/error_handler.py 全局异常处理中间件
108 lines
3.2 KiB
Python
108 lines
3.2 KiB
Python
"""
|
|
Request and response logging middleware.
|
|
Logs all incoming requests and outgoing responses with trace context.
|
|
"""
|
|
|
|
import time
|
|
from typing import Callable
|
|
from fastapi import Request, Response
|
|
from starlette.middleware.base import BaseHTTPMiddleware
|
|
from starlette.types import ASGIApp
|
|
from observability.logging import get_logger
|
|
|
|
logger = get_logger(__name__)
|
|
|
|
|
|
class RequestLoggingMiddleware(BaseHTTPMiddleware):
|
|
"""
|
|
Middleware for logging HTTP requests and responses.
|
|
|
|
Logs:
|
|
- Request method, path, client IP
|
|
- Response status code, processing time
|
|
- Trace ID for correlation
|
|
"""
|
|
|
|
def __init__(self, app: ASGIApp):
|
|
"""
|
|
Initialize middleware.
|
|
|
|
Args:
|
|
app: ASGI application
|
|
"""
|
|
super().__init__(app)
|
|
|
|
async def dispatch(self, request: Request, call_next: Callable) -> Response:
|
|
"""
|
|
Process request and log details.
|
|
|
|
Args:
|
|
request: Incoming request
|
|
call_next: Next middleware or route handler
|
|
|
|
Returns:
|
|
Response: Response from handler
|
|
"""
|
|
# Record start time
|
|
start_time = time.time()
|
|
|
|
# Get trace ID from request state
|
|
trace_id = getattr(request.state, "trace_id", "")
|
|
|
|
# Get client IP
|
|
client_ip = request.client.host if request.client else "unknown"
|
|
|
|
# Log request
|
|
logger.info(
|
|
f"Request started: {request.method} {request.url.path}",
|
|
extra={
|
|
"method": request.method,
|
|
"path": request.url.path,
|
|
"query_params": str(request.query_params),
|
|
"client_ip": client_ip,
|
|
"trace_id": trace_id,
|
|
}
|
|
)
|
|
|
|
# Process request
|
|
try:
|
|
response = await call_next(request)
|
|
except Exception as e:
|
|
# Calculate processing time
|
|
process_time = time.time() - start_time
|
|
|
|
# Log error
|
|
logger.error(
|
|
f"Request failed: {request.method} {request.url.path} - {str(e)}",
|
|
extra={
|
|
"method": request.method,
|
|
"path": request.url.path,
|
|
"client_ip": client_ip,
|
|
"trace_id": trace_id,
|
|
"process_time_ms": round(process_time * 1000, 2),
|
|
},
|
|
exc_info=True
|
|
)
|
|
raise
|
|
|
|
# Calculate processing time
|
|
process_time = time.time() - start_time
|
|
|
|
# Log response
|
|
logger.info(
|
|
f"Request completed: {request.method} {request.url.path} - {response.status_code}",
|
|
extra={
|
|
"method": request.method,
|
|
"path": request.url.path,
|
|
"status_code": response.status_code,
|
|
"client_ip": client_ip,
|
|
"trace_id": trace_id,
|
|
"process_time_ms": round(process_time * 1000, 2),
|
|
}
|
|
)
|
|
|
|
# Add processing time header
|
|
response.headers["X-Process-Time"] = f"{process_time:.4f}"
|
|
|
|
return response
|