67 lines
1.9 KiB
Python
67 lines
1.9 KiB
Python
|
|
"""
|
|||
|
|
loguru 统一日志配置 + InterceptHandler 拦截标准库 logging。
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
import logging
|
|||
|
|
import sys
|
|||
|
|
|
|||
|
|
from loguru import logger
|
|||
|
|
|
|||
|
|
|
|||
|
|
class InterceptHandler(logging.Handler):
|
|||
|
|
"""Route standard-library logging messages into loguru."""
|
|||
|
|
|
|||
|
|
def emit(self, record: logging.LogRecord) -> None:
|
|||
|
|
try:
|
|||
|
|
level = logger.level(record.levelname).name
|
|||
|
|
except ValueError:
|
|||
|
|
level = record.levelno
|
|||
|
|
|
|||
|
|
frame, depth = logging.currentframe(), 2
|
|||
|
|
while frame and frame.f_code.co_filename == logging.__file__:
|
|||
|
|
frame = frame.f_back
|
|||
|
|
depth += 1
|
|||
|
|
|
|||
|
|
logger.opt(depth=depth, exception=record.exc_info).log(level, record.getMessage())
|
|||
|
|
|
|||
|
|
|
|||
|
|
def setup_logging() -> None:
|
|||
|
|
"""Call once at application startup, before any other import that logs."""
|
|||
|
|
logger.remove()
|
|||
|
|
|
|||
|
|
logger.add(
|
|||
|
|
sys.stderr,
|
|||
|
|
level="INFO",
|
|||
|
|
format=(
|
|||
|
|
"<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | "
|
|||
|
|
"<level>{level: <8}</level> | "
|
|||
|
|
"<cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> | "
|
|||
|
|
"{extra[request_id]} | "
|
|||
|
|
"<level>{message}</level>"
|
|||
|
|
),
|
|||
|
|
backtrace=True,
|
|||
|
|
diagnose=False,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 将根 logger 重定向到 loguru,不再使用 basicConfig(文档要求:统一走 loguru)
|
|||
|
|
root = logging.getLogger()
|
|||
|
|
root.handlers = [InterceptHandler()]
|
|||
|
|
root.setLevel(0)
|
|||
|
|
|
|||
|
|
for name in (
|
|||
|
|
"uvicorn",
|
|||
|
|
"uvicorn.error",
|
|||
|
|
"uvicorn.access",
|
|||
|
|
"sqlalchemy.engine",
|
|||
|
|
"celery",
|
|||
|
|
"celery.worker",
|
|||
|
|
):
|
|||
|
|
logging.getLogger(name).handlers = [InterceptHandler()]
|
|||
|
|
|
|||
|
|
logger.configure(extra={"request_id": "-"})
|
|||
|
|
|
|||
|
|
|
|||
|
|
def get_logger(name: str) -> logging.Logger:
|
|||
|
|
"""获取具名 logger,统一走 loguru 拦截。各模块应使用此函数而非直接 import logging。"""
|
|||
|
|
return logging.getLogger(name)
|