Repository navigation
feat: add pino logger adapter - #225
Merged
GiovaniGuizzo merged 3 commits intoOct 14, 2026
Merged
Conversation
Add `logger.adapter` ("winston" | "pino") and `logger.options`. Each
adapter is a strategy that receives Sidequest's entries: winston stays the
internal logger and, when an adapter is selected, forwards every entry
to it through a stream transport, so `logger()` and its call sites do not
change. Winston remains the default.
The engine loads the adapter in Engine.configure(), which runs in the app
process, the forked engine process and every worker thread, so only
serializable config crosses those boundaries. Non-serializable
`logger.options` fail fast instead of failing every job.
pino is an optional peer dependency, imported only when selected. Error
values in the metadata are written with pino's `err` serializer.
The worker logs "Starting worker..." after configuring the engine, and
config validation runs after the logger is set up, so those entries also
go through the selected adapter.
Closes sidequestjs#123
Contributor
|
Thanks for the contribution, @bhupinder759! I want to check this manually too today when I have the time. |
merencia
reviewed
Oct 3, 2026
…ries
pino writes to stdout asynchronously by default. A piscina worker thread
blocks its event loop while it waits for the next job, so the write never
completes and every later entry from that thread is lost: only the first
line per thread reached stdout. Without a transport, use
pino.destination({ dest: 1, sync: true }).
The integration test now runs two jobs on one worker thread and fails
without this change. The docs no longer recommend pino transports with
the thread runner, since they need the thread's event loop as well.
GiovaniGuizzo
approved these changes
Oct 14, 2026
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.
Closes #123
Checklist for Pull Requests
yarn test:allandyarn test:integration): unit tests and the non-DB integration tests pass locally; the backend and Postgres suites need Docker, which I don't have, so I'm relying on CI for thoseSummary of Changes
Adds
logger.adapter("winston"|"pino") andlogger.options, as discussed in #123:Design
SidequestLogger(error/warn/info/debug(message, meta?)) is the strategy interface.createPinoLoggeris the pino strategy, andloggerAdaptersmaps names to factories, so a new adapter is one factory plus one entry.scope, metadata) to that strategy.logger(), theLoggertype and all call sites are unchanged, and the default output is the same as before.Engine.configure(), which runs in the app process, the forked engine process and each worker thread, so only serializable config crosses those boundaries.logger.optionsthat can't be serialized (e.g. atimestampfunction) fail at start instead of failing every job.pinois an optional peer dependency of@sidequest/core, imported only when selected, with an install hint if it's missing. Error values in metadata go throughpino.stdSerializers.err.Small behaviour changes
engine.configure(), andvalidateConfig()runs after the logger is set up, so those lines also go through the selected adapter (and followlogger.level/logger.json).Engine.configure()registers the backend right after the config, before the newawait, so a concurrent caller never sees the config without a backend.Docs: installation ("Logger Adapters", with the warning that pino must be installed), logging guide ("Using pino"), configuration table.
How I tested
yarn build,yarn lint,yarn format:check: pass.tests/integration/pino-logger.integration.test.mjs(SQLite, no DB service): runs an app withadapter: "pino"in a child process and checks that every stdout line is pino JSON, including lines from the forked engine and a job'slogger()call in a worker thread. It fails with the previousworkers/main.tsorder.fork: false+runner: "inline"works.