feat. 注入上下文完整记录到日志 - #1
Conversation
59ca43f to
d537c97
Compare
|
PR: feat. 注入上下文完整记录到日志 by @ColumbinaXn 🔴 Blocking(必须修复)
if not prefix or not isinstance(prefix, str):
reset_stdout() 在 main() 开头就打开文件,但后续有 7+ 个 return 早退点(tool_name 不匹配、file_path 空、config 缺失、非代码文件、无 domains、无 matched、无 selected)。这些路径都不会执行 正确做法:atexit.register(cleanup_none_logfile) 或 try/finally。
os.makedirs(LOG_ROOT, exist_ok=True) # 模块顶层执行
PreToolUse 对每次 Edit/Write/MultiEdit 触发。原实现纯内存处理;现在每次都 open(w)、write、可能 cleanup。在密集编辑场景下,是显著的 disk IO 回归。且 LogTee.close() 从未被调用,文件句柄泄漏。 🟡 Major(强烈建议修复)
%Y%m%d_%H%M%S 无毫秒/微秒。同一 session 同秒两次 Hook → 同名文件 → 后者 w 模式覆盖前者日志。应加 %f 或序列号。
Python 标准警告:包装 sys.stdout.buffer 后 wrapper 被 GC 时会尝试关闭底层 buffer,导致后续写 stdout 失败。正确做法是 sys.stdout.reconfigure(encoding="utf-8")(Py3.7+)。
except Exception as e:
若未来有人下掉日志逻辑但保留 ensure_ascii=False,在非 UTF-8 控制台(Windows cp1252)下会 UnicodeEncodeError 破坏 Hook 协议。建议在 assemble_context 或 cf_core 统一处理编码,而不是隐式耦合。
日志落盘的是完整 JSON payload,其中含所有注入的 spec 文件内容。用户 spec 若含内部架构/凭据指引,将持久化到磁盘。至少应:(a) 添加到 .gitignore;(b) README 声明;(c) 提供关闭开关(如 CF_LOG=1 🟢 Minor
建议重构方向(KISS) 70 行自造 LogTee 完全可用 stdlib 替代: import logging, logging.handlers
修复 Checklist(给 PR 作者)
|
6313850 to
9cc50dc
Compare
…eature_53309 # Conflicts: # .code-flow/config.yml # src/core/code-flow/config.yml
af58c5a to
3f00e65
Compare
3f00e65 to
3441671
Compare
|
⏺ PR 代码审查:feat. 注入上下文完整记录到日志 PR: #1 🔴 Blocking Issues
def init_log_path(self, prefix: str | None) -> str: 问题:LOG_ROOT 是文件路径而非目录,os.path.dirname(LOG_ROOT) 得到上一级目录路径是对的。但 if not prefix 分支直接用 log_file_name 而不是 prefix,与注释逻辑相反。当 prefix=None 时走 if 分支,结果是 实际上,代码写的是 os.makedirs(os.path.dirname(log_path), exist_ok=True),而 log_path 是文件路径,所以 dirname(log_path) 是目录,这没问题。真正的问题是:当 prefix=None 时,日志文件直接放在 但 LOG_ROOT = os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(file)), "../logs")),这实际上是个目录而非文件路径。所以 os.path.dirname(LOG_ROOT) 会得到 ../,这有问题。 正确的实现应该是: 而不是 os.makedirs(os.path.dirname(log_path), exist_ok=True)。
Enable logging if configured (default off)if inject_config.get("log") is True: ... 后面多个 early return ...if not isinstance(file_path, str) or not file_path: if not config: StdoutLogTee 在 atexit 注册了 close(),但如果进程在 close() 被调用前就通过 early return 退出,日志文件会被留下(虽然 close() 会删除空文件,但前提是文件被写入过)。 修复:在 early return 前检查是否需要 cleanup: 或者更好的方案是:使用 Python 标准库 logging + RotatingFileHandler,完全避免 sys.stdout 替换。 🟡 Design Issues
用 sys.stdout = tee 替换全局 stdout 会影响所有后续输出,任何未捕获的异常或提前退出都会导致日志不完整。 建议:使用 logging 模块 + RotatingFileHandler,通过环境变量 CF_LOG=1 启用,这样更符合 Python 惯例: if os.getenv("CF_LOG") == "1":
当前实现为每个 session 创建新的日志文件,每次注入都打开/写入/flush。若高频调用会有 I/O 开销。 建议:除非 CF_LOG=1,否则不记录日志。默认只记录错误到 stderr。
当前创建在 .code-flow/scripts/cf_log.py 和 src/core/code-flow/scripts/cf_log.py。如果需要跨项目复用,考虑放到独立模块;否则放在项目内合理。 🟢 Minor Issues
cf_log.py 的 write 方法返回 int,但 StdoutLogTee.write 返回 int,而标准 sys.stdout.write 返回 None。这会导致类型不匹配。
新模块 cf_log.py 需要测试用例覆盖:
📋 Summary ┌────────┬────────────────────────────────────┬─────────────┐ 建议:采用 Python logging 标准库替代当前实现,修复 LOG_ROOT 路径问题,并添加单元测试。 |
b2aaade to
c8bb9e3
Compare
c8bb9e3 to
bff2aed
Compare
No description provided.