Files
xwlb/tests/test_logrotate.py
T
simon c67a4ce367 feat: 日志轮转(保留 14 天)
main.log 无轮转、已涨到 34MB,且每晚任务都会继续追加。

- logrotate/xwlb 模板 + scripts/install_logrotate.sh(幂等,装到 /etc/logrotate.d/xwlb)
- 每天轮转、保留 14 份、立即压缩 → main.log-YYYYMMDD.gz
- 必须用 copytruncate:脚本以 >>main.log 长开句柄,改名式轮转会
  让当晚日志写进归档、新文件空着
- journald 同步设 MaxRetentionSec=14day + SystemMaxUse=500M
- 安装脚本自带 logrotate -d 校验(这条立刻抓到"指令行尾注释"被当成参数值的错误)
- tests/test_logrotate.py 19 项,锁住保留天数、行尾注释、占位符替换

实测:34MB → 2.9MB,归档 32453 行与轮转前完全一致
2026-09-25 12:49:53 +08:00

86 lines
3.1 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.
"""日志轮转配置回归测试(不依赖 pytest,不需要 root)
python tests/test_logrotate.py
覆盖:
- 保留 14 天等关键指令齐全;
- **指令后面不能有行尾注释**(logrotate 会把注释当成参数值,
实测报错 `bad rotation count '14 # 保留 14 份'`,这条就是那次踩坑的回归);
- 占位符齐全,且安装脚本确实会替换(否则装过去的路径是字面量 @PROJECT_DIR@);
- 若本机已安装,装好的文件里不应残留占位符。
"""
import re
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
CONF = ROOT / 'logrotate' / 'xwlb'
INSTALLER = ROOT / 'scripts' / 'install_logrotate.sh'
INSTALLED = Path('/etc/logrotate.d/xwlb')
def directives(text):
"""取配置块里的指令行(去注释、去空行、去大括号)"""
out = []
for raw in text.splitlines():
line = raw.strip()
if not line or line.startswith('#') or line in ('{', '}'):
continue
out.append(line)
return out
def main():
failed = 0
def check(desc, got, want):
nonlocal failed
if got == want:
print(f" ✓ {desc}: {got!r}")
else:
failed += 1
print(f" ✗ {desc}: 期望 {want!r},实际 {got!r}")
print("配置文件:")
check('模板存在', CONF.exists(), True)
text = CONF.read_text(encoding='utf-8')
lines = directives(text)
def has_directive(name):
return any(re.match(rf'^{name}(\s|$)', ln) for ln in lines)
for d in ('daily', 'rotate', 'missingok', 'notifempty', 'compress',
'copytruncate', 'dateext', 'dateformat', 'su'):
check(f'含指令 {d}', has_directive(d), True)
print("\n保留天数:")
rotate = [ln for ln in lines if ln.startswith('rotate')][0]
check('rotate 值为 14(保留 14 天)', int(rotate.split()[1]), 14)
print("\n行尾注释(logrotate 会把注释吃成参数值):")
bad = [ln for ln in lines if '#' in ln]
check('指令行无行尾注释', bad, [])
print("\n占位符与安装替换:")
check('含路径占位符 @PROJECT_DIR@', '@PROJECT_DIR@' in text, True)
check('含属主占位符 @OWNER@', '@OWNER@' in text, True)
installer = INSTALLER.read_text(encoding='utf-8')
check('安装脚本会替换路径占位符', 's#@PROJECT_DIR@#' in installer, True)
check('安装脚本会替换属主占位符', 's#@OWNER@#' in installer, True)
check('安装脚本会做语法校验(logrotate -d)', 'logrotate -d' in installer, True)
print("\n已安装文件(若本机装过):")
if INSTALLED.exists():
installed = INSTALLED.read_text(encoding='utf-8')
check('无残留占位符', [p for p in ('@PROJECT_DIR@', '@OWNER@', '@GROUP@')
if p in installed], [])
check('已指向真实项目路径', str(ROOT) in installed, True)
else:
print(" · 本机未安装,跳过(未运行 scripts/install_logrotate.sh)")
print(f"\n结果: {'全部通过' if failed == 0 else f'{failed} 项失败'}")
return 1 if failed else 0
if __name__ == '__main__':
sys.exit(main())