Crowlog is a simple, lightweight, zero-dependency, and extendable logging library for any JavaScript environment.
- Ultra lightweight - Crowlog is very lightweight (less than 1kB minified + gzipped, see comparison).
- Zero dependencies - No runtime dependencies, just pure JavaScript.
- Extendable - Crowlog is designed to be extendable, so you can add your own transports and plugins to it.
- Simple - Crowlog is designed to be simple and easy to use.
- Fully typed - Crowlog is fully typed, so you can get autocomplete and type safety when using it.
- Any environment - Crowlog works in any environment, including Node.js, browsers, and the edge.
- Testing friendly - Crowlog is designed to be testing friendly, so you can easily test your logs with the in-memory transport.
- Slightly opinionated - Crowlog is designed to be slightly opinionated, so it has a default transport and some plugins.
- Pretty logs - Crowlog pretty log command to display logs in a more readable format for development.
# pnpm
pnpm install @crowlog/logger
# npm
npm install @crowlog/logger
# yarn
yarn add @crowlog/loggerBasic usage:
import { createLogger } from '@crowlog/logger';
const logger = createLogger({ namespace: 'my-app' });
logger.info('Hello world');
logger.error({ error: new Error('...') }, 'Something went wrong');Note
The logging interface is either a single string message or a data object and a message string tuple.
logger.info('Hello world');
logger.info({ foo: 'bar' }, 'Hello world');Crowlog logger provides 4 different logging methods: debug, info, warn, and error.
logger.debug(/* ... */);
logger.info(/* ... */);
logger.warn(/* ... */);
logger.error(/* ... */);Crowlog logger provides a createChildLogger method to create a child logger that inherit the configuration of the parent logger.
import { createLogger } from '@crowlog/logger';
const logger = createLogger({ namespace: 'my-app' });
const childLogger = logger.createChildLogger({ namespace: 'child' });Alternatively, you can use the createLoggerFactory to create a logger factory that can be used to create child loggers with the same configuration.
import { createLoggerFactory } from '@crowlog/logger';
const createLogger = createLoggerFactory({ transports: /* ... */, plugins: /* ... */ });
const logger = createLogger({ namespace: 'child' });Transports control where logs are sent. By default, Crowlog uses the stdout transport (outputs JSON to console).
import { createLogger, createStdoutLoggerTransport } from '@crowlog/logger';
// Customize serialization
const logger = createLogger({
namespace: 'my-app',
transports: [
createStdoutLoggerTransport({
serialize: ({ level, message }) => `[${level}] ${message}`
})
]
});For testing, use the in-memory transport:
import { createInMemoryLoggerTransport } from '@crowlog/logger';
const inMemoryTransport = createInMemoryLoggerTransport();
const logger = createLogger({
namespace: 'my-app',
transports: [inMemoryTransport]
});
logger.info('Test log');
const logs = inMemoryTransport.getLogs({ excludeTimestampMs: true });See the full documentation for more details on transports and how to create custom ones.
Plugins extend logger functionality with filtering, redaction, and context management.
Control which logs reach transports:
import { createLogger, createFilterPlugin } from '@crowlog/logger';
const logger = createLogger({
namespace: 'my-app',
plugins: [
createFilterPlugin({
minLevel: 'info', // Only info and above
excludedNamespaces: ['debug-utils'] // Exclude specific namespaces
})
]
});Automatically hide sensitive data:
import { createRedactPlugin } from '@crowlog/logger';
const logger = createLogger({
namespace: 'my-app',
plugins: [
createRedactPlugin({
paths: ['password', 'apiKey', 'user.email']
})
]
});
logger.info({ password: 'secret', username: 'alice' }, 'Login');
// Output: { password: '[redacted]', username: 'alice' }Add application-wide context to all logs:
import { createGlobalLogContextPlugin } from '@crowlog/logger';
const { globalContextPlugin, setGlobalLogContext } = createGlobalLogContextPlugin();
const logger = createLogger({
namespace: 'my-app',
plugins: [globalContextPlugin]
});
setGlobalLogContext({ environment: 'production', version: '1.0.0' });
logger.info('Started'); // Includes environment and versionAdd request-scoped context (requires async_hooks support):
import { createAsyncContextPlugin, wrapWithLoggerContext } from '@crowlog/async-context-plugin';
const logger = createLogger({
namespace: 'my-app',
plugins: [createAsyncContextPlugin()]
});
wrapWithLoggerContext({ requestId: '123' }, () => {
logger.info('Processing'); // Includes requestId
});See the full documentation for more details on plugins and how to create custom ones.
Format JSON logs for development with @crowlog/pretty:
node index.js | npx crowlog-prettySee the pretty logging guide for more details.
Use the in-memory transport to capture logs in tests, or the noop logger to disable logging entirely:
import { createNoopLogger } from '@crowlog/logger';
// No logs will be produced
const result = doSomething({ logger: createNoopLogger() });See the testing guide for more details.
| Library | Runtime dependencies | Bundled size |
|---|---|---|
| @crowlog/logger@1.0.0 | 0 dependencies | 1.3kB (674B minified + gzipped) source |
| pino@9.6.0 | 11 dependencies | 7.5kB (2.9kb minified + gzipped) source |
| winston@3.17.0 | 11 dependencies | 147.9kB (37.4kB minified + gzipped) source |
| bunyan@1.8.15 | 19 dependencies | 15.7kB (5.6kB minified + gzipped) source |
This project is licensed under the MIT License. See the LICENSE file for more information.
This project is crafted with ❤️ by Corentin Thomasset. If you find this project helpful, please consider supporting my work.
The icon is the Raven Rounded from the Material Symbols.
