logging_config.py 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. from __future__ import annotations
  2. """统一日志配置与trace_id上下文管理:通过contextvars实现一次工作流调用的trace_id贯穿所有日志。"""
  3. import logging
  4. import sys
  5. import uuid
  6. from contextvars import ContextVar
  7. _trace_id_context: ContextVar[str] = ContextVar(
  8. "trace_id",
  9. default="-",
  10. )
  11. class TraceIdFilter(logging.Filter):
  12. """向每条日志中注入当前请求trace_id。"""
  13. def filter(
  14. self,
  15. record: logging.LogRecord,
  16. ) -> bool:
  17. """向日志记录注入当前上下文的trace_id,供日志格式串引用。"""
  18. record.trace_id = get_trace_id()
  19. return True
  20. def configure_logging(
  21. level: int = logging.INFO,
  22. ) -> None:
  23. """配置TravelMind统一日志格式。"""
  24. handler = logging.StreamHandler(
  25. sys.stdout
  26. )
  27. handler.addFilter(TraceIdFilter())
  28. formatter = logging.Formatter(
  29. fmt=(
  30. "%(asctime)s "
  31. "| %(levelname)s "
  32. "| trace_id=%(trace_id)s "
  33. "| %(name)s "
  34. "| %(message)s"
  35. ),
  36. datefmt="%Y-%m-%d %H:%M:%S",
  37. )
  38. handler.setFormatter(formatter)
  39. root_logger = logging.getLogger()
  40. root_logger.handlers.clear()
  41. root_logger.addHandler(handler)
  42. root_logger.setLevel(level)
  43. # 降低第三方HTTP库的日志噪声。
  44. logging.getLogger(
  45. "httpcore"
  46. ).setLevel(logging.WARNING)
  47. logging.getLogger(
  48. "httpx"
  49. ).setLevel(logging.WARNING)
  50. def new_trace_id() -> str:
  51. """生成并设置一次工作流调用的trace_id。"""
  52. trace_id = uuid.uuid4().hex[:16]
  53. _trace_id_context.set(trace_id)
  54. return trace_id
  55. def set_trace_id(
  56. trace_id: str,
  57. ) -> None:
  58. """设置外部传入的trace_id。"""
  59. normalized = trace_id.strip()
  60. _trace_id_context.set(
  61. normalized or "-"
  62. )
  63. def get_trace_id() -> str:
  64. """读取当前上下文trace_id。"""
  65. return _trace_id_context.get()