A structured logging facade for Node.js with pluggable providers.
A logger composes structured log events and passes them to a provider. Providers decide what to do with them: filtering, encoding, buffering, and output. Libraries can log through a logger without deciding where their logs go, and applications choose the provider.
Warning
This module is under active development. Until 1.0.0, breaking changes may happen in minor releases.
npm install @nodejs/loggerNode.js 24.6.0 or later is required.
const create = require('@nodejs/logger');
const logger = create({ name: 'app' });
logger.info('server started', { port: 3000 });
// {"attributes":{"port":3000},"bindings":{},"level":{"name":"info","value":30},
// "message":"server started","name":"app","timestamp":1791280457128}import create, { ConsoleProvider } from '@nodejs/logger';
const logger = create(new ConsoleProvider({ flatten: true, pid: true }), {
name: 'app',
bindings: { service: 'users' },
});
logger.info('server started', { port: 3000 });
// {"service":"users","port":3000,"level":30,"levelName":"info",
// "message":"server started","name":"app","timestamp":1791280457128,"pid":4242}const { AsyncLocalStorage } = require('node:async_hooks');
const create = require('@nodejs/logger');
const requestContext = new AsyncLocalStorage();
const logger = create({
name: 'http',
// Function values are invoked for every event.
bindings: { request: () => requestContext.getStore() },
});
const child = logger.child({ component: 'router' });
requestContext.run({ requestId: 1 }, () => {
child.info('handled', { statusCode: 200 });
});Loggers created without a provider use the default provider, a
ConsoleProvider writing to stdout unless the application sets another one.
The default provider is shared by every copy of @nodejs/logger in the
process, so libraries can simply create loggers and let the application decide
where their logs go:
// In a library:
const log = require('@nodejs/logger')({ name: 'my-library' });
// In the application:
const { setDefaultProvider, ConsoleProvider } = require('@nodejs/logger');
setDefaultProvider(new ConsoleProvider({ level: 'debug', destination: 'stderr' }));Each worker thread has its own default provider. Records written by
ConsoleProviders in different threads never interleave. Loading
@nodejs/logger in the main thread before creating workers lets them write
directly, which is fastest:
require('@nodejs/logger');
const { Worker } = require('node:worker_threads');See Worker threads for details.
ConsoleProvider: Writes newline-delimited JSON (or the output of a custom serializer) to stdout or stderr, in synchronous batches written at the end of each turn of the event loop and when the process exits.EventProvider: AnEventEmitterthat emits events.AggregateProvider: Fans events out to multiple providers.
A provider is any object with a synchronous log(event, context) method, and
optionally an isEnabled(level, context) method:
const provider = {
isEnabled(level) {
return level.value >= 30;
},
log(event) {
// Forward the event to another logger, a buffer, a remote service, etc.
},
};
const logger = require('@nodejs/logger')(provider);Every enabled event is traced through the nodejs:logger:log tracing channel,
whenever it has subscribers. Tools can observe events and add data to them
without the application having to configure anything. See the
API reference.
See the API reference.
npm install
npm test # Run the tests
npm run test:types # Check the TypeScript declarations
npm run lint # Lint the code
npm run bench # Run the benchmarksLibrary code uses the built-ins captured in lib/internal/primordials.js,
following the conventions of Node.js core, so that it can be vendored into
Node.js.
This project follows the Node.js Code of Conduct.