Skip to content

feat(logging): 插件与调试适配器接入结构化日志 v2 - #1699

Merged
xiaoyumuxi merged 4 commits into
previewfrom
codex/owned-plugin-logging
Nov 4, 2026
Merged

xiaoyumuxi merged 4 commits into
previewfrom
codex/owned-plugin-logging

Conversation

@xiaoyumuxi

@xiaoyumuxi xiaoyumuxi commented Nov 4, 2026 •

Copy link
Copy Markdown
Collaborator

概要

结构化日志 v2 的插件与调试适配器接入:Core 为官方插件进程新增独立的 litheLogging 1 协商和 lithe/log 通知,插件只能上报四种受控事实,由 Core 统一校验、脱敏并写入 plugins/<id>/host;LSP/插件/VCS 的上游消息按明确严重度拆成独立目录事件,未分类 stderr 降为 DEBUG;DAP 生命周期由 Core 记录;内置 Java Support 的 Equinox 原生日志改由宿主日志会话承接。

目标分支为 preview。这是跨仓库改动的第一步,SDK 和各插件仓库的配套 PR 依赖本 PR 合并后的 Core(见文末“合并顺序”)。

插件结构化诊断(logging protocol 1)

  • 新增 rust/lithe-core/src/lsp/interface/plugin_logging.rs:插件会话(plugin_owned)在 initialize 的 experimental 能力里声明 litheLogging: {"versions":[1]},插件回答 {"version":1} 后才启用;未协商的会话不接受 lithe/log。
  • lithe/log 只接受四种事实:operationFinished → INFO、operationFailed → ERROR、degraded → WARN、recovered → WARN;字段限定为 operation、durationMs、code、count、operationId,不接受自由文本。
  • 事实按已安装插件身份写入 plugins/<id>/host,对应新目录事件 plugins.operation.finished / failed / fallback_selected / recovery_finished。未协商或字段不合法的通知每会话只记一次 plugins.diagnostics.rejected WARN,不回显被拒内容;每会话每分钟最多 600 条,越限只计丢弃数(由宿主汇总为 log.dropped),不记 WARN。
  • 插件给出的仍在途 wire 请求号会映射回宿主的 op,日志窗口里插件事实和宿主请求属于同一调用链。
  • client.rs 在协商成功时把该能力写入 server_capabilities,engine.rs / engine_logging.rs 接入路由;core_events.rs 的 note_dropped 改为 pub(crate) 供限流计数复用。
  • 契约:shared/contracts/plugins/v1/README.md 新增“Structured plugin diagnostics (logging protocol 1)”一节,新增 fixture shared/contracts/plugins/v1/fixtures/plugin-logging.json;shared/contracts/rust-core-api.md、shared/logging/README.md 同步说明。

快捷键导入请求的诊断事实(286c0090d)

  • SDK rebase 到 typed shortcut import provider(lithe-plugin-docs [Bug] 设置界面语言切换不到英文 #15/[Feature] 希望尽快推出 Windows 版,另外支持一下 keymap 自定义 #16)后,会按线协议方法名 lithe/keymap/import 为快捷键导入请求上报终态事实。Core 的 known_operation 原先只认注册函数、SDK 自有阶段、lithe/build/* 和 lithe/vcs/*,会把它当作未注册 operation 拒收;现在白名单加入 keymap_provider::IMPORT_METHOD。
  • 插件契约 README 中 operation 字段的说明同步列出 lithe/keymap/import。
  • plugin_logging.rs 新增回归:lithe/build/model、lithe/vcs/status、lithe/keymap/import 在没有任何函数注册时也能通过校验。

评审 P2 修复:没有宿主活动时,Core 事实也会落盘

问题:Core 事实队列原先只在 MacLogStore 因宿主事件、flush 或退出而 drain 时被取走。插件 lithe/log 事实、析构和后台清理事实如果发生在宿主空闲时,会一直留在内存,既不写盘,也不推给日志窗口。

修复(不加轮询、不加第二个 writer):

  • rust/lithe-core/src/diagnostics/core_events.rs:队列旁新增一个唤醒回调槽位。drain 之后第一条事实或第一次丢弃计数触发一次回调,同一 drain 周期内的后续事实合并;drain() 在队列锁内清除请求标记,之后入队的事实一定再次触发。安装时已有待取事实立即回调。回调在持有槽位锁时同步执行,移除也取这把锁,移除返回后 Core 不再使用宿主 context。
  • rust/lithe-core/src/runtime/ffi.rs 新增 C ABI lithe_core_install_log_waker / lithe_core_remove_log_waker(只有 context 匹配时才移除,返回 1/0);同步 lithe_core.h、lithe_bridge.h、bridge.c(含 weak 回退)和 shared/contracts/rust-core-api.md。
  • MacLogStore.observeCoreFacts():回调只复用宿主事件已有的 100 ms 单次 drain 调度(已有调度时不重复安排),drain 本身仍在 writer 的串行队列上,不在 Core 线程。CoreLogWakeTarget 弱引用 store,不延长 writer 生命周期;finishSession 先停止接纳并移除回调,再做最后一次 drain;deinit 也会移除。
  • 只有 MacServiceContainer.makeApplicationLogWriter 创建的进程应用 writer 安装回调;测试和其他临时 MacLogStore 不安装,避免两个 writer 争抢同一个进程队列。
  • 文档:rust-core-api.md 说明唤醒语义和回调约束;结构化日志 Note 记录这一决策,以及被否方案(宿主定时轮询、每条事实回调或在回调里直接 drain)。
  • 测试:新增 Rust 集成测试 rust/lithe-core/tests/core_log_waker.rs(独立测试二进制,覆盖空队列不唤醒、突发合并、drain 后重新触发、非持有者不能移除、移除后不再回调、安装时已有事实立即回调);新增 Swift 测试 coreFactsReachDiskAndSubscribersWithoutHostActivity,在隔离子进程里只触发 Core 事实、不调用 emit/flush,验证事实写入磁盘并推送给订阅者。

CI 修复(本 PR 引入的失败)

  • MacLogStoreTests:本 PR 把未分类 stderr 降为 DEBUG 后,非诊断模式下 DEBUG 不落盘,原来用 stderr 事件做样本的保留、轮转和 Core 事实测试因此失败;样本改为仍为 WARN 的 lsp.message.warning.logged / vcs.message.warning.logged(coreFactsUseCatalogFieldsAndNativeFilesStayInsideTheSession 原来以 WARN 级别提交 vcs.stderr.received,与目录里的 DEBUG 不一致,被 Core 目录校验拒绝)。原有的隔离子进程逻辑抽成 runsInIsolatedCoreProcess,供新测试复用。
  • PluginSettingsTests:Java 插件 logLevel 默认值断言从 ALL 改为 WARNING;JVM 参数测试补 logDirectory(${logDir} 现在是必需输入),并断言 -Dosgi.logfile=/logs/jdt.log。
  • CI 中 GitModuleTests(386/477/3140 行)和 GitWorktreeAppearanceTests 的失败来自 GIT-07 统一 ChangeList 归属与提交范围 #1697 把 changelist 投影改成异步;分支已合入最新 preview,其中的 修复 ChangeList 工作树测试的异步投影 #1704 让这些测试等待投影完成,修复了这些失败。

LSP / 插件 / VCS 消息严重度

  • window/logMessage 和 window/showMessage 按上游明确的 type 选择独立目录事件:Error → *.message.error.logged|shown(ERROR)、Warning → *.message.warning.*(WARN)、Info 沿用原有 *.message.logged|shown(INFO)、Log 及未知类型 → *.message.detail.*(DEBUG),覆盖 lsp、plugins.host、vcs 三类会话。
  • 未分类 stderr(lsp.stderr.received、plugins.host.stderr.received、vcs.stderr.received)由 WARN 降为 DEBUG:stderr 不代表严重度,真实失败在失败边界用新增的 lsp.session.failed、plugins.host.session.failed、vcs.session.failed 记 ERROR。
  • 共享 fixture shared/fixtures/diagnostics/logging-v2.json 中 lsp.stderr.received 的归一化样例级别同步改为 DEBUG(否则严格目录校验会拒绝该样例)。

DAP 生命周期

  • rust/lithe-core/src/debug/engine.rs 在真实状态转换点记录 debug.process.started、debug.session.initialized、debug.session.finished(INFO),debug.session.state_changed、debug.operation.cancelled(DEBUG),debug.session.failed、debug.operation.failed、debug.transport.failed(ERROR),通道为 debug/<adapter>。程序输出和原始 stderr 仍只进调试控制台,不进日志。
  • macOS CoreDebugAdapterProtocolSession.swift 只补 Core 看不到的三处传输失败:进程启动失败(stage: process-start)、初始化超时(initialization-timeout)、非零退出且会话尚未失败(transport-exit,带 exitCode),都关联调试会话 ID。

Java Support 原生日志

  • Plugins/mac/Official/JavaSupport/plugin.json 增加 -Dosgi.logfile=${logDir}/jdt.log、-Declipse.log.include.commandline=false、-Declipse.log.size.max=1024、-Declipse.log.backup.max=2、-Declipse.log.level=WARNING:Equinox 日志写到宿主分配的日志会话目录(平台可写目录,不在 bundle),不记录启动命令行,1 MiB、两个备份。
  • JDT 默认 -Dlog.level 由 ALL 收紧为 WARNING(plugin.json 设置默认值与 rust/lithe-core/src/lsp/languages/jdt.rs 的 DEFAULT_LOG_LEVEL_ARGUMENT,测试同步)。OSGi 状态和索引不进入日志目录。

目录、文档与功能矩阵

  • shared/logging/events/{debug,lsp,plugins,vcs}.json 新增上述事件,重新生成 LogEvents.generated.swift 与 catalog_generated.rs(合并 修复 IDE 快捷键导入与终端切换 #1695 后共 241 条)。
  • Agent Notes:2026-11-03-structured-logging-channels.md 补严重度映射、“官方插件通过新的类型化协议交付事实”“DAP:记录状态与失败,保留程序内容边界”两节;2026-10-13-java-language-server-as-declarative-plugin.md 新增“原生日志属于宿主日志会话”;2026-10-14-declarative-plugin-settings.md 更新 JDT 默认级别。
  • 功能矩阵:diagnostics-export、java-support-plugin、lsp-status-logs、plugin-debug-adapters 补充实现文件与验证说明。

验证

在最新 preview(含 #1695)上 rebase 后本地完成:

  • cargo test --lib(workspace 全部):lithe-core 1683 项、lithe-agent-host 258 项(另 1 项既有 ignored)及其余 crate 全部通过;cargo fmt -p lithe-core -- --check 通过。
  • generate-log-events.mjs --check(241 条)、verify-log-usage.mjs(0 违规)、test-log-events.mjs。
  • verify-app-language-localization.mjs、generate-i18n.mjs --check。
  • verify-platform-feature-matrix.sh(234 项)与 verify-platform-feature-matrix-change.sh origin/preview HEAD。
  • verify-shared-contracts.sh、verify-rust-core-comments.sh、verify-agent-notes.sh(203 篇)、verify-windows-boundaries.sh、verify-runtime-bundle-immutability.sh。
  • 追加快捷键修复(286c0090d)后复验:cargo test -p lithe-core --lib 1683 项通过,cargo fmt -p lithe-core -- --check、verify-shared-contracts.sh、verify-rust-core-comments.sh 通过。
  • SDK 端到端:在 lithe-plugin-docs 运行 node scripts/sdk-e2e.mjs --source <本工作树> --ref codex/owned-plugin-logging(宿主 286c009),9/9 通过,含三种 SDK 的快捷键导入场景(此前 Codex 工作区的 6 项是在 SDK 加入快捷键导入场景之前跑的)。
  • 评审 P2 与 CI 修复(ff7b31722):本地 MacLogStoreTests + PluginSettingsTests 40 项全部通过(含新测试 coreFactsReachDiskAndSubscribersWithoutHostActivity);cargo test -p lithe-core --test core_log_waker 与 --lib core_events 通过;cargo fmt -p lithe-core -- --check、verify-rust-core-comments.sh、generate-log-events.mjs --check、verify-log-usage.mjs、i18n 两项检查、verify-shared-contracts.sh、verify-runtime-bundle-immutability.sh、verify-windows-boundaries.sh、verify-agent-notes.sh、verify-platform-feature-matrix.sh 通过。
  • 此前在 Codex 工作区:DAP 两项 Core 回归、JDT 参数幂等与默认值回归通过;LitheDebugModule 和生成日志类型在本机 Swift 6.4.2 编译通过。

限制与评审重点

  • 本机没有指定的 Swift 6.3.3,只用 6.4.2 编译过 macOS 改动,不能代替指定工具链验收;macOS 整机日志窗口、真实 JDT 日志文件生成与轮转、LLDB、Docker daemon 未做端到端验收。
  • Windows 仍是 v1 writer,本 PR 不宣称 Windows 已接入。
  • 本地 cargo fmt --all --check 会报 lithe-agent-host 的格式差异,该 crate 本 PR 未改动,差异在 preview 上已存在。
  • 建议重点看 plugin_logging.rs 的协商与校验边界(未协商拒收、限流、拒收只记一次、wire 请求号映射),以及 stderr 降级到 DEBUG 是否会让某些真实失败只剩 DEBUG(失败边界已补 *.session.failed)。

合并顺序(跨仓库)

  1. 本 PR(宿主 Core、目录、共享契约)合入 preview。
  2. 在 lithe-plugin-docs 运行 node scripts/contract.mjs sync --revision <本 PR 合并后的 preview commit> 同步 contract/v1,再合入 SDK PR。
  3. 合入各插件 PR:database、docker、cargo、svn 的集成测试要求所选 Core 具备 litheLogging 1,在本 PR 合并前这些插件的 CI 会按预期失败(cargo、svn 报 “Selected Core lacks litheLogging:1”);正式发布前把各插件 vendored SDK 固定到合并后的 SDK commit。
  4. 按插件发布流程发版本并更新 Store。

配套 PR:

- Core 为插件进程协商独立的 litheLogging 1,校验 lithe/log 的四种受控事实
  (finished/failed/degraded/recovered),按已安装插件身份写入
  plugins/<id>/host,并把仍在途的 wire 请求号映射回宿主 op
- LSP window/logMessage、window/showMessage 按上游明确类型选择独立目录事件;
  未分类 stderr 降为 DEBUG,真实失败在失败边界记 ERROR
- DAP 由 Core 在真实状态转换点记录生命周期、内部状态与失败;macOS 宿主只补
  进程启动失败、初始化超时和异常退出
- Java Support 用 ${logDir}/jdt.log 承接 Equinox 原生日志,限制体积与备份,
  关闭命令行记录,默认级别收紧为 WARNING
- 补齐插件契约、fixture、日志目录、Agent Note 与平台功能矩阵
@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 02:41
- Core 的 lithe/log 操作白名单加入 lithe/keymap/import,SDK 为快捷键导入
  上报的终态事实按线上方法名记录,不再被当作未注册操作拒绝
- 插件契约 README 的 operation 字段说明同步列出该方法
- 新增回归:build/vcs/keymap 请求方法无需函数注册即可通过校验
@lithe-code-review

lithe-code-review Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

Lithe Review

结论: ⚠️ 有建议
范围: preview ← codex/owned-plugin-logging · head: 4ab4c12

未发现需要阻塞合并的问题。

Findings

  1. [P2] 插件日志入队后需要触发宿主排空
    rust/lithe-core/src/lsp/interface/engine.rs:7728

    • 实际影响:合法插件事实可能长期不落盘、不出现在实时日志窗口;连续输入还能填满 256 条 Core 队列,导致后续 ERROR 被丢弃。
    • 触发条件:已有写入完成后,插件发送独立的 lithe/log 通知,期间没有其他宿主日志或显式刷新。此处只调用 core_events::record,没有通知写入器;MacLogStore.swift:108 仅在宿主 enqueue 时安排 drain,:286 才排空 Core 队列。LogWindowModel.swift:175 的实时订阅也不会主动排空。
    • 复现步骤:完成协商并打开日志窗口跟随,待现有批次结束;发送 {"kind":"degraded","operation":"notification","code":"retry_pending","count":1}。该记录要等无关日志或手动刷新才可见。将 count 依次改为 1~256,再发送一条合法 operationFailed,在没有 drain 的情况下失败记录会被队列丢弃,且尚未触及每分钟 600 条限额。
    • 来源:本次引入。新分支截获通知并仅写入 Core 队列,使常规插件日志依赖无关活动才能交付宿主。

Scope Check

  • 未找到可验证的关联 Issue;按 PR 所述目标审查。
  • 已检查插件协商与字段校验、请求关联、限流、LSP 严重度映射、DAP 记录、Java 参数,以及相关契约、fixture、Notes 和功能矩阵。
  • 变更复用现有 Core 日志边界与 Equinox 配置,没有发现新增并行领域模型。
  • Finding 属于本次日志接入的直接交付路径;跨仓库 SDK、契约同步和真实产品验收仍待完成。

Suggestions

  1. 在 Core 队列获得新事实时,通过合并的事件通知唤醒现有宿主写入器,继续保持有界批处理和单一 writer。补充无其他日志活动时的端到端回归,验证通知及时落盘、实时订阅收到记录,以及持续输入期间队列得到排空。

Summary

协议字段、身份来源和严重度边界总体清晰。主要缺口在从 Core 入队到宿主持久化之间的通知机制;现有 decoder 和目录测试不能覆盖这一交付问题。

Verification

  • 对指定 ced0422...4ab4c12 范围进行了静态审查,并追踪 Core 队列、MacLogStore 和日志窗口订阅。两个生成文件按机械生成内容处理,未审读正文。
  • 作者报告 Rust 测试、日志目录与用法检查、i18n、契约和 bundle 只读检查通过;所提供 Check Run 中 Structured Logging 已成功,主要 Rust、Swift、Windows 和打包检查仍有进行中或排队项。
  • 本次未运行代码、应用或测试,未访问网络;作者报告的本地结果未经独立复验。
  • Swift 6.3.3、真实 JDT 日志生成与轮转、macOS 日志窗口及真实适配器工作流尚有验证缺口;Windows v2 writer 不在本 PR 交付范围。

@lithe-code-review

Copy link
Copy Markdown

Lithe 运行验收

版本:286c0090ded36ece78d48ddaa1be5662ee13314c;状态:partial。
本报告独立于代码审查;只报告实际执行的场景,不代表所有问题均已修复。

对照:共同祖先 ced042289b5fbf9b6562eacd8da1f15428b5849d → PR head;当前目标分支合并适用性:未运行。

  • 条件不足,未验证:Negotiate and validate logging protocol 1; preserve trusted routing, privacy, correlation and bounds; map explicit LSP/plugin/VCS severity without treating ordinary stderr as failure.
    • The inventory supplies Cargo and rustc, but no native C compiler/linker or Windows SDK. lithe-core's pinned ring and tree-sitter dependencies require native compilation, and no revision-matched Core DLL is provided. These prerequisites cannot be assumed or installed automatically.
  • 条件不足,未验证:Record DAP lifecycle and failure facts with catalog severity and correlation, preserve cancellation semantics, and keep program output and raw stderr outside structured logs.
    • Requires a native Core build or revision-matched DLL. The required native C compiler/linker and Windows SDK are outside the supplied inventory.
  • 条件不足,未验证:Address the review comment's delivery concern: independently arriving plugin facts must reach the single writer and live log window without relying on unrelated host activity.
    • Requires macOS, the native MacLogStore integration and a desktop for the real log-window subscription workflow. Windows retains the v1 writer and cannot establish this behavior. Sustained-delivery or latency claims also need a prespecified timing/statistical protocol.

未覆盖:

  • No runtime requirement has executed coverage. The frozen baseline/head probe, repeated twice per revision, remains unavailable until native build prerequisites are supplied.
  • Java Support's real Equinox/JDT behavior: WARNING defaults and explicit overrides, writable logDir expansion, jdt.log creation, command-line exclusion, 1 MiB rotation with two backups, and separation of logs from OSGi state/indexes. Java is unavailable; the changed bundled plugin is macOS-specific.
  • macOS-only DAP transport failures: process-start failure, initialization timeout, and nonzero transport exit before an existing failure, including session correlation and duplicate suppression.
  • Actual installed plugin admission and identity provenance, official SDK interoperability, and real LLDB/Java/other debugger workflows. Deterministic protocol peers would establish only Core integration behavior.
  • The plugin budget's 60-second rollover requires a deterministic production clock seam or an explicitly bounded integration protocol. The PR body promises a rejection WARN for over-limit input, while the checked-in contract specifies dropped accounting; that acceptance expectation needs resolution.
  • Real macOS persistence, live subscription and queue-pressure behavior remain blocked, including the review finding. No statistical protocol is supplied for intermittent delivery or performance claims.
  • Runtime bundle/install-directory immutability, Windows/Tauri resource resolution, and preservation of Windows v1 writer behavior require separate native acceptance.
  • Cross-repository contract synchronization, three SDK end-to-end checks, companion plugin compatibility and release ordering are unverified and require additional checkouts/artifacts.
  • Catalog generation parity, shared fixtures/contracts, documentation, feature-matrix accuracy and repository validation gates were not executed; they are separate from runtime acceptance.

工作副本与运行状态已清理;可复用编译缓存按 12 GiB / 7 天预算保留。
详细步骤和原始证据保存在服务器受限目录(14 天、总计不超过 1 GiB);当前没有公开下载链接。

Core 事实队列原先只在宿主事件、flush 或退出时被排空,插件 lithe/log
事实和后台清理事实在宿主空闲时会一直留在内存,既不落盘也不推给日志窗口。

- Core 队列旁增加单一唤醒回调槽位:drain 后第一条事实或丢弃计数触发
  一次回调,同一周期内合并;drain 在队列锁内重新武装;安装时已有待取
  事实立即回调;移除返回后不再使用宿主 context。
- 新增 C ABI lithe_core_install_log_waker / lithe_core_remove_log_waker,
  同步头文件、桥接(含 weak 回退)与 rust-core-api 契约。
- MacLogStore.observeCoreFacts 只复用已有 100 ms 单次 drain 调度;仅进程
  应用 writer 安装,finishSession 先移除回调再做最后一次 drain。
- 结构化日志 Note 记录唤醒决策和被否方案。
- 测试:新增 Rust core_log_waker 集成测试与 Swift 无宿主活动落盘测试;
  stderr 降为 DEBUG 后改用仍为 WARN 的事件作样本;Java 插件测试改为
  WARNING 默认值并补 logDirectory、断言 -Dosgi.logfile。
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