/logform

An mutable object format designed for chaining & objectMode streams

Primary LanguageJavaScriptMIT LicenseMIT

logform

An mutable object-based log format designed for chaining & objectMode streams.

const { format } = require('logform');

const alignedWithColorsAndTime = format.combine(
  format.colorize(),
  format.timestamp(),
  format.align(),
  format.printf(info => `${info.timestamp} ${info.level}: ${info.message}`)
);

info Objects

The info parameter provided to a given format represents a single log message. The object itself is mutable. Every info must have at least the level and message properties:

{
  level: 'info',                 // Level of the logging message  
  message: 'Hey! Log something?' // Descriptive message being logged.
}

logform itself exposes several additional properties:

  • splat: string interpolation splat for %d %s-style messages.
  • timestamp: timestamp the message was received.
  • label: custom label associated with each message.

As a consumer you may add whatever properties you wish – internal state is maintained by Symbol properties:

  • Symbol.for('level') (READ-ONLY): equal to level property. Is treated as immutable by all code.
  • Symbol.for('message'): complete string message set by "finalizing formats": json, logstash, printf, prettyPrint, and simple.

Understanding formats

Formats are prototypal objects (i.e. class instances) that define a single method: transform(info, opts) and return the mutated info

  • info: an object representing the log message.
  • opts: setting specific to the current instance of the format.

They are expected to return one of two things:

  • An info Object representing the modified info argument. Object references need not be preserved if immutability is preferred. All current built-in formats consider info mutable, but [immutablejs] is being considered for future releases.
  • A falsey value indicating that the info argument should be ignored by the caller. (See: Filtering info Objects) below.

logform.format is designed to be as simple as possible. To define a new format simple pass it a transform(info, opts) function to get a new Format.

The named Format returned can be used to create as many copies of the given Format as desired:

const { format } = require('logform');

const volume = format((info, opts) => {
  if (opts.yell) {
    info.message = info.message.toUpperCase(); 
  } else if (opts.whisper) {
    info.message = info.message.toLowerCase();
  }

  return info;
});

// `volume` is now a function that returns instances of the format.
const scream = volume({ yell: true });
console.dir(scream.transform({
  level: 'info',
  message: `sorry for making you YELL in your head!`
}, scream.options));
// {
//   level: 'info'
//   message: 'SORRY FOR MAKING YOU YELL IN YOUR HEAD!'
// }

// `volume` can be used multiple times to create different formats.
const whisper = volume({ whisper: true });
console.dir(whisper.transform({ 
  level: 'info', 
  message: `WHY ARE THEY MAKING US YELL SO MUCH!` 
}), whisper.options);
// {
//   level: 'info'
//   message: 'why are they making us yell so much!'
// }

Combining formats

Any number of formats may be combined into a single format using format.combine. Since format.combine takes no opts, as a convenience it returns pre-created instance of the combined format.

const { format } = require('logform');
const { combine, timestamp, label } = format;

const labelTimestamp = combine(
  label({ label: 'right meow!' }),
  timestamp()
);

const info = labelTimestamp.transform({
  level: 'info',
  message: 'What time is the testing at?'
});

console.dir(info);
// { level: 'info',
//   message: 'What time is the testing at?',
//   label: 'right meow!',
//   timestamp: '2017-09-30T03:57:26.875Z' }

Filtering info Objects

If you wish to filter out a given info Object completely then simply return a falsey value.

const ignorePrivate = format((info, opts) => {
  if (info.private) { return false; }
  return info;
});

console.dir(ignorePrivate.transform({
  level: 'error',
  message: 'Public error to share'
}));
// { level: 'error', message: 'Public error to share' }

console.dir(ignorePrivate.transform({
  level: 'error',
  private: true,
  message: 'This is super secret - hide it.'
}));
// false

Use of format.combine will respect any falsey values return and stop evaluation of later formats in the series. For example:

const { format } = require('logform');
const { combine, timestamp, label } = format;

const willNeverThrow = format.combine(
  format(info => { return false })(), // Ignores everything
  format(info => { throw new Error('Never reached') })()
);

console.dir(willNeverThrow.transform({
  level: 'info',
  message: 'wow such testing'
}))

Tests

Tests are written with mocha, assume, and nyc. They can be run with npm:

npm test
LICENSE: MIT