优化支付耗时和日志

This commit is contained in:
yml2213
2026-08-12 23:20:43 +08:00
parent f1a22e87e9
commit 74a85c8328
5 changed files with 81 additions and 71 deletions
+36 -47
View File
@@ -1,33 +1,28 @@
"""日志配置模块"""
import os
import sys
import logging
from datetime import date
import re
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:
class _RelevantAccessFilter(logging.Filter):
"""仅保留异常 HTTP 请求,避免前端轮询淹没业务日志"""
_STATUS_RE = re.compile(r'"\s+(\d{3})\b')
def filter(self, record: logging.LogRecord) -> bool:
if record.levelno >= logging.WARNING:
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
matched = self._STATUS_RE.search(record.getMessage())
return bool(matched and int(matched.group(1)) >= 400)
def _configure_standard_logging(level: str, log_dir: Path) -> None:
""" Uvicorn/FastAPI 的标准日志同步到控制台和文件。"""
def _configure_standard_logging(level: str, log_dir: Path) -> logging.Logger:
"""业务日志和关键框架日志收敛到单一轮转文件。"""
log_level = getattr(logging, level.upper(), logging.INFO)
formatter = logging.Formatter(
"%(asctime)s | %(levelname)-8s | %(name)s | %(message)s"
@@ -38,17 +33,30 @@ def _configure_standard_logging(level: str, log_dir: Path) -> None:
console_handler.setFormatter(formatter)
file_handler = TimedRotatingFileHandler(
log_dir / "server.log", when="midnight", backupCount=7, encoding="utf-8"
log_dir / "app.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"):
app_logger = logging.getLogger("app")
app_logger.handlers.clear()
app_logger.handlers = [console_handler, file_handler]
app_logger.setLevel(log_level)
app_logger.propagate = False
for name in ("uvicorn", "uvicorn.error", "fastapi", "starlette"):
standard_logger = logging.getLogger(name)
standard_logger.handlers = [console_handler, file_handler]
standard_logger.setLevel(log_level)
standard_logger.propagate = False
access_logger = logging.getLogger("uvicorn.access")
access_logger.handlers = [console_handler, file_handler]
access_logger.filters = [_RelevantAccessFilter()]
access_logger.setLevel(logging.INFO)
access_logger.propagate = False
return app_logger
def setup_logger(level: str = "INFO", log_dir: str = None, log_file: str = None) -> None:
"""
@@ -56,45 +64,26 @@ def setup_logger(level: str = "INFO", log_dir: str = None, log_file: str = None)
Args:
level: 日志级别
log_dir: 日志目录路径(文件名按日期自动生成,如 app-2026-06-24.log
log_dir: 日志目录路径(写入 app.log,按日轮转
log_file: 日志文件路径(兼容旧接口,优先级低于 log_dir)
"""
# 移除默认handler
# 移除默认 handler,由标准 logging 统一处理控制台和文件输出。
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")
app_logger = _configure_standard_logging(level, dir_path)
elif log_file:
# 兼容旧接口
file_path = Path(log_file)
file_path.parent.mkdir(parents=True, exist_ok=True)
file_path = str(file_path)
app_logger = _configure_standard_logging(level, file_path.parent)
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",
)
def forward_to_standard(message) -> None:
record = message.record
app_logger.log(record["level"].no, f"{record['name']} | {record['message']}")
logger.add(forward_to_standard, level=level, format="{message}")