Structured JSON logger with child loggers, redaction, and pretty dev output
npm install @philiprehberger/loggerStructured JSON logger with child loggers, redaction, and pretty dev output
npm install @philiprehberger/logger
import { createLogger } from '@philiprehberger/logger';
const logger = createLogger({ name: 'api', level: 'info' });
logger.info('Server started', { port: 3000 });
// {"level":"info","name":"api","msg":"Server started","port":3000,"ts":"2026-03-09T..."}
logger.error('Request failed', { status: 500, path: '/api/users' });
trace → debug → info → warn → error → fatal → silent
Messages below the configured level are silently dropped. Use silent to disable all output (useful in tests)
const reqLogger = logger.child({ requestId: 'abc-123' });
reqLogger.info('Processing request');
// {"level":"info","name":"api","msg":"Processing request","requestId":"abc-123","ts":"..."}
const dbLogger = reqLogger.child({ service: 'database' });
// Inherits requestId + adds service
Sensitive fields are automatically masked:
logger.info('Auth', { token: 'secret123', user: 'alice' });
// {"level":"info","name":"api","msg":"Auth","token":"[REDACTED]","user":"alice","ts":"..."}
Default redacted patterns: password, token, secret, authorization, cookie, key, credential, api_key, access_token, refresh_token, private_key.
Custom patterns:
const logger = createLogger({
name: 'app',
redact: ['ssn', 'credit_card', 'password'],
});
Arrays are redacted recursively:
logger.info('Users', { users: [{ name: 'alice', token: 'abc' }] });
// token is redacted inside the array element
Circular references are handled safely:
const obj: any = { name: 'test' };
obj.self = obj;
logger.info('Circular', obj);
// self becomes "[Circular]"
Disable redaction:
const logger = createLogger({ name: 'app', redact: false });
Auto-detected in development (NODE_ENV=development), or set manually:
const logger = createLogger({ name: 'app', pretty: true });
// INFO [app] Server started {"port":3000}
const logger = createLogger({ name: 'app', level: 'info' });
logger.debug('hidden'); // dropped
logger.setLevel('debug');
logger.debug('now visible'); // logged
// Child loggers inherit the parent's level unless they set their own
const child = logger.child({ req: '123' });
logger.setLevel('error'); // child also uses 'error' now
child.setLevel('debug'); // child overrides to 'debug'
Reduce log volume in noisy environments by emitting only a fraction of calls. A gated call returns without writing.
Single global rate (between 0 and 1):
import { createLogger } from '@philiprehberger/logger';
// Keep ~10% of all log calls
const logger = createLogger({ name: 'app', sampling: 0.1 });
logger.info('hello'); // ~90% of the time this is dropped
Per-level rates:
import { createLogger } from '@philiprehberger/logger';
const logger = createLogger({
name: 'app',
sampling: {
trace: 0.01, // 1% of trace
debug: 0.1, // 10% of debug
info: 1, // all info (any unspecified level defaults to 1)
warn: 1,
error: 1,
fatal: 1,
},
});
Default is 1 (no sampling). Child loggers inherit the parent's sampling config:
const logger = createLogger({ name: 'app', sampling: 0.5 });
const reqLogger = logger.child({ requestId: 'abc' });
// reqLogger also samples at 50%
LOG_LEVEL — sets the log level (overrides constructor option, case-insensitive)NODE_ENV=development — enables pretty mode by defaultimport { consoleTransport } from '@philiprehberger/logger';
const transport = consoleTransport({
pretty: true,
colors: { error: '\x1b[41m', info: '\x1b[36m' },
});
| Export | Type | Description |
|---|---|---|
createLogger(options) | Function | Create a logger instance with structured JSON output |
consoleTransport(options?) | Function | Create a console transport (default); supports pretty mode and custom colors |
createRedactor(patterns) | Function | Create a custom redaction function for sensitive fields |
LOG_LEVELS | Object | Level name to numeric priority mapping |
| Method | Description |
|---|---|
trace(msg, data?) | Log at trace level |
debug(msg, data?) | Log at debug level |
info(msg, data?) | Log at info level |
warn(msg, data?) | Log at warn level |
error(msg, data?) | Log at error level |
fatal(msg, data?) | Log at fatal level |
child(bindings) | Create a child logger with inherited context |
setLevel(level) | Change log level at runtime |
LoggerOptions| Property | Type | Default | Description |
|---|---|---|---|
name | string | required | Logger name attached to every entry |
level | LogLevel | 'info' | Minimum level to emit (or LOG_LEVEL env var) |
pretty | boolean | NODE_ENV==='development' | Pretty-print human-readable output |
redact | string[] | boolean | true | Field patterns to redact, false to disable, true for defaults |
transports | Transport[] | [consoleTransport(pretty)] | Custom output sinks |
sampling | number | Record<LogLevel, number> | 1 | Sample rate (0–1) globally or per level |
| Type | Description |
|---|---|
Logger | Logger instance interface |
LoggerOptions | Options accepted by createLogger |
LogLevel | 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal' | 'silent' |
LogEntry | Shape of a structured log entry |
Transport | Transport function signature |
SamplingRate | number or per-level { trace?, debug?, info?, warn?, error?, fatal? } map |
ConsoleTransportOptions | Options for consoleTransport |
npm install
npm run build
npm test
If you find this project useful: