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
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