Roarr! the perfect JSON logger for Node.js and browser

Zero-configuration, out of process transports and adheres to the Twelve Factors

Running services in high-concurrency you need to be able to pin point when and what breaks.

Existing loggers

  • I can use in an application code and in dependencies
  • allows me to correlate logs between the main application code and the dependency code
  • works well with transports in external processes
Roarr is loud

Strict API

Configuration

ROARR_LOG=true node ./index.js

The logger function

  • The first parameter can be either a string (message) or an object. If the first parameter is an object (context), the second parameter must be a string (message).
  • Arguments after the message parameter are used to enable printf message formatting. Printf arguments must be of a primitive type (string | number | boolean | null). There can be up to 9 printf arguments (or 8 if the first parameter is the context object).
import log from 'roarr';

log('foo');

log('bar %s', 'baz');

const debug = log.child({
level: 'debug'
});

debug('qux');

debug({
quuz: 'corge'
}, 'quux');
{"context":{},"message":"foo","sequence":0,"time":1506776210000,"version":"1.0.0"}
{"context":{},"message":"bar baz","sequence":1,"time":1506776210000,"version":"1.0.0"}
{"context":{"level":"debug"},"message":"quux","sequence":2,"time":1506776210000,"version":"1.0.0"}
{"context":{"level":"debug","quuz":"corge"},"sequence":3,"message":"quux","time":1506776210000,"version":"1.0.0"}

Inspecting the logs

CLI program output.

Usage patterns

Using Roarr in an application

/**
* @file Example contents of a Logger.js file.
*/
import Roarr from 'roarr';
import ulid from 'ulid';
// Instance ID is useful for correlating logs in high concurrency environment.
//
// See `roarr augment --append-instance-id` option as an alternative way to
// append instance ID to all logs.
const instanceId = ulid();
// The reason we are using `global.ROARR.prepend` as opposed to `roarr#child`
// is because we want this information to be prepended to all logs, including
// those of the "my-application" dependencies.
global.ROARR.prepend = {
...global.ROARR.prepend,
application: 'my-application',
instanceId
};
export default Roarr.child({
// .foo property is going to appear only in the logs that are created using
// the current instance of a Roarr logger.
foo: 'bar'
});

Using Roarr in a dependency

/**
* @file Example contents of a Logger.js file.
*/
import Roarr from 'roarr';export default Roarr.child({
domain: 'database',
package: 'my-package'
});

Filtering logs

ROARR_LOG=true node ./index.js | jq 'select(.context.logLevel == "warning" or .context.logLevel == "error")'
ROARR_LOG=true node ./index.js | jq 'select(.context.package == "usus")' | roarr pretty-print

Manipulating the log message context globally

import log from 'roarr';
import foo from 'foo';

const taskIds = [
1,
2,
3
];

for (const taskId of taskIds) {
global.ROARR = global.ROARR || {};
global.ROARR.prepend = {
taskId
};

log('starting task ID %d', taskId);

// In this example, `foo` is an arbitrary third-party dependency that is using
// roarr logger.
foo(taskId);

log('successfully completed task ID %d', taskId);

global.ROARR.prepend = {};
}
{"context":{"taskId":1},"message":"starting task ID 1","sequence":0,"time":1506776210000,"version":"1.0.0"}
{"context":{"taskId":1},"message":"foo","sequence":1,"time":1506776210000,"version":"1.0.0"}
{"context":{"taskId":1},"message":"successfully completed task ID 1","sequence":2,"time":1506776210000,"version":"1.0.0"}
[...]

Transports

  • Beats
    For aggregating at a process level
    Written in Go
  • logagent
    For aggregating at a process level
    Written in JavaScript
  • Fluentd
    For aggregating logs at a container orchestration level such as Kubernetes
    Written in Ruby

The future of Roarr

What about the name?

You’re gonna hear me roar!

Roarr!

Roarr!

You like to read, I love to write

--

--

We’ve moved to https://freecodecamp.org/news and publish tons of tutorials each week. See you there.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Gajus Kuizinas

Founder, engineer interested in JavaScript, PostgreSQL and DevOps. Follow me on Twitter for outbursts about startups & engineering. https://twitter.com/kuizinas