Files
surugaya/app/core/logging_setup.py
T
2026-06-08 16:09:13 +08:00

83 lines
2.7 KiB
Python

"""日志配置:使用 loguru 替代标准 logging,统一管理日志输出
- 控制台输出:始终启用
- 文件输出:生产环境默认启用,支持日志轮转、压缩和保留策略
- 拦截标准 logging:将 uvicorn 等第三方库的日志转发到 loguru
"""
from __future__ import annotations
import logging
import sys
from pathlib import Path
from types import FrameType
from loguru import logger as loguru_logger
from app.core.config import Settings
class InterceptHandler(logging.Handler):
"""拦截标准 logging 日志,转发到 loguru"""
def emit(self, record: logging.LogRecord) -> None:
try:
level: str | int = loguru_logger.level(record.levelname).name
except ValueError:
level = record.levelno
frame: FrameType | None = logging.currentframe()
depth = 2
while frame and frame.f_code.co_filename == logging.__file__:
frame = frame.f_back
depth += 1
loguru_logger.opt(depth=depth, exception=record.exc_info).log(level, record.getMessage())
def configure_logging(settings: Settings) -> None:
"""根据配置初始化日志系统
- 移除 loguru 默认 handler
- 添加控制台输出
- 生产环境添加文件输出(轮转、压缩、保留策略)
- 拦截标准 logging,统一走 loguru 输出
"""
loguru_logger.remove()
loguru_logger.add(
sys.stdout,
level=settings.log_level.upper(),
format=settings.log_format,
enqueue=settings.log_enqueue,
backtrace=False,
diagnose=False,
)
if settings.log_to_file_effective:
log_dir = Path(settings.log_dir)
log_dir.mkdir(parents=True, exist_ok=True)
log_path = log_dir / f"app_{settings.app_env}.log"
loguru_logger.add(
str(log_path),
level=settings.log_level.upper(),
format=settings.log_format,
rotation=settings.log_rotation,
retention=settings.log_retention,
compression=settings.log_compression,
enqueue=settings.log_enqueue,
encoding="utf-8",
backtrace=False,
diagnose=False,
)
intercept = InterceptHandler()
logging.basicConfig(handlers=[intercept], level=getattr(logging, settings.log_level.upper(), logging.INFO), force=True)
# 将 uvicorn 的日志也转发到 loguru
for name in ("uvicorn", "uvicorn.error", "uvicorn.access"):
logger = logging.getLogger(name)
logger.handlers = [intercept]
logger.propagate = False
# 降低 asyncio 的日志级别,避免过多输出
logging.getLogger("asyncio").setLevel(logging.WARNING)