feat(logging): 日志持久化落盘(LOG_FILE 滚动文件)

- LOG_FILE 配置: 空(默认)保持 stdout + Admin 内存日志页(重启清零);
  填路径后额外写 RotatingFileHandler(单文件 10MB × 5 份,utf-8)
- setup_logging 幂等挂载(按 abspath 判重,相对/绝对同文件算一个);
  目录自动创建;文件基础设施失败只 warning 绝不拖垮启动
- docker-compose: api 挂 applogs 卷,默认 LOG_FILE=/app/logs/app.log,
  容器重建日志不丢;.env.example/.gitignore/docs 同步
- tests/test_log_persistence.py: 落盘/幂等/空值禁用/自动建目录/失败降级
- test_p0_standings_cutoff: 匿名约束 name=None 使 any() 子串匹配 TypeError
  (集合顺序不定 → flaky),先判真值再匹配(存量缺陷顺手加固)
This commit is contained in:
WorkBuddy
2026-09-22 12:18:03 +08:00
parent 8fef411ced
commit f0c1cc1491
11 changed files with 195 additions and 13 deletions
+3 -1
View File
@@ -73,7 +73,9 @@ class TestStandingsModel:
def test_unique_constraint_includes_available_at(self):
names = {c.name for c in Standing.__table__.constraints}
assert any("available" in n and n.startswith("uq_") for n in names), \
# 匿名约束(PK/Check)的 name 是 None,必须先判真值再子串匹配,
# 否则 any() 撞上 None 直接 TypeError(集合顺序不定 → flaky)
assert any(n and "available" in n and n.startswith("uq_") for n in names), \
f"缺少含 available_at 的唯一约束,现有: {names}"
def test_old_unique_constraint_removed(self):