Winston: Custom log levels

Created on 8 Feb 2012  路  27Comments  路  Source: winstonjs/winston

I'm unable to get custom log levels to work. I've tried updating node, installing winston via npm, and cloning the winston repo. The example code in the readme for custom levels runs without any errors:

 var myCustomLevels = {
    levels: {
      foo: 0,
      bar: 1,
      baz: 2,
      foobar: 3
    },
    colors: {
      foo: 'blue',
      bar: 'green',
      baz: 'yellow',
      foobar: 'red'
    }
  };

  var customLevelLogger = new (winston.Logger)({ levels: myCustomLevels.levels }); 
  customLevelLogger.foobar('some foobar level-ed message');

but nothing prints out into console.

I've also tried a variation of

  var logger = new (winston.Logger)({
    transports: [
      new (winston.transports.Console)(),
      new (winston.transports.File)({ filename: 'somefile.log' })
    ]
  });

with logger.addLevels() but I get the same results. The new log levels I pass do nothing.

The originals (info, debug, etc.) are not available - just as expected.

Most helpful comment

So I was able to dig into this a bit more and figure out a bit more about what's going on. From all the code samples I've seen in the documentation and this thread, the expectation is that setting the default level on the logger is the only required configuration to use custom levels.

I found that not only do you need to set the default logger level but also the default transport level to get the examples above and in the documentation to work as expected. From your example above, changing this line to the following:

transports: [new winston.transports.Console({level: foobar})]

This is mostly to do with this conditional in lib/winston/logger.js:

if ((transport.level && self.levels[transport.level] <= self.levels[level]) 
    || (!transport.level && self.levels[self.level] <= self.levels[level])) 

Since the default transport.level is set to info in lib/winston/transports/transport.js here:

this.level = options.level  || 'info';

You'll need to do one of two things to use custom levels, in addition to defining the default level on the logger:

  1. Define a default level on your transport
  2. Include an info level in your custom levels

If this isn't by design, it can be fixed by altering the conditional and the forced variable assignment. If it is by design, the documentation should be tweaked a bit too avoid confusion.

I'd be happy to help accomplish either, just let me know which direction you'd like to head.
Thanks!

All 27 comments

You need to set both levels and transports:

 var myCustomLevels = {
    levels: {
      foo: 0,
      bar: 1,
      baz: 2,
      foobar: 3
    },
    colors: {
      foo: 'blue',
      bar: 'green',
      baz: 'yellow',
      foobar: 'red'
    }
  };

  var customLevelLogger = new (winston.Logger)({
    level: 'foo', 
    levels: myCustomLevels.levels,
    transports: [new winston.transports.Console()]
  }); 
  customLevelLogger.foobar('some foobar level-ed message');

Hey indexzero, I'm running into the same issue working with a slightly simplified version of your example code:

var winston = require('winston')
var myCustomLevels = {
    levels: {
      foo: 0,
      bar: 1,
      baz: 2,
      foobar: 3
    }
};

var customLevelLogger = new (winston.Logger)({
    levels: myCustomLevels.levels,
    transports: [new winston.transports.Console()]
});
customLevelLogger.foobar('some foobar level-ed message');

will not work. It prints nothing to the console:

ruby-1.9.2-p290:winston-test: node server.js 
ruby-1.9.2-p290:winston-test:

If I modify the first two levels to include info and debug, I will get the expected result:

var myCustomLevels = {
    levels: {
      info: 0,
      debug: 1,
      baz: 2,
      foobar: 3
    }
};

var customLevelLogger = new (winston.Logger)({
    levels: myCustomLevels.levels,
    transports: [new winston.transports.Console()]
});
customLevelLogger.foobar('some foobar level-ed message');

Will result in:

ruby-1.9.2-p290:winston-test: node server.js 
foobar: some foobar level-ed message
ruby-1.9.2-p290:winston-test:

>.< @JCBarry Read my code sample carefully. You are missing the level property being passed to the winston.Logger constructor:

 var customLevelLogger = new (winston.Logger)({
    level: 'foo', // You are not passing a level parameter, so it is defaulting to `info` which doesnt exist.
    levels: myCustomLevels.levels,
    transports: [new winston.transports.Console()]
  }); 
  customLevelLogger.foobar('some foobar level-ed message');

Your exact code sample copy and pasted into a node script doesn't output anything to the terminal. Also, since you're specifying which level to use specifically ("foobar") in this case, why would it care about the default level?

I've also tried both of the code examples you provided. Neither of them output anything to console.

It's not until you include "debug" and "info" in the custom levels, that things will work as expected.

Here is a video of me using your example code, and changing those 2 keys.

http://screencast.com/t/CxWAleAueeRW

Also, taking out level:'foo', didn't seem to make a difference.

So I was able to dig into this a bit more and figure out a bit more about what's going on. From all the code samples I've seen in the documentation and this thread, the expectation is that setting the default level on the logger is the only required configuration to use custom levels.

I found that not only do you need to set the default logger level but also the default transport level to get the examples above and in the documentation to work as expected. From your example above, changing this line to the following:

transports: [new winston.transports.Console({level: foobar})]

This is mostly to do with this conditional in lib/winston/logger.js:

if ((transport.level && self.levels[transport.level] <= self.levels[level]) 
    || (!transport.level && self.levels[self.level] <= self.levels[level])) 

Since the default transport.level is set to info in lib/winston/transports/transport.js here:

this.level = options.level  || 'info';

You'll need to do one of two things to use custom levels, in addition to defining the default level on the logger:

  1. Define a default level on your transport
  2. Include an info level in your custom levels

If this isn't by design, it can be fixed by altering the conditional and the forced variable assignment. If it is by design, the documentation should be tweaked a bit too avoid confusion.

I'd be happy to help accomplish either, just let me know which direction you'd like to head.
Thanks!

Hey Index,
Just wanted to know if I could help in any way relating to this?

Thanks!

Thanks JCBarry, though it believe it should be ({level: "foobar"}).

Seems that configuring winston is a bit of a black art, unless you're the author of course.

If it's of any use to someone, here's my fully working example with 2 loggers, custom levels and console coloring: https://gist.github.com/2570757

That seems to work:

var logger = new (Winston.Logger)({
    levels: {trace: 0, notice: 1, warning: 2, error: 3},
    transports: [
        new Winston.transports.Console({
            level: "trace",
            colorize: true
        })
    ],
    colors: {trace: "white", notice: "cyan", warning: "yellow", error: "red"}
});

+1 @garth

thanks @garth

Hi, I had the same problem. I solved it by starting with "info : 0"

levels : {
        info    : 0,
        emerg   : 1,
        alert   : 2,
        crit    : 3,
        err     : 4,
        warn    : 5,
        notice  : 6,
        debug   : 7
}

Strange, what I encountered:

My levels were (I copied from the default system settings, and added the trace one) (require('winston').config.syslog.levels)

{"emerg":0,"alert":1,"crit":2,"error":3,"warning":4,"notice":5,"info":6,"debug":7, "trace":8}

When I inverted the order, it worked ... I found it strange since the syslog.levels are inverted.

{"emerg":8,"alert":7,"crit":6,"error":5,"warning":4,"notice":3,"info":2,"debug":1, "trace":0}

But its working properly now.

Weird, but I confirm that it also worked for me after having the order inverted in comparison to syslog.

+1 @lucastschmidt although I feel weird doing it. I'd like to know the reason why inverting the levels worked; was it something to do with conflicting values vs the syslog?

Well @kb19, I have no idea actually, I didnt investigate the code.

Hi, I had the same problem. I solved it by change orders

var config = {
levels: {
debug: 0,
info: 1,
help: 2,
warn: 3,
error: 4,
data: 5,
input: 6,
verbose: 7,
prompt: 8,
silly: 9

 },
 colors: {
     debug: 'blue',
     info: 'green',
     help: 'cyan',
     warn: 'yellow',
     error: 'red',
     data: 'grey',
     input: 'grey',
     verbose: 'cyan',
     prompt: 'grey',
     silly: 'magenta'

 }

};

+1 Doesn't work. Cannot get the colors to work at all. Tried all examples listed here and in the main docs.

Yeah, I'm having the same problem. Tried everything, any hints about why it might not be working?

+1

Ditto :+1:

hi,
I just want to print my custom logs in a file.but along with the custom logs info,debug are also getting printing in file.what to do in this case?please reply

From comments on @vikas5914 s thread, I realized that the level: parameter to logger/format isn't the default log level, but the log level limit, and everything 'below' (meaning with a higher number) will not be displayed. This would explain why so many people here had success by changing the order of their log levels.

will someone update the docs with a working example?

Was this page helpful?
0 / 5 - 0 ratings