A dive into the Node.js ‘Util’ module

Eran Schoellhorn
Mar 28, 2017 · 7 min read

I’ve been doing some general exploration of core Node.js modules lately and recently took a look at the util module. I had seen it used here and there in the past but never really explored it further. What I found are several special use case but handy functions. Here’s a quick rundown of each, along with some explanation and examples. As usual, the official docs are great as well.

The docs note that util is maintained for internal use however the tools within it are generic enough that they could also benefit application and module developers. I’ve seen a variety of packages on NPM which address similar needs so it’s always interesting to see what can be done using core modules and avoiding excess dependencies.

Here’s the whole list of util functions (ignoring deprecated stuff):

  • util.debuglog: A straightforward debug logger that can be enabled/disabled with an environment variable.
  • util.deprecate: Wrap public functions with a simple deprecation notice.
  • util.format: String formatter (ala. sprintf, printf, etc. )
  • util.inherits: Update an object’s prototype to inherit from another's
  • util.inspect: More powerful logging of data with support for color, object depth traversal, and other options.

util.debuglog

const util = require('util');
const log = util.debuglog('API');
const myObject = {
url: 'http://eran.sh',
coffee: true,
address: {
address1: '123 Fake St.',
address2: 'Gainesville, FL',
},
tags: ['red', 'banana', 'golf']
};
log(myObject);

Before logging anything, util.debuglog is called and given a tag corresponding to the module within which it will be used. It then returns a function which can be called to log anything within your application.

By default, nothing will be logged above as util.debuglog is silent by default. Only when the above script is run with NODE_DEBUG=API node app.js will we actually see the output in the console. This allows you to leave helpful debug logging in your code without cluttering the console or inadvertently, adversely affecting performance.

Once the environment variable is set, the logging looks something like this:

In addition to the module name, the process ID is also shown. This can be helpful when dealing with multiple processes.

If you feel like util.debuglog is too limited, there are a variety of more elaborate logging solutions available. I’ve had good results with winston but there are many others out there as well.

More on util.debuglog here.

util.deprecate

function capitalizeAndJoin(inputArray = []) {
return inputArray
.map(s => s.toString().toUpperCase())
.join(',')
}
module.exports = capitalizeAndJoin;

Here’s our developer’s code, using this module:

const capitalizeAndJoin = require(‘./capitalize-and-join’);const demoArray = [‘hello’, ‘test’, ‘wee’, 8];console.log(capitalizeAndJoin(demoArray))// Outputs:
// HELLO,TEST,WEE,8

If we have decided to deprecate the capitalizeAndJoin function, we can do so easily with util.deprecate.

const util = require('util');// ...module.exports = util.deprecate(
capitalizeAndJoin,
'This function has been deprecated. Use something else instead.'
);

By wrapping our function with util.deprecate and providing a warning message, developers will receive a clear indication of when function may be nearing removal. Here’s what that looks like:

The program still runs as normal however the DeprecationWarning is displayed.

More on util.deprecate here.

util.format

const util = require('util');const name = 'Eran';
const daysLeft = 4;
const message = util.format(
'Hello, %s! You have %d days remaining on your subscription.',
name,
daysLeft
);
console.log(message);// Outputs:
// Hello, Eran! You have 4 days remaining on your subscription.

util.format accepts a format string which can include tokens such as %s, %d, and a few others. This allows you to write out a string without dealing with variable interpolation directly. This means that the string could be stored separately or pulled from a localized group of messages, keeping your variables separate.

More on util.format here.

util.inherits

const util = require('util');
const EventEmitter = require('events');

function MyStream() {
EventEmitter.call(this);
}

util.inherits(MyStream, EventEmitter);

Now that JavaScript supports inheritances in a traditional OOP class sense, the encouraged manner to inherit from a superclass is to use extends without the need for util.inherits

const EventEmitter = require('events');

class MyStream extends EventEmitter {
constructor() {
super();
}
}

More on util.inherits here.

util.inspect

const util = require('util');const myObject = {
url: 'http://eran.sh',
coffee: true,
address: {
address1: '123 Fake St.',
address2: 'Gainesville, FL',
},
tags: ['red', 'banana', 'golf']
};
console.log(util.inspect(myObject))

The default behavior will give you something like this:

Inspect accepts a second parameter, a config object, which allows you to tailor the output. Some interesting items include…

const inspectOpts = {
showHidden: true, // Display non-enumerable properties
depth: 1, // How many nested properties deep should read
colors: true, // Display output in color
breakLength: 1 // # of items to be listed on a single line
};

Note: More options are available, check the docs for the full list.

The same object with the config options above applied.

The ability to control the depth of the data returned can be extremely helpful to prevent over-logging and making it hard to find the data you’re looking for which makes util.inspect a great tool to have at your disposal.

More on util.inspect here.

A unified logger for the lazy…

simple-logger.js

const { debuglog, inspect } = require('util');const defaultOptions = {
depth: 1, // How many nested properties deep should read
colors: true, // Display output in color
breakLength: 20 // # of items to be listed on a single line
};
function getLogger(tagName = 'APP', overrideOptions = {}) {
const logger = debuglog(tagName);
const inspectOptions = Object.assign(
{},
defaultOptions,
overrideOptions
);
return debugData => logger(inspect(debugData, inspectOptions))
}
module.exports = getLogger;

This module can now be imported in our project like so…

const log = require('./simple-logger')();const myObject = {
// ...
};
log(myObject);

Now we can categorize the util.debuglog tag when requiring the module or leave it blank to allow it to default to 'APP'. We’ve got some default config setup for util.inspect as well to make for pretty output.

Using an approach like this allows you to safely leave logging in place and only draw from it when needed by setting the NODE_DEBUG variable to 'APP'.

Thanks for reading!

ThreeFiveTwo

352 Inc Design and Engineering Blog

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

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