Skip to main content

Logging

API BackendTooling

Lightweight level based logging system.

Installation​

yarn add @boost/log

Environment variables​

  • BOOSTJS_LOG_DEFAULT_LEVEL (LogLevel) - The default log level to use when calling the logger function stand alone (the usage examples below). Defaults to the lowest level, log.
  • BOOSTJS_LOG_MAX_LEVEL (LogLevel) - The maximum level, based on priority, to write to a stream. All levels higher than the maximum will be ignored. Defaults to allowing all levels.

Logging​

Logging is based around the concept of a "logger", which provides a set of functions of severity levels to log with. Logs are written to one or many provided transports -- or console if not defined. To begin, instantiate a logger with createLogger, which returns a function that can be used for standard level logging.

import { createLogger } from '@boost/log';

const log = createLogger({ name: 'boost' });

log('Something has happened…');

Each logging function requires a message string as the 1st argument, and an optional rest of arguments to interpolate into the message using util.format().

log('Name: %s %s', user.first_name, user.last_name);
log('Object: %O', data);

If you would prefer to interact with a class instance, you may use the Logger class. The major difference between the class and the function, is that the class only has 1 logging method, Logger#log().

import { Logger } from '@boost/log';

const logger = new Logger({ name: 'boost' });

logger.log({
level: 'info',
message: 'Something else has happened…',
});

Options​

When creating a logger, a LoggerOptions object can be passed. The options cannot be customized after the fact.

import chalk from 'chalk';
import { createLogger, StreamTransport } from '@boost/log';

const log = createLogger({
name: 'boost',
labels: {
error: chalk.bgRed.black.bold(' FAIL '),
},
transports: [new StreamTransport({ levels: ['error'], stream: process.stderr })],
});

Log levels​

There are 5 distinct logging levels outside the standard level, each represented as a unique function on the logger instance. The levels in order of priority are trace, debug, info, warn, and error. Each function requires a message as the 1st argument, and an optional rest of arguments to interpolate into the message.

log.trace('Code path hit?');
log.debug('What is going on here?');
log.info('Systems are stable');
log.warn('Something is definitely going on…');
log.error('Systems are down! %s', error.message);

Silencing output​

By default, all logged messages are immediately written to the configured transports. To silence output and disable writes, call the logger.disable() function, and to re-enable, call logger.enable().

log.disable();

// Will not write!
log.debug('Something is broken!');

Messages that are logged while silenced are lost and are not buffered.

Formats​

All logs are represented as an object, known as a LogItem. These items contain metadata about the environment, the logger, and the current log message.

Before an item is written to a transport, it must be formatted from an object into a string. This can be done on a per transport basis using the format option, like so.

import { ConsoleTransport, formats } from '@boost/log';

const transport = new ConsoleTransport({
format: (item) => `${item.level} ${item.message}`,
// Or a pre-built format
format: formats.json,
});

Boost provides formats by default, all of which are pre-configured into each built-in transport. Feel free to use the built-in formats, or customize your own!

Metadata​

Sometimes additional metadata may be required that is not found within the pre-defined log item fields. Metadata can be defined on the logger using an object, which is then passed to all log items.

const log = createLogger({
name: 'boost',
metadata: {
locale: 'en',
region: 'eu',
},
});

It can also be defined per log by passing an object as the 1st argument. Metadata defined at this level will override the logger metadata.

log({ locale: 'de' }, "What's going on?");

Fields name, host, and pid are reserved names and cannot be used.

Transport types​

There are multiple types of transports that can be used within a logger, all of which support a TransportOptions object. Some transports support additional options, so please refer to their types.

ConsoleTransport​

The ConsoleTransport logs messages to the native console and its corresponding level. This is the default transport when no transports are defined.

import { ConsoleTransport } from '@boost/log';

const transport = new ConsoleTransport();

StreamTransport​

The StreamTransport logs messages to any writeable stream or an object that defines a write() method. Additional StreamTransportOptions options may be provided.

import { StreamTransport } from '@boost/log';

const transport = new StreamTransport({
levels: ['error', 'warn'],
stream: process.stderr,
});

FileTransport​

The FileTransport appends and logs messages to a file at the defined path. Will automatically rotate files when a max file size is met. Additional FileTransportOptions options may be provided.

import { FileTransport } from '@boost/log';

const transport = new FileTransport({
levels: ['error'],
path: '/var/log/error.log',
});

RotatingFileTransport​

The RotatingFileTransport is like FileTransport, but also rotates files based on timestamps and a chosen periodic interval. Additional RotatingFileTransportOptions options may be provided.

import { RotatingFileTransport } from '@boost/log';

const transport = new RotatingFileTransport({
levels: ['error'],
path: '/var/log/error.log',
rotation: 'daily',
});

Test utilities​

A handful of Vitest utilities are available in the @boost/log/test module. View the API for a full list.