modify:日志命名问题
This commit is contained in:
@@ -43,6 +43,10 @@ UMask=0027
|
||||
# 每机可选覆盖(如 APP_WORKERS),文件不存在时忽略(- 前缀)
|
||||
EnvironmentFile=-/etc/chongming.env
|
||||
Environment=PYTHONUNBUFFERED=1
|
||||
# ffmpeg 位于非标准路径(AI Box 的 sophon-ffmpeg):覆盖默认 PATH 才能被
|
||||
# shutil.which / create_subprocess_exec 找到(RTSP 拉流依赖);若 ffmpeg 还依赖
|
||||
# 私有动态库,再补一条 Environment=LD_LIBRARY_PATH=/opt/sophon/sophon-ffmpeg-latest/lib
|
||||
Environment=PATH=/opt/sophon/sophon-ffmpeg-latest/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
|
||||
# 优雅停机:SIGTERM 由 gunicorn 排空 worker,等在途请求/告警上传完成
|
||||
KillSignal=SIGTERM
|
||||
|
||||
@@ -67,6 +67,80 @@ class ColoredFormatter(logging.Formatter):
|
||||
return result
|
||||
|
||||
|
||||
class DailyRotatingFileHandler(RotatingFileHandler):
|
||||
"""
|
||||
按自然日切分 + 大小轮转的文件处理器
|
||||
|
||||
日志文件名形如 {log_name}-2026-08-19.log:进程启动时按当天日期命名,
|
||||
跨天后写入时自动切换到新日期文件,避免长时间运行的进程把跨天日志
|
||||
全部堆积到启动当天的文件里。同时保留 RotatingFileHandler 的大小轮转
|
||||
(单文件超限追加 .1/.2 后缀)。
|
||||
|
||||
历史文件(跨天文件与大小备份)按修改时间保留最近 backup_count 个,
|
||||
超出部分在切换日期的瞬间清理。
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
log_dir: str,
|
||||
log_name: str,
|
||||
max_bytes: int,
|
||||
backup_count: int,
|
||||
encoding: str = "utf-8",
|
||||
):
|
||||
self.log_dir = Path(log_dir)
|
||||
self.log_name = log_name
|
||||
self._current_date = datetime.date.today()
|
||||
super().__init__(
|
||||
str(self.log_dir / f"{log_name}-{self._current_date}.log"),
|
||||
encoding=encoding,
|
||||
maxBytes=max_bytes,
|
||||
backupCount=backup_count,
|
||||
)
|
||||
|
||||
def _build_filename(self, day: datetime.date) -> str:
|
||||
return str(self.log_dir / f"{self.log_name}-{day}.log")
|
||||
|
||||
def _cleanup_old_files(self) -> None:
|
||||
"""保留最近 backup_count 个日志文件,删除更早的历史文件"""
|
||||
# 按 (日期, 轮转序号) 排序,不依赖 mtime(同日备份可能同时落盘):
|
||||
# 日期越大越新;同日内主文件(.log)最新,.N 备份按 N 递减更旧
|
||||
pattern = re.compile(
|
||||
rf"^{re.escape(self.log_name)}-(\d{{4}}-\d{{2}}-\d{{2}})\.log(?:\.(\d+))?$"
|
||||
)
|
||||
|
||||
def sort_key(path: Path):
|
||||
match = pattern.match(path.name)
|
||||
if not match:
|
||||
return (datetime.date.min, 0)
|
||||
return (
|
||||
datetime.date.fromisoformat(match.group(1)),
|
||||
-int(match.group(2) or 0),
|
||||
)
|
||||
|
||||
files = sorted(
|
||||
self.log_dir.glob(f"{self.log_name}-*.log*"),
|
||||
key=sort_key,
|
||||
reverse=True,
|
||||
)
|
||||
for old in files[self.backupCount :]:
|
||||
try:
|
||||
old.unlink()
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def emit(self, record):
|
||||
# 跨天:关闭旧文件流,切换到新日期文件,并清理过期历史文件
|
||||
today = datetime.date.today()
|
||||
if today != self._current_date:
|
||||
self._current_date = today
|
||||
self.close()
|
||||
self.baseFilename = self._build_filename(today)
|
||||
self.stream = self._open()
|
||||
self._cleanup_old_files()
|
||||
super().emit(record)
|
||||
|
||||
|
||||
class ExcludeWatchFilesFilter(logging.Filter):
|
||||
"""
|
||||
日志过滤器,用于排除第三方库的日志输出
|
||||
@@ -112,7 +186,7 @@ def setup_logging(logger: logging.Logger, log_name: str = "app"):
|
||||
|
||||
为指定的 logger 配置以下功能:
|
||||
1. 设置日志级别和格式
|
||||
2. 创建按日期命名的轮转文件处理器(支持文件大小限制和备份数量控制)
|
||||
2. 创建按自然日切分的轮转文件处理器(跨天自动切换文件,支持文件大小限制和备份数量控制)
|
||||
3. 创建带颜色格式化的控制台处理器
|
||||
4. 应用过滤器排除第三方库日志
|
||||
|
||||
@@ -145,15 +219,15 @@ def setup_logging(logger: logging.Logger, log_name: str = "app"):
|
||||
plain_formatter = logging.Formatter(log_format)
|
||||
color_formatter = ColoredFormatter(log_format)
|
||||
|
||||
# 创建轮转文件处理器 - 限制文件大小为 10MB,保留 5 个备份文件
|
||||
# 创建按自然日切分的轮转文件处理器(跨天自动切文件,单文件超限再按大小轮转)
|
||||
max_bytes = log_config.get("max_size", 10 * 1024 * 1024) # 默认 10MB
|
||||
backup_count = log_config.get("backup_count", 5) # 默认保留 5 个备份
|
||||
backup_count = log_config.get("backup_count", 5) # 默认保留 5 个历史文件
|
||||
|
||||
file_handler = RotatingFileHandler(
|
||||
f"{log_config['file']}/{log_name}-{datetime.date.today()}.log",
|
||||
encoding="utf-8",
|
||||
maxBytes=max_bytes,
|
||||
backupCount=backup_count,
|
||||
file_handler = DailyRotatingFileHandler(
|
||||
log_config["file"],
|
||||
log_name,
|
||||
max_bytes=max_bytes,
|
||||
backup_count=backup_count,
|
||||
)
|
||||
file_handler.setFormatter(plain_formatter)
|
||||
file_handler.addFilter(ExcludeWatchFilesFilter())
|
||||
|
||||
Reference in New Issue
Block a user