feat(T-003): 建立日志与运行产物目录策略
- src/paths.py: 集中管理 logs/、artifacts/ 路径与产物命名 (artifacts/<task_id>/<时间戳>_<step>.png|.xml),_safe 安全化防路径穿越, 运行时自动创建且被 .gitignore 忽略。 - src/logging_config.py: 统一日志格式(含 task_id/step),控制台 + logs/app.log, 缺上下文时由 filter 补默认值,setup 幂等;约定不记录敏感信息。 - src/main.py: 启动时初始化运行目录与日志。 - 运行方式统一为 python -m src.main(绝对导入下的唯一干净入口), 同步替换 00/03/05/current-state 文档命令与 dev.bat。 - 文档:04 §七 补 paths.py 与产物命名规则;tasks/progress/current-state 更新。 验证:compileall OK;unittest Ran 17 tests OK;python -m src.main exit=0,logs/app.log 写入正常。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
41bc666322
commit
b1e38ffd7a
@@ -0,0 +1,41 @@
|
||||
"""日志配置测试(T-003)。"""
|
||||
import logging
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from unittest import mock
|
||||
|
||||
from src import logging_config
|
||||
from src.logging_config import _FORMAT, _ContextDefaultsFilter, get_task_logger
|
||||
|
||||
|
||||
class LoggingTest(unittest.TestCase):
|
||||
def test_task_logger_carries_context(self):
|
||||
log = get_task_logger("T9", "pay")
|
||||
self.assertEqual(log.extra["task_id"], "T9")
|
||||
self.assertEqual(log.extra["step"], "pay")
|
||||
|
||||
def test_format_tolerates_missing_context(self):
|
||||
"""非任务日志(无 task_id/step)也能格式化,不抛 KeyError。"""
|
||||
record = logging.LogRecord("x", logging.INFO, __file__, 1, "msg", None, None)
|
||||
_ContextDefaultsFilter().filter(record)
|
||||
out = logging.Formatter(_FORMAT).format(record)
|
||||
self.assertIn("task=-", out)
|
||||
self.assertIn("step=-", out)
|
||||
|
||||
def test_setup_logging_idempotent(self):
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
with mock.patch.object(logging_config, "LOG_FILE", Path(tmp) / "app.log"):
|
||||
logging_config._configured = False
|
||||
logging.getLogger().handlers.clear()
|
||||
logging_config.setup_logging()
|
||||
first = len(logging.getLogger().handlers)
|
||||
logging_config.setup_logging() # 第二次应无操作
|
||||
self.assertEqual(len(logging.getLogger().handlers), first)
|
||||
# 还原全局 logging 状态,避免影响其它测试
|
||||
logging.getLogger().handlers.clear()
|
||||
logging_config._configured = False
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user