Files
danial 0e41e7acce feat(core): 初始化核心配置和部署文件
- 添加 .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 全局异常处理中间件
2025-11-01 14:32:29 +08:00

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