- 添加 .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 全局异常处理中间件
106 lines
3.0 KiB
Python
106 lines
3.0 KiB
Python
"""
|
|
TraceID injection middleware with W3C Trace Context support.
|
|
Extracts or generates trace IDs and propagates them through the request lifecycle.
|
|
"""
|
|
|
|
import uuid
|
|
from typing import Callable
|
|
from fastapi import Request, Response
|
|
from starlette.middleware.base import BaseHTTPMiddleware
|
|
from starlette.types import ASGIApp
|
|
from observability.logging import set_trace_id
|
|
|
|
|
|
class TraceContextMiddleware(BaseHTTPMiddleware):
|
|
"""
|
|
Middleware for trace context management.
|
|
|
|
Extracts trace ID from W3C Trace Context headers or generates a new one.
|
|
Adds trace ID to request state and response headers.
|
|
"""
|
|
|
|
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 inject trace context.
|
|
|
|
Args:
|
|
request: Incoming request
|
|
call_next: Next middleware or route handler
|
|
|
|
Returns:
|
|
Response: Response with trace ID header
|
|
"""
|
|
# Extract trace ID from W3C Trace Context header (traceparent)
|
|
# Format: 00-{trace_id}-{parent_id}-{flags}
|
|
trace_id = self._extract_trace_id(request)
|
|
|
|
# Generate new trace ID if not present
|
|
if not trace_id:
|
|
trace_id = str(uuid.uuid4())
|
|
|
|
# Store trace ID in request state
|
|
request.state.trace_id = trace_id
|
|
|
|
# Set trace ID in logging context
|
|
set_trace_id(trace_id)
|
|
|
|
# Process request
|
|
response = await call_next(request)
|
|
|
|
# Add trace ID to response headers
|
|
response.headers["X-Trace-ID"] = trace_id
|
|
|
|
return response
|
|
|
|
def _extract_trace_id(self, request: Request) -> str:
|
|
"""
|
|
Extract trace ID from request headers.
|
|
|
|
Supports:
|
|
- W3C Trace Context (traceparent header)
|
|
- X-Trace-ID custom header
|
|
|
|
Args:
|
|
request: Incoming request
|
|
|
|
Returns:
|
|
str: Trace ID or empty string if not found
|
|
"""
|
|
# Try X-Trace-ID header first (custom header)
|
|
trace_id = request.headers.get("X-Trace-ID", "")
|
|
if trace_id:
|
|
return trace_id
|
|
|
|
# Try W3C Trace Context traceparent header
|
|
# Format: 00-{trace_id}-{parent_id}-{flags}
|
|
traceparent = request.headers.get("traceparent", "")
|
|
if traceparent:
|
|
parts = traceparent.split("-")
|
|
if len(parts) >= 2:
|
|
# Extract trace_id (second part)
|
|
return parts[1]
|
|
|
|
return ""
|
|
|
|
|
|
def get_trace_id_from_request(request: Request) -> str:
|
|
"""
|
|
Get trace ID from request state.
|
|
|
|
Args:
|
|
request: FastAPI request
|
|
|
|
Returns:
|
|
str: Trace ID or empty string
|
|
"""
|
|
return getattr(request.state, "trace_id", "")
|