feat: pluggable per-instance logger via WechatyOptions - #120
Merged
Conversation
Pick up the schema additions for the optional `callId` field on call events. No business code change in this repo — downstream consumers need the new puppet types to consume callId end-to-end.
- Add a local LoggerLike alias (temporary stub for the field wechaty-puppet is publishing in parallel). - Add optional logger?: LoggerLike to WechatyOptions. - In puppet-mixin.init(), forward WechatyOptions.logger down into PuppetOptions.logger before resolvePuppet, so a caller-supplied logger reaches the puppet layer through the same code path as the rest of puppet options.
- WechatySkeleton grows a mutable __log (LoggerLike, initialised to brolog) backing a public readonly `log` getter. Static log stays bound to brolog for pre-instance callers. - puppet-mixin adopts the puppet's own `log` onto __log right after resolvePuppet succeeds — with a permissive access shape so this compiles against puppet versions before they publish puppet.log. - wechatifyMixin adds static + instance `log` getters that delegate to `this.wechaty.log` with a try/catch fall back to brolog. That gives every wechatified user module (Contact/Message/Room/...) a `log` handle without touching each file individually.
Route Wechaty's own and every user module's per-instance log calls
through `this.log` so they follow the caller-supplied logger set up
in the previous two commits. Static factories / classmethods keep
using the module-imported brolog `log`, and pre-`super()` calls
inside constructors do too (no `this` yet).
Also widen the local LoggerLike shape from brolog's strict
`Loggable` (2 required args) to a Brolog-class-compatible interface
(1 required arg, ...rest). The rest of the codebase has historically
relied on single-arg calls like `log.warn('unknown payload type ' + x)`;
the strict shape would surface these as fresh type errors under
`this.log` even though they were valid against the concrete Brolog
class the puppet re-exports.
wechaty-puppet 1.0.147+ exports `LoggerLike` and ships `log` on the Puppet base with a typed `options.logger` field, so wechaty can re-export the type directly and use `LoggerLike` in the adopt cast instead of `typeof log`. Comments updated to reflect that the cast persists because `PuppetInterface` hides `log`, not because of backward compat.
Hoist the `__log` adoption from after `emit('puppet')` to right after
`resolvePuppet` returns. Previously wechaty's own init-time verbose
logs (setMemory / setupPuppetEvents / the sync `emit('puppet')`
listeners in wechaty-redux and friends) all ran through the brolog
fallback while the rest of the lifecycle ran through the
caller-supplied logger — a half-brolog, half-caller-logger observation
gap on the exact path most needed for init failure triage.
Also:
- WechatySkeleton.static log: `Loggable` -> `LoggerLike`, so the
static and instance log surfaces expose the same contract to
callers (a Brolog instance already satisfies LoggerLike).
- WechatyOptions.logger JSDoc: spell out the scope so callers know
embedded libs (state-switch, memory-card, gerror) still emit via
the process-wide brolog and are not rerouted by this option.
Route static-method log calls through the wechatified class's `static get log()` (defined in user-mixins/wechatify.ts), so per-wechaty logger overrides also apply to Tag.list / Message.find / Contact.load and every other user-module static entrypoint. Module-top factory `log.verbose(...)` calls (executed once at mixin definition time, before any wechaty instance exists) are intentionally untouched. The one non-wechatified helper (PostBuilder in post.ts) keeps its brolog import.
The Io class stores `options` (with wechaty) via its constructor
parameter property, so every method — including the constructor body
past the parameter assignment — can route logging through the
per-wechaty logger.
The class-field initializer `new StateSwitch('Io', { log })` still
depends on the module-imported brolog because it runs before `this` is
constructed. That import stays for that one call site.
The `get isLoggedIn` fallback branch was still logging via the module-imported brolog. Route it through `this.log` so pluggable loggers see it too. Module-top factory calls and constructor pre-super log calls keep their brolog import (nothing to migrate elsewhere in wechaty-mixins).
Aligns with the wechaty-puppet re-release under 1.0.148 (the earlier 1.0.147 slot went to cache-hardening from main, not pluggable-logger).
Aligns with puppet-service re-release under 1.0.124 (its 1.0.123 slot went to cache-hardening from main, not pluggable-logger). Pin style preserved.
Slot 1.0.159 was published from main (cache-hardening pipeline) without the pluggable-logger changes. Re-release under 1.0.160.
Same fix as juzibot/wechaty-puppet#105 — unpinned @types/node ships newer syntax (e.g. 'using' declarations) that TS 4.7.4 cannot parse. Aligning the smoke test with the dev pin (^20.8.6) keeps CI green.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Add
WechatyOptions.loggerand route it through to the puppet layer.Wechaty.log,Contact.log,Message.log,Room.logand every other user module now resolve to whatever logger the caller supplied — with brolog fallback preserved end-to-end.Motivation
Multi-bot hosts need to attach botId to logs emitted deep inside wechaty and every user module. Making the logger pluggable at the
WechatyOptionslevel threads that context through the whole stack without any per-module surgery.Changes
src/schemas/logger.ts: re-exportLoggerLikefrom@juzi/wechaty-puppetsrc/schemas/wechaty-options.ts:logger?: LoggerLikesrc/wechaty/wechaty-skeleton.ts:__log: LoggerLike+get log(): LoggerLikesrc/wechaty-mixins/puppet-mixin.ts: forwardWechatyOptions.loggerintoPuppetOptions.loggerand adoptpuppet.logafter the puppet is built (structural cast becausePuppetInterfacehideslog)src/user-mixins/wechatify.ts: single-placestatic get log()+ instance getter — every user module gets it for freelog.xxx→this.log.xxx(90 in wechaty core, 194 in user modules)Compatibility
Zero-break: callers who do not pass
options.loggerget the historical brolog behaviour verbatim.Wechaty.logstill falls back to brolog when a third-party puppet doesn't expose.log.Verified
npm test: 33/33 tap spec pass (linked to local wechaty-puppet 1.0.147)🤖 Generated with Claude Code