Files
live-hub-py/utils/logger.py
T

101 lines
3.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""日志配置模块"""
import os
import sys
import logging
from datetime import date
from logging.handlers import TimedRotatingFileHandler
from pathlib import Path
from loguru import logger
def _should_rotate(message, file):
"""自定义轮转条件:每天0点轮转,或单文件超过10M。"""
if not file:
return False
try:
# 单文件超过 10M 则轮转
if os.path.getsize(file.name) > 10 * 1024 * 1024:
return True
# 跨天则轮转:日志日期 ≠ 文件最后修改日期
file_date = date.fromtimestamp(os.path.getmtime(file.name))
log_date = message.record["time"].date()
return file_date != log_date
except OSError:
return False
def _configure_standard_logging(level: str, log_dir: Path) -> None:
"""将 Uvicorn/FastAPI 的标准日志同步到控制台和文件。"""
log_level = getattr(logging, level.upper(), logging.INFO)
formatter = logging.Formatter(
"%(asctime)s | %(levelname)-8s | %(name)s | %(message)s"
)
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setLevel(log_level)
console_handler.setFormatter(formatter)
file_handler = TimedRotatingFileHandler(
log_dir / "server.log", when="midnight", backupCount=7, encoding="utf-8"
)
file_handler.setLevel(log_level)
file_handler.setFormatter(formatter)
for name in ("uvicorn", "uvicorn.error", "uvicorn.access", "fastapi", "starlette"):
standard_logger = logging.getLogger(name)
standard_logger.handlers = [console_handler, file_handler]
standard_logger.setLevel(log_level)
standard_logger.propagate = False
def setup_logger(level: str = "INFO", log_dir: str = None, log_file: str = None) -> None:
"""
配置日志
Args:
level: 日志级别
log_dir: 日志目录路径(文件名按日期自动生成,如 app-2026-06-24.log
log_file: 日志文件路径(兼容旧接口,优先级低于 log_dir)
"""
# 移除默认handler
logger.remove()
# 控制台输出
logger.add(
sys.stdout,
level=level,
format="<green>{time:YYYY-MM-DD HH:mm:ss}</green> | "
"<level>{level: <8}</level> | "
"<cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> | "
"<level>{message}</level>",
colorize=True,
)
# 确定日志文件路径
if log_dir:
# 新接口:按目录 + 日期命名
dir_path = Path(log_dir)
dir_path.mkdir(parents=True, exist_ok=True)
_configure_standard_logging(level, dir_path)
file_path = str(dir_path / "app-{time:YYYY-MM-DD}.log")
elif log_file:
# 兼容旧接口
file_path = Path(log_file)
file_path.parent.mkdir(parents=True, exist_ok=True)
file_path = str(file_path)
else:
return
# 文件输出:按天命名 + 单文件最大10M轮转 + 保留7天
logger.add(
file_path,
level=level,
format="{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {name}:{function}:{line} | {message}",
rotation=_should_rotate, # 超过10M轮转
retention="7 days", # 保留7天
compression="zip", # 旧日志自动压缩节省空间
encoding="utf-8",
)