DEV Community

Cover image for What JS Logging library / tool do you use?
Daniel Golant
Daniel Golant

Posted on

What JS Logging library / tool do you use?

I am trying to decide on what logging module to try out for my next project. I'd love the dev community's input on:

A) What logging lib you use
B) Whether you structure your logs (and how)
C) Where you store your logs or any other logging infra you have

I have been using Winston, but I would like something that supports structured logging out of the box. The general ecosystem on NPM seems to be pretty split, and some options seem to be popular but un-maintained.

Latest comments (38)

Collapse
 
ajstacy profile image
Andrew Stacy

I recently wrote and released a new library for logging in JavaScript that was created from the ground up with TypeScript and works seamlessly in the browser and node environments. It also offers a ton of other features (like log listeners for capturing log data) and it fully wraps the entire Console API standard. It offers a convenient, chainable API as well.

import adze from 'adze';

// Chaining example
adze().namespace('my-module').meta('fooKey', 'barVal').timestamp.log('This is an example log with a namespace, timestamp, and some meta data attached.');
Enter fullscreen mode Exit fullscreen mode

Here's an example of the default output and levels.

Output example

It's called Adze and you can find the docs at adzejs.com/ .

You can also find the GitHub repo at github.com/AJStacy/adze .

If you find it useful, please give it a star on GitHub!

Collapse
 
nombrekeff profile image
Keff

Hi there! Nice topic.

A:
I currently use a library I've been working on and maintaining for the last 2 years, its called Loggin'JS github.com/loggin-js/loggin-js. I mostly use it on NodeJS apps, but it also has support for the browser.

B:
In the browser I usually use logging as a debugging feature as tux0r said in another comment.
But if I make some kind of cli app for example, I will structure logs much more and separate them between user and debug logs, I usually save them all to log files, but only show specific logs to the user, as this lib makes this really simple. I also give the option to manage what logs the user want to see.

C:
If I'm working on the browser I usually don't store my logs, but on NodeJS apps I mostly save them on files or on some database like mongo-db, which this lib has a plugin to do so.

Collapse
 
download profile image
Stijn de Witt

For all you guys out there using the console directly, because you don't want to commit to some logging library, I came up with anylogger. It is a ~360 bytes minified and gzipped logging shim that wraps the console. But it is also a facade object that supports an adapter pattern to plug in support for the logging framework of choice.

For example, if you were building my-library, you could install anylogger like this:

npm install --save anylogger

Then in your code, you would create and use a logger like this:

my-library.js

var anylogger = require('anylogger')
var log = anylogger('my-library')
log('Logging is simple!')

This adds a tiny, ~360 bytes overhead to your library, but you now have configurable logging support. Suppose you discover you really like debug and want to use it in your new project that is using my-library. Here is how you would install my-library into your application project and make it use debug:

npm install --save my-library anylogger debug anylogger-debug

This installs my-library, anylogger, debug and the anylogger-debug adapter.

Then, in your main.js, just require the adapter and it will work:

main.js

require('anylogger-debug')
var debug = require('debug')
debug.enable('my-library')
// you should start to see logging from 'my-library'
// in the format expected from debug

I am working towards an 1.0 release and would appreciate feedback.

 
download profile image
Stijn de Witt

It is an example. The point is that if you do expensive things to produce the arguments of a log call, the fact that the log function is a no-op does not help with performance. In such cases you need the if. The example is there to demonstrate the if.

Collapse
 
download profile image
Stijn de Witt

I have, a long time ago, registered the NPM package name anylogger, because basically logging in JS is a royal mess. If you build an app out of a few dozen packages, chances are you end up including 5 different logging libraries because every module chooses it's own logger.

Wouldn't it be much better if libraries would use a facade to log and leave the choice of the actual logger (and it's config) to the final app? A bit like what SLF4J is doing in Java land, but much simpler of course ;)

This is what anylogger is supposed to be... a Facade that libs can use and that can be replaced by a real logger like Winston, Bunyan, Loglevel, Debug, or, of course, Ulog.

If you are interested in this, please check it out. It's mostly in pipe-dream stage at the moment though. But I would love to hear feedback on this.

Collapse
 
download profile image
Stijn de Witt • Edited

Please, please try ulog It is just over 1KB and it supports all this stuff out of the box. Plus it has a test suite and everything and does not have the bugs your home-brew implementation will have. I am speaking from experience. I have been developing this simple lib for years now and it is amazing how many things can (and will) go wrong in different environments when it comes to logging.

Basically I am hearing you guys re-inventing the wheel :) ulog has a simple config mechanism via env vars or localStorage that does exactly what you mention here, plus a bit more. Check it out and let me know what you think.

About the no-op thing.... It is probably just minimal overhead, not no overhead. But really if the overhead of an empty function call is an issue in your code, better look very carefully at your code because that should never be an issue.

What could be an issue is if you do this:

log.info(veryExpensiveFunctionCall())

The veryExpensiveFunctionCall() will be performed and the result passed to the no-op method... So still slow.

In ulog we fix that like this:

if (log.level >= log.INFO) {
  log.info(veryExpensiveFunctionCall())
}

The level check makes sure we only call veryExpensiveFunctionCall() if it is really needed.

Collapse
 
download profile image
Stijn de Witt

Before I proceed I must warn you I am the author of the logging library I am using, so there is a tiny possibility that I might be biased. Very tiny :)

ulog - The microscopically small universal logger

Basically ulog is debug meets loglevel meets the console. It works in Node JS and all major browsers (even old ones!)

  • Mostly works exactly like the console does
  • Supports levels that map to console methods (info, warn, error...)
  • Supports configuration of log level via query string/localStorage (browser) or environment variables (Node)
  • Supports a debug mode that selectively enables loggers
  • Smart default log levels

Why I built it

It started out because using console directly is basically VERBOTEN. Because some browsers simply don't support it and will crash your code. Also you need to remove these statements afterwards etc. Making logging difficult and error prone. So it started as a tiny shim that just makes sure that your code never crashes or fails whether console is available or not.

I then decided I wanted log level support so I added that. And then I discovered debug, which is GREAT, and I decided to copy those features I loved about that.

Why I think it is one of the best loggers

  • It is SMALL. Some loggers really go overboard but I need this stuff to be tiny. 1K is about all I want to spend on a logging lib
  • It supports levels. Levels make logging useful!
  • It has AWESOME debug features. Just set DEBUG=module1,module2 and these modules will start logging debug info
  • By default, only Error and Warning message will show up in the console in browsers, meaning you can log as much as you want and only those people that are interested in it will actually see it. You can just leave your log statements in your production code. In Node JS we use INFO as the default level because there the 'users' are mostly developers / server admins etc who are more interested in our logging. Using different defaults on different platforms felt weird at first but it actually works out great for my projects.
  • It supports a shorthand form that applies formatting.

Example usage

var ulog = require('ulog')
var log = ulog('my-module')

log.debug('Debug message');
log.info('Info message');
log.warn('Warning message');
log('Formatted message (at debug level)')
log('warn', 'Formatted message (at warning level)')
Enter fullscreen mode Exit fullscreen mode

Yields (on browsers)

Warning message
21:23:24   .03 my-module                Formatted message (at warning level)
Enter fullscreen mode Exit fullscreen mode

If you want to try it

Now is the perfect time as I am trying to perfect v2 currently. So if you want to try this, please install the beta and let me know:

npm install --save ulog@beta
Enter fullscreen mode Exit fullscreen mode

Or you can use v1, but that version is more limited in features:

npm install --save ulog
Enter fullscreen mode Exit fullscreen mode
Collapse
 
robertcoopercode profile image
Robert Cooper

Haven't heard of Winston before this post. Looks really cool for creating log files based on the console statements used in the code!

Collapse
 
joelnet profile image
JavaScript Joel

I have used and enjoyed bunyan. Used in combination with bunyan-format it improved the project.

You can see it used in my project here:
github.com/joelnet/bitcoin-all-tim...

Collapse
 
adrienpoly profile image
Adrien Poly

I love

console.table()

console table

Collapse
 
download profile image
Stijn de Witt

It is great but not very well supported I think? Does this work in Edge? Firefox?

Collapse
 
jasman7799 profile image
Jarod Smith

A) I use a combination of morgan for request logging, and Winston for error logs.

B) I structure my logs into information logs, warning logs, request logs, and error logs.

  • The information logs are used for things like user sign-in, database modifications, and algorithm analysis.
  • Warning logs are things like the user was denied access, A resource is using up too much memory or taking too long, or a result that doesn't break the system, but could be a problem for the user.
  • Error logs are reserved for runtime errors or anything where a system actually failed to perform its job.
  • The request logs are handled by Morgan and they mainly log the request made to the server, the parsed query (using GraphQL), and the response to the user.

C) I store my logs in a logs folder on the production server. They are organized into 3 files based on the level of severity, and each log entry is prepended with a time stamp, and the userId if applicable.

Collapse
 
antogarand profile image
Antony Garand

Winston has been my daily driver for a while.
Having different transport methods, easily changing the logging level and the handling uncaught exceptions makes debugging a lot better!

This is a game changer, specially on old code!

Collapse
 
entrptaher profile image
Md Abu Taher • Edited

Other than console.log(), there have been morgan, winston, pino and at least hundreds of others.

But, I am very surprised to see no one mentioned debug, it has 22,914,644 weekly downloads as of right this comment.

  • I can filter out and specify different keywords I put beforehand, can use wildcards for multiple keywords/namespace
  • Can have namespace colors
  • Even works on web browser with colorized output
  • can show ms diff between last msg
  • ...lots of other cool features like streams and the list goes on
  • and most importantly it is actively developed

Though it is more of a debugging tool than a logging tool, we do have to log a lot while trying to debug, or in most case debugging is the only goal for logging.

There are obvious gotchas, but who cares as long as I can get to see what I wanted to see.

Collapse
 
download profile image
Stijn de Witt

Indeed, debug RULES! So much so I rebuilt my logging lib from scratch so it could incorporate debug's best features.

The biggest gripe I have with it is that it is not full-featured. It basically is ONLY for debug logging. I like to log some info/warning messages as well some times. With debug you still need either a different lib or the console just for that.

Collapse
 
d0ruk profile image
Doruk Kutlu

debug module borks when minimized

You need to configure the compression to let some optimizations through

I also couldnt get it to work on an isomorphic app. Minimizing for node.js and tje web require 2 different approaches

Collapse
 
pim profile image
Pim

Seems like a lot of people use winston. I primarily use serilog (.NET), the reason I love it and bring it up is because it's a fully-structured logger. I can't speak to winston's capabilities, but I know bunyan offers similar features in node which I highly recommend finding.

Collapse
 
pldg profile image
Luca

For those who use simple console.log() and VS Code as editor, try out wrap-console-log extension.

If you'd like to color your log try chalk.

Collapse
 
hdennen profile image
Harry Dennen

chalk is great.

Collapse
 
dangolant profile image
Daniel Golant

this is awesome :)