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.