chore: auto release commit (2026-09-15 00:32:44)
All checks were successful
技能自动化发布 / release (push) Successful in 7s

This commit is contained in:
2026-09-15 00:32:44 +08:00
parent 693a5e4a53
commit 293b7d1591
15 changed files with 1715 additions and 16 deletions

View File

@@ -0,0 +1,86 @@
"""读取日志文件末尾 N 行(v1.1.18)。
按 level 过滤:默认 INFO+。适用于 RotatingFileHandler 落地的日志文件。
"""
from __future__ import annotations
import os
from pathlib import Path
from util.runtime_paths import get_logs_dir
DEFAULT_TAIL = 200
_LEVEL_ORDER = {
"DEBUG": 10, "INFO": 20, "WARNING": 30, "ERROR": 40, "CRITICAL": 50,
}
def _resolve_log_path() -> Path:
"""解析日志文件路径。
优先级:
1. LOG_FILE env(绝对路径直接用,相对路径走 get_logs_dir())
2. 默认 get_logs_dir() / LOG_FILE_DEFAULT_NAME
"""
raw = os.environ.get("LOG_FILE", "")
if raw:
p = Path(raw)
if not p.is_absolute():
p = get_logs_dir() / raw
return p
from util.constants import LOG_FILE_DEFAULT_NAME
return get_logs_dir() / LOG_FILE_DEFAULT_NAME
def tail_log_file(tail: int = DEFAULT_TAIL, min_level: str = "INFO") -> dict:
"""读日志文件末尾 tail 行,过滤 level >= min_level。
Returns:
{
"log_file": str,
"exists": bool,
"total_lines": int,
"returned_lines": int,
"lines": [str, ...],
"min_level": str,
}
"""
log_path = _resolve_log_path()
if not log_path.exists():
return {
"log_file": str(log_path),
"exists": False,
"total_lines": 0,
"returned_lines": 0,
"lines": [],
"min_level": min_level,
}
text = log_path.read_text(encoding="utf-8", errors="replace")
all_lines = text.splitlines()
last_n = all_lines[-tail:] if tail > 0 else all_lines
threshold = _LEVEL_ORDER.get(min_level.upper(), 20)
filtered: list[str] = []
for line in last_n:
# 格式: "2026-09-15 12:34:56 [alert-contract-expiring-hr] INFO message"
# 取第 4 个 token (INFO/DEBUG/...)
parts = line.split()
if len(parts) >= 4 and parts[1].count(":") >= 2 and parts[3] in _LEVEL_ORDER:
line_level = parts[3]
if _LEVEL_ORDER.get(line_level, 0) >= threshold:
filtered.append(line)
else:
# 非标准行 / 解析不到 level:保留
filtered.append(line)
return {
"log_file": str(log_path),
"exists": True,
"total_lines": len(all_lines),
"returned_lines": len(filtered),
"lines": filtered,
"min_level": min_level,
}