54 lines
1.3 KiB
Python
54 lines
1.3 KiB
Python
|
|
"""TraceID 贯穿:ContextVar + 12-hex 生成 + logging.Filter。
|
|||
|
|
|
|||
|
|
每个 HTTP 请求生成唯一 trace_id,注入 ContextVar,日志通过 TraceFilter
|
|||
|
|
自动带上 trace_id 字段,便于全链路追踪。
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
from __future__ import annotations
|
|||
|
|
|
|||
|
|
import logging
|
|||
|
|
import random
|
|||
|
|
import contextvars
|
|||
|
|
|
|||
|
|
# 单请求内贯穿的 trace_id
|
|||
|
|
trace_id_var: contextvars.ContextVar[str] = contextvars.ContextVar(
|
|||
|
|
"trace_id", default=""
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
def new_trace_id() -> str:
|
|||
|
|
"""生成 12 字符 hex trace_id。
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
12 字符 hex 字符串(如 "a3b5c7d9e1f2")
|
|||
|
|
"""
|
|||
|
|
return f"{random.getrandbits(48):012x}"
|
|||
|
|
|
|||
|
|
|
|||
|
|
def get_trace_id() -> str:
|
|||
|
|
"""获取当前 ContextVar 中的 trace_id。"""
|
|||
|
|
return trace_id_var.get()
|
|||
|
|
|
|||
|
|
|
|||
|
|
def set_trace_id(trace_id: str) -> contextvars.Token:
|
|||
|
|
"""设置 trace_id,返回 Token 供 reset 使用。"""
|
|||
|
|
return trace_id_var.set(trace_id)
|
|||
|
|
|
|||
|
|
|
|||
|
|
def reset_trace_id(token: contextvars.Token) -> None:
|
|||
|
|
"""重置 trace_id 到之前的状态。"""
|
|||
|
|
trace_id_var.reset(token)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class TraceFilter(logging.Filter):
|
|||
|
|
"""日志 Filter:在每条日志的 extra 中注入 trace_id。
|
|||
|
|
|
|||
|
|
用法:
|
|||
|
|
logger.addFilter(TraceFilter())
|
|||
|
|
日志格式中可用 %(trace_id)s 引用。
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
def filter(self, record: logging.LogRecord) -> bool:
|
|||
|
|
record.trace_id = trace_id_var.get()
|
|||
|
|
return True
|