← Back to PRs

#12475: fix(logging): use Symbol.for for externalTransports to survive jiti module isolation

by Yida-Dev open 2026-02-09 08:59 View on GitHub →
stale
## Summary Fixes #12473 Plugins loaded via jiti get their own module cache, so the module-level `externalTransports` Set in `logger.ts` becomes a **separate instance** in the plugin context. Any transport registered by a plugin via `registerLogTransport()` is silently lost when `buildLogger()` iterates the main process's Set. ### Root cause ``` Main process: import logger.ts -> externalTransports = new Set() (A) Plugin (jiti): import logger.ts -> externalTransports = new Set() (B) Plugin calls registerLogTransport(fn) -> adds to Set B buildLogger() iterates Set A -> fn is missing ``` ### Fix Store the Set on `globalThis[Symbol.for("openclaw.logging.externalTransports")]` so all module instances -- regardless of how they were loaded -- share the same collection. This matches the pattern already established in: - `src/infra/warning-filter.ts` (`Symbol.for("openclaw.warning-filter")`) - `src/plugins/runtime.ts` (`Symbol.for("openclaw.pluginRegistryState")`) ### Files changed | File | Change | |------|--------| | `src/logging/logger.ts` | Replace `new Set()` with `globalThis[Symbol.for()]` getter | | `src/logging/logger-transport.test.ts` | Verify shared Set and register/unregister lifecycle | ## Test plan - [x] New test: `externalTransports` is stored on `globalThis` via `Symbol.for` - [x] New test: `registerLogTransport` adds to and removes from the shared global Set - [x] All 27 existing logging + diagnostics-otel tests pass <!-- greptile_comment --> <h2>Greptile Overview</h2> <h3>Greptile Summary</h3> This PR changes `src/logging/logger.ts` to store the `externalTransports` Set on `globalThis[Symbol.for("openclaw.logging.externalTransports")]` so transports registered from jiti-loaded plugin module instances are visible to the main process logger builder. It also adds `src/logging/logger-transport.test.ts` to validate that the Set is shared via `Symbol.for` and that `registerLogTransport()` mutates the shared Set (including unregister cleanup). <h3>Confidence Score: 4/5</h3> - Mostly safe to merge, but the newly added tests are order-dependent and can fail in isolation/sharded runs. - The production change in logger.ts is small and follows established patterns (Symbol.for + globalThis). The only clear issues found are in the new test file, which assumes logger.js has already been executed and dereferences the global Set before ensuring initialization. - src/logging/logger-transport.test.ts <!-- greptile_other_comments_section --> <!-- /greptile_comment -->

Most Similar PRs