Skip to content

feat(logging): 记录 git 命令、Core 请求和用户动作的执行轨迹 - #1714

Merged
xiaoyumuxi merged 8 commits into
previewfrom
fix/git-command-logging
Nov 4, 2026
Merged

xiaoyumuxi merged 8 commits into
previewfrom
fix/git-command-logging

Conversation

@xiaoyumuxi

Copy link
Copy Markdown
Collaborator

背景

日志 v2 上线后,日志里看不到执行了哪些 git 命令,也看不到按钮背后实际调用了哪些 Core 接口,用户报告问题时无法从日志定位。本 PR 把执行轨迹拆成三层,用同一个 op 串起来:

层 事件 通道 级别
用户动作 app.action.performed app INFO
Core 请求 app.core.request.finished / .traced / .failed app/core INFO / DEBUG / WARN
Git 进程 vcs.git.command.finished / .traced / .failed vcs/git INFO / DEBUG / WARN

在日志窗口按 op 过滤,一次点击对应的请求和每个 git 进程(脱敏后的参数、退出码、耗时、stderr 尾部)就会排在一起。

Rust Core

  • 新增 git/command_trace.rs:本地和远程工作区共用的唯一执行点,每个 git 进程记一条终态。
    • 结果判定顺序:被取消 → 其他运行器错误算失败 → 退出 0 算成功 → exit_is_answer 列出的“回答型”退出码算成功(如 git diff --quiet 的 1)→ 来源不是用户的内部读取,非零退出交给调用方判断 → 其余算失败。
    • 只有用户来源的可见命令(走 execute_git、会显示在 Git 控制台的命令)记 INFO finished;内部读取和后台命令记 DEBUG traced;失败统一记 WARN failed。
    • format_arguments 是唯一允许把 argv 写进日志的格式化函数:提交信息替换成 <message>,含凭据或个人身份的 -c 值替换成 <redacted>,URL 用户信息和共享脱敏规则生效,超过 1 KiB 截断并加 …。
    • stderr 只取最后 16 KiB 中最后 8 行非空内容,逐行脱敏后用 | 连接,保留最新的 1 KiB。
    • 运行器错误另写 error / error_code / error_domain,不和进程 exit_code 混用。从不记录 stdout、stdin 和环境变量。
  • 新增 diagnostics/request_trace.rs:dispatcher 为每个请求记一条终态。
    • op 依次取 origin.operation、operationId、id 中第一个格式合法的值。
    • 来源依次取 origin.source(unknown 视为未提供)、gitExecution.source。
    • 请求期间用线程局部上下文把 {op, source} 传给它启动的 git 进程。
    • 只记录方法名、来源、耗时、payload 里的 operation 选择器、trigger、第一个绝对路径和是否远程,不记录其他 payload 内容。
    • core.ping、所有 diagnostics.*,以及按键、逐帧、轮询、监听类高频方法(is_hot 列表)不记录。
  • 协议:请求信封新增可选的 origin {source?, trigger?, operation?},只用于诊断,不改变命令行为;格式不合法的值从轨迹中省略,不会让请求失败。
  • DEBUG 门:新增 diagnostics.configureCoreEvents {debug, roots?},默认关闭。被门拒绝的 DEBUG 事实不入队、不计入 dropped,后台轨迹不会挤占 256 条队列里后续的 WARN/ERROR。
  • 排空:轨迹事实入队或 dropped 计数增加后,调用 preview feat(logging): 插件与调试适配器接入结构化日志 v2 #1699 新增的 Core 唤醒回调(wake()),由宿主合并调度一次排空,不加空闲轮询。本分支早先在响应信封里加的 coreEventsPending 标记,合并 preview 后已删除(见下文“合并 preview 时的调整”)。
  • git/history.rs、remote_history.rs、remote_process.rs、git/mod.rs 的进程执行路径接入 trace,并标明可见或内部。
  • 事件目录 shared/logging/events/app.json、vcs.json 新增上述事件,重新生成 Rust/Swift 目录代码;删除原来的 Swift 侧 git 生命周期事件。

macOS

  • 新增 LitheModuleAPI/Logging/UserActionTrace.swift:
    • UserAction / UserActionContext(TaskLocal)/ UserActionTrace.run/action:只记录最外层入口一次,嵌套入口既不重复记录,也不重新绑定。
    • detached / mainAsync 让脱离当前任务的工作继续带着这次动作。
  • RustCoreBridge:
    • RequestOrigin.resolve 根据当前动作生成 origin;动作开始超过 60 秒后,长期运行的工作只保留 op,不再声称来源是用户。
  • MacLogStore:只在详细诊断状态或通道根集合变化时调用 configureCoreEvents;失败时记一次 app.logging.diagnostics_failed,之后直到期望状态变化才重试。Core 轨迹事实的排空沿用 preview 的 observeCoreFacts() 唤醒回调。
  • 删除 MacGitLifecycleLog 及其测试:git 进程事实统一由 Core 记录。
    • GitService.failureReference 让失败提示引用同一 op 的 Core 失败轨迹:有进程以非零状态退出时引用 vcs.git.command.failed;没有这样的进程而请求失败时引用 app.core.request.failed;进程全部以 0 退出、只是操作结果报告失败时不返回引用,由调用方记录自己的终态。
    • 行为变化:以前 git 失败由宿主记 ERROR,现在是 Core 记 WARN 轨迹,提示里的“查看日志”定位到这条记录。
  • 接入用户动作追踪的入口:
    • 菜单(show-logs、open-project 等)。
    • 右键菜单和下拉菜单(menu:<i18n key slug>)。
    • 插件动作(plugin:<pluginID>/<actionID>)。
    • Git 操作(vcs.git.<method>)。
    • 工作区:
      • 打开:workspace.open。
      • 远程:workspace.remote.manage/.browse/.add/.remove/.test/.test.cancel/.locate/.save/.open/.folder.choose。
      • 克隆:workspace.clone。
      • 项目:workspace.project.create/.new/.switch/.open-recent。
      • 条目:workspace.item.trash/.refresh/.dependencies.refresh。
    • 工作台:workbench.run-start-or-restart 等。
    • 运行:run.*。
    • 构建:build.*。
    • 测试:tests.run/stop/debug/refresh。
    • 终端:terminal.new。
    • 通知里的按钮:用其动作 id,surface 为 .notification。
    • 动作 id 一律是目录 token,不使用本地化标题或用户内容。
  • GitExecutionJournal 移除重复的生命周期记录,GitExecutionContext 增加 traceOperationID。

文档

  • shared/contracts/rust-core-api.md:
    • 新增请求 origin。
    • 诊断命令表新增 drainCoreEvents 和 configureCoreEvents,并给出示例。
    • 新增 “Execution traces” 一节(触发条件、字段、脱敏、结果判定)。
    • macOS 排空节奏一段与 preview 的唤醒回调描述合并,补充 configureCoreEvents 只在状态变化时发送、失败也只报告一次。
  • 整体重写 .agents/notes/implemented/architecture/2026-11-03-structured-logging-channels.md。
  • 重写 develop-lithe Skill 的 references/logging.md 和 shared/logging/README.md 中对应章节:
    • 明确“可见命令”和“内部读取”的定义、级别规则。
    • 写明宿主与 Core 的失败边界和引用规则。
  • shared/platform-feature-matrix/features/diagnostics-export.json:证据路径原来指向已删除的 MacGitLifecycleLog.swift 及其测试,导致矩阵校验失败;改为指向 command_trace.rs、request_trace.rs、core_request_traces.rs、UserActionTrace.swift、CoreRequestTraceTests.swift、UserActionTraceTests.swift,并在验收说明里补充执行轨迹的检查方法。
  • Windows 仍使用日志 v1,本 PR 不迁移。

合并 preview 时的调整

分支用 merge(非 rebase)先后合并了三次 preview:第一次带入 #1704、#1708,第二次带入 #1699(插件日志 v2)和 #1700(日志窗口),第三次带入 #1711(AI 提交信息上下文),当前基于 preview e876453e2。

  • feat(logging): 插件与调试适配器接入结构化日志 v2 #1699 新增了 Core 日志唤醒回调(Rust install_waker/remove_waker,FFI lithe_core_install_log_waker,Swift MacLogStore.observeCoreFacts()),它覆盖所有来源的 Core 事实,作用和本分支的 coreEventsPending 信封标记重复。合并时删除了该标记的全部实现:
    • Rust:core_events::has_pending、dispatcher 的 encode 及其测试;record/note_dropped 改为调用 wake()。
    • Swift:RustCoreBridge.onCoreEventsPending、Envelope.coreEventsPending、MacServiceContainer 里的接线,以及和 preview 重名的 scheduleCoreDrain()。
    • CoreRequestTraceTests 改为由测试写入器调用 observeCoreFacts(),依靠唤醒回调排空。
    • 契约、shared/logging/README.md、Agent Note 和 develop-lithe 日志参考同步改为描述唤醒回调;信封标记写进 Agent Note 的被否方案。
  • Agent Note 和 shared/logging/README.md 的冲突按两边内容合并:保留 preview 新增的插件 litheLogging 协议、上游严重度映射和 DAP 章节,同时保留本分支的执行轨迹章节。
  • fix(git): 校验 AI 提交说明的完整上下文 #1711 新增的 git/commit_message_context.rs 通过 capture_git_with_options 执行 git,这条路径已经经过 command_trace,所以它启动的 git 进程同样会记录轨迹,不需要额外接入。
  • fix(git): 校验 AI 提交说明的完整上下文 #1711 合入的 ai/mod.rs、git/mod.rs、runtime/dispatcher.rs 有几处未按 rustfmt 格式化,导致 cargo fmt -p lithe-core --check 失败;单独提交一次 cargo fmt(只调整 use 顺序和换行,不改逻辑)。CI 目前不跑 fmt 检查,这里补上是为了本地门禁通过。

测试修复

  • MacLogStoreTests.collectionBudgetKeepsActiveChannelsBeforeOldRotations 和 LogWindowTests.realtimeWatermarkCapPauseAndReference 在本机负载高时失败,报 Caught error: Error Domain=NSCocoaErrorDomain Code=3072 "The operation was cancelled."。原因是两者都用真实 systemUptime 计算 MacLogStore 的 10 秒控制租约,而它们分别要读约 12 MB 的轮转文件、连续查询三批各 10000 条记录。现在给这两个测试注入固定的 diagnosticNow,期限不再取决于机器速度;生产代码的 10 秒期限和取消检查不变。

验证

以下结果都在合并最新 preview(e876453e2,包含 #1699、#1700、#1704、#1708、#1711)后重跑,并以最终提交为准。

Rust

  • cargo test -p lithe-core --lib:1719 通过,0 失败,0 忽略(包含 core_request_traces、command_trace、request_trace 等新测试)。
  • cargo test -p lithe-core --test core_log_waker:1 通过。
  • cargo fmt -p lithe-core --check:通过。
  • 编译剩下 3 条 warning,分别在 lithe-git-host/src/configuration.rs、lithe-core/src/network/mod.rs 和 lithe-core/src/lsp/interface/plugin_function.rs,这三个文件和 preview 完全相同,不是本 PR 引入的。

macOS(scripts/macos/test/test-macos.sh --no-parallel)

  • 过滤器 UserActionTrace|CoreRequestTrace|KeyboardShortcut|ContextMenu|Dropdown|MacLogStore|LogWindow|DiagnosticsWorkflow|DiagnosticsExportV2|RustLanguageServerLaunch|WorkbenchNotification|WorkbenchContributionHost|WorkbenchModuleUIRegistry|RunEntryPoint|PluginInstallationGuidancePresentation|PluginNative|DebugModuleCoordinator|CommitWorkflow|Git:
    • LitheTests:479 个测试、66 个 suite,478 通过、1 失败。需要设置 LITHE_RUN_GIT_EXECUTION_INTEGRATION=1(或 LITHE_VERIFY_IDEA_RESOURCES=1)的测试在这一轮按条件跳过,改由下面的桥接验证执行。
    • Git graph 性能基线:21 通过。两个需要 LITHE_RUN_GIT_COMPOSITOR_TESTS=1 的可见窗口测试按条件跳过。
    • LitheGitModuleTests:237 个测试、15 个 suite,全部通过。
  • 唯一的失败是 LogWindowReviewTests.serverTabShowsOneServerAndClearsOnlyThatServer(),在 LogWindowReviewTests.swift:56 报 Expectation failed: await loaded.waitUntilOpen()(2.1 秒后超时)。
  • scripts/rust-core/verify-rust-core-swift-bridge.sh --skip-build(即 CI 的 Rust Core Swift bridge 步骤):
    • C ABI 探针和链接符号检查通过。
    • test-git-execution.py 的 12 个 Git 执行集成用例全部通过,包括可见命令、内部查询静默、AskPass 和认证取消。
    • 设置 LITHE_RUN_GIT_EXECUTION_INTEGRATION=1 后,GitConsoleLifecycleBridgeTests、GitConsolePresentationBridgeTests、MacGitHubGitOperationsTests、MavenDependencyTreeBridgeTests 共 9 个测试、4 个 suite 全部通过。

仓库门禁(全部通过)

  • node scripts/logging/generate-log-events.mjs --check:242 个事件。
  • node scripts/logging/verify-log-usage.mjs:0 违规,0 永久例外。
  • node scripts/logging/test-log-events.mjs:15/15。
  • node scripts/i18n/verify-app-language-localization.mjs 和 node scripts/i18n/generate-i18n.mjs --check。
  • scripts/platform-feature-matrix/verify-platform-feature-matrix.sh:234 项能力。
  • test-platform-feature-matrix.mjs:4/4。
  • verify-platform-feature-matrix-change.sh origin/preview HEAD。
  • scripts/architecture/verify-shared-contracts.sh。
  • scripts/agent-notes/verify-agent-notes.sh:203 条 Agent Note。
  • scripts/rust-core/verify-rust-core-comments.sh。
  • write-stable-tests 的 verify-test-stability.sh。
  • scripts/macos/verify/verify-runtime-bundle-immutability.sh。

尚未完成

  • 整机操作验收:在真实应用里点击按钮,在日志窗口按 op 查看完整调用链。

日志 v2 之前看不到执行了哪些 git 命令,也看不到按钮背后调用了哪些 Core 接口,无法用日志定位问题。现在把执行轨迹拆成三层,用同一个 op 串起来:

- 用户动作:app.action.performed
- Core 请求:app.core.request.finished / traced / failed
- Git 进程:vcs.git.command.finished / traced / failed

Rust Core
- 新增 git/command_trace.rs,作为本地和远程 git 进程唯一的执行轨迹点:参数脱敏,stderr 尾部脱敏截断,不记录 stdout、stdin 和环境变量。用户可见的命令记 INFO,后台读取记 DEBUG,失败记 WARN。
- 新增 diagnostics/request_trace.rs:dispatcher 为每个请求记一条终态,高频方法不记录。
- 请求信封新增可选的 origin;新增 diagnostics.configureCoreEvents 作为 DEBUG 开关;有待取事实时,响应带 coreEventsPending。

macOS
- 新增 UserActionTrace:菜单、右键菜单、插件动作、Git、工作区、运行、构建、测试、终端和通知按钮这些入口各记录一次用户动作,并把 op 传给 Core。
- RustCoreBridge 生成 origin,收到 coreEventsPending 后按需排空;MacLogStore 合并排空调度,并同步 DEBUG 开关。
- 删除 MacGitLifecycleLog,git 进程事实统一由 Core 记录;失败提示引用同一 op 的 Core 失败轨迹。

文档
- 更新 rust-core-api 契约。
- 整体重写结构化日志 Agent Note、develop-lithe 日志参考页,以及 shared/logging README 的相关章节。
…gging

# Conflicts:
#	macos/Sources/Lithe/Views/Components/LitheContextMenu.swift
#	macos/Sources/LitheGitModule/Application/GitFeatureModel.swift
#	rust/lithe-core/src/git/mod.rs
#	shared/logging/events/vcs.json
preview 的 #1699 新增了 Core 日志唤醒回调(install_waker / observeCoreFacts),
它覆盖所有来源的 Core 事实,取代本分支在响应信封里加的 coreEventsPending 标记。
合并时删除该标记及其宿主接线:

- Rust:移除 core_events::has_pending、dispatcher 的 encode 及对应测试,
  record / note_dropped 改为调用 wake();保留 DEBUG 门和请求轨迹。
- Swift:移除 RustCoreBridge.onCoreEventsPending、Envelope.coreEventsPending、
  MacServiceContainer 的接线和重复的 scheduleCoreDrain();
  CoreRequestTraceTests 改为由测试写入器调用 observeCoreFacts()。
- 文档:rust-core-api 契约、shared/logging/README、Agent Note 和
  develop-lithe 日志参考改为描述唤醒回调,信封标记记为被否方案。
MacGitLifecycleLog 及其测试已删除,diagnostics-export 的证据路径仍指向它们,
平台功能矩阵校验因此失败。改为指向 command_trace、request_trace、
UserActionTrace 及对应测试,并在验收说明中补充执行轨迹的检查方法。
MacLogStoreTests.collectionBudgetKeepsActiveChannelsBeforeOldRotations 读取
约 12 MB 的轮转文件,LogWindowTests.realtimeWatermarkCapPauseAndReference
连续查询三批各 10000 条记录。两者都用真实 systemUptime 计算 10 秒控制租约,
本机负载高时超过期限,抛出 NSCocoaErrorDomain 3072(操作已取消)。

为这两个测试注入固定的 diagnosticNow,使租约期限不再取决于机器速度;
生产代码的 10 秒期限和取消检查不变。
preview 的 #1711 新增的 ai/mod.rs 导出、git/mod.rs 模块顺序和 dispatcher 分支
没有经过 rustfmt,cargo fmt -p lithe-core --check 因此失败。只做格式化,不改行为。
@ghfind-review ghfind-review Bot added the review: high ghfind author score; see https://ghfind.com label Nov 4, 2026
@xiaoyumuxi
xiaoyumuxi marked this pull request as ready for review November 4, 2026 05:30
@xiaoyumuxi
xiaoyumuxi merged commit 4a027b1 into preview Nov 4, 2026
21 of 31 checks passed
@xiaoyumuxi
xiaoyumuxi deleted the fix/git-command-logging branch November 9, 2026 05:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review: high ghfind author score; see https://ghfind.com

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant