Getting started
This page takes you from an empty project to a logger that writes to the console and a file, carries context, and flushes cleanly on shutdown.
Install
npm install logixiapnpm add logixiayarn add logixialogixia needs Node.js 16 or later and has three runtime dependencies (commander, fast-json-stringify, picocolors). Everything else is optional: NestJS (@nestjs/common, reflect-metadata) and Express are optional peer dependencies, only needed for logixia/nest. Database drivers are only needed for the database transport.
Your first logger
import { createLogger } from 'logixia';
const logger = createLogger({
appName: 'my-service',
environment: 'development',
});
await logger.info('Service started', { port: 3000 });
await logger.warn('Cache is cold', { keys: 0 });
await logger.error(new Error('Database connection lost'), { retryIn: 5000 });Every method returns a Promise<void>. Passing an Error to error() logs its message and serializes the name, message, stack and cause chain under error in the payload.
With no transports option, logixia prints one text line per entry to stdout (error goes to stderr). The default level is info, so debug calls are dropped until you change the level; see Log levels.
Add transports
Setting transports replaces the default output. Add console explicitly if you still want terminal output.
import { createLogger } from 'logixia';
const logger = createLogger({
appName: 'my-service',
environment: 'production',
transports: {
console: { format: 'json' },
file: {
filename: 'app.log',
dirname: './logs',
format: 'json',
maxSize: '50MB',
maxFiles: 5,
},
},
});
await logger.info('Order created', { orderId: 'ord_123', total: 49.9 });
await logger.close();Transports replace the default output
If you set transports but leave out console, nothing is written to the terminal. See Configuration for how the two output paths differ.
The transports overview lists everything available: file, database, CloudWatch, Google Cloud, Azure Monitor, Datadog, OTLP, analytics services, Slack, Discord and a worker-thread transport.
Redact secrets
import { createLogger } from 'logixia';
const logger = createLogger({
appName: 'my-service',
redact: {
paths: ['req.headers.authorization', '*.password'],
autoDetect: true,
},
});
await logger.info('Login', { user: 'ada', password: 'hunter2' });
// payload.password is replaced with [REDACTED]More in Redaction.
Add context
A child logger shares the parent's transports and adds a context label plus fields to every entry:
import { createLogger } from 'logixia';
const logger = createLogger({ appName: 'my-service' });
const orders = logger.child('OrderService', { region: 'eu-west-1' });
await orders.info('Order created', { orderId: 'ord_123' });For request-scoped context that follows async calls without passing a logger around, use LogixiaContext and trace IDs. See Child loggers and context and Tracing.
Flush before you exit
Batching transports (file, database, cloud) keep entries in memory briefly. Call close() when a script or test is done, or turn on graceful shutdown for long-running services:
import { createLogger } from 'logixia';
const logger = createLogger({
appName: 'my-service',
transports: { file: { filename: 'app.log', dirname: './logs' } },
gracefulShutdown: { enabled: true, timeout: 5000 },
});
await logger.info('ready');See Graceful shutdown.
TypeScript and flush()
The value returned by createLogger() is typed as the logger interface, which has close() but not flush(), healthCheck() or setNamespaceLevels(). Those exist at runtime on the LogixiaLogger class. If you need them, create the logger with new LogixiaLogger(config) instead. The class also adds custom level methods at runtime, but only createLogger() types them.
Next steps
- Configuration for every option
- HTTP logging or NestJS to wire logging into a web framework
- Testing to assert on logs without a real transport