Shared Transports #101

Closed
bluepines opened this Issue Feb 16, 2012 · 24 comments
@bluepines

I am having trouble setting up shared transports.

I am using this method to add the shared transports:

winston.loggers.add('some-category', {
    transports: [
      // Setup your shared transports here
    ]
});

Basically, I have two types of loggers one "debugLogger", and then a large number of "specificDebugLoggers". I want the specific debug loggers to each get their own file, but I also want them to log output to the main debug file.

However, when I try and share the transports, I get this error:

Error: Transport already attached: file

Here is what I am doing:

debugFileTransport = {
    filename: '/var/log/mycoolapp/debug.log',
};

// Here is how the main debug log is created.
winston.loggers.add('debugLogger', {
  transports: [
    new winston.transports.File(debugFileTransport)  // Here is the shared transport
  ]
});

// And here is how the specific debug logs get created.
createLogger = function(name, filepath) {
  winston.loggers.add(name, {
    transports: [
      new winston.transports.File(debugFileTransport), // Here is the shared transport
      new winston.transports.File({
        filename: filepath,
      })
    ]
  });
  return winston.loggers.get(name);
};
@indexzero
winstonjs member

@bluepines Why do you need two file transports? This is currently not supported.

@ryan-roemer

I'd also like this, my use case is:

  • app.log: Everything.
  • app-error.log: Just the errors.

The different files get different logrotate, persistence, etc. treatment. I can also see use cases more generally for multiple transports of the same type with different configurations.

@indexzero
winstonjs member

@ryan-roemer That is already possible through configurable log levels.

@ryan-roemer

@indexzero Thanks for the response. Could you post a quick example? I don't see how to do this from the readme. Ideally, I want info-everything higher in one log, and duplicate of the errors only in another. I was trying to do this:

Log = new (winston.Logger)({
  transports: [
    new (winston.transports.File)({
      level: "info",
      filename: "foo.log"
    }),
    new (winston.transports.File)({
      level: "error",
      filename: "foo-error.log"
    })
  ]
});

And, apologies for clogging this issue!

@domenic

I too am stumped by how to do this. @ryan-roemer did you figure it out in the end?

@ryan-roemer

@domenic Nope -- my use case morphed into using two different transports, thus avoiding the issue. I am interested in finding out a good example of how to do this with the same transport though!

@rickcrawford

Couldn't you use 2 different loggers instead? I needed one for request logging and the other for debug/std out logging, so I just created 2 instances.

//configure the logger
var requestLogger = new (winston.Logger)({
    transports: [
//      new (winston.transports.Console)(),
      new (winston.transports.File)({ 
          filename: '../logs/requests.log',
          json: true,
          maxsize: 1024,
          maxFiles: 2
      })
    ]
  });

//configure the logger
var logger = new (winston.Logger)({
    transports: [
//      new (winston.transports.Console)(),
      new (winston.transports.File)({ 
          filename: '../logs/stdout.log',
          json: true,
          maxsize: 1024,
          maxFiles: 2
      })
    ]
  });
@ryan-roemer

@rickcrawford Thanks for offering some suggestions.

Unfortunately, my ideal use case would be to make this a matter of pure configuration -- (1) I log at a different levels using one logger, and (2) I have different log outputs at different levels (and some multiply overlapping).

Having logger.error and logger.info is much more consistent and easy to change and maintain over time than having to intersperse errorLogger.error and nonerrorLogger.info throughout my code.

@rickcrawford

@ryan-roemer I agree it should be similar to log4j's approach of having multiple loggers assigned to 1 root logger.

@darcy

+1 for this.

My example use case:

var logger = new (winston.Logger)({
    exitOnError: false, //don't crash on exception
    transports: [
        new (winston.transports.Console)(), //always use the console
        new (winston.transports.File)({ filename: 'logs/server.log' }), //log everything to the server.log
        new (winston.transports.File)({ level: 'error', filename: 'logs/error.log', handleExceptions: true }), //log errors and exceptions to the error.log
        new (winston.transports.File)({ level: 'warn', filename:'logs/warn.log' }), //log warn to the warn.log
        new (winston.transports.File)({ level: 'info', filename:'logs/info.log' }) //log info to the info.log
    ]
});
@k0nG

Yeah again +1 for this. @darcy 's use case makes sense to me. Or something like this

var winston = require('winston');
winston.add(winston.transports.File, { filename: '/path/to/logfile.log', json: false, maxsize: 10485760, level: 'info' }); 
winston.add(winston.transports.File, { filename: '/path/to/errorfile.log', json: false, maxsize: 10485760, level: 'error' }); 

Seems weird you can specify the levels with the transport but then can't add a different one for different levels.

@indexzero
winstonjs member

@k0nG Looks like a one line change? Pull-request?

@jfhbrook

Fixed ^^

@jfhbrook jfhbrook closed this Oct 19, 2012
@darcy

Awesome, thanks!

@ash211

I'm still getting this error in 0.7.2 and @stephenbeeson was asking 2mo ago at #149

Are you sure it's working?

@ash211

That test still fails for me, I don't think the other commit fixed it. I'd reopen this issue if I could

@gdbtek

@all, am I right that winston still has not support multiple File transports in one logger? In my testing, the error mesg sometimes go to warn.log file.

==> error.log <==
{"level":"error","message":"errorrrr","timestamp":"2013-08-26T18:08:33.869Z"}

==> info.log <==
{"level":"info","message":"infoooo ","timestamp":"2013-08-26T18:08:33.867Z"}
{"level":"error","message":"errorrrr","timestamp":"2013-08-26T18:08:33.869Z"}
{"level":"warn","message":"warnnnnnn","timestamp":"2013-08-26T18:08:33.869Z"}

==> warn.log <==
{"level":"error","message":"errorrrr","timestamp":"2013-08-26T18:08:33.869Z"}
{"level":"warn","message":"warnnnnnn","timestamp":"2013-08-26T18:08:33.869Z"}
@yhpark

@ash211 @gdbtek or anyone who see this thread,
You should set name field in the option. It's being used to detect duplicate transports.

new winston.transports.File({ filename: './logs/error.log', name: 'file.error', level: 'error' }),
new winston.transports.File({ filename: './logs/info.log', name: 'file.info', level: 'info' }),
new winston.transports.File({ filename: './logs/debug.log', name: 'file.debug', level: 'debug' })
@gdbtek

@yhpark and @ash211 , I actually set name and filename fields but it still does not work as expected. If anyone see what I'm missing, please let me know. Thanks.

  var fileTransportConfig = function (level, json, maxFile, maxSize, path) {
    return new (winston.transports.File)({
      colorize: true,
      filename: path,
      handleExceptions: true,
      json: json,
      level: level,
      maxFiles: maxFile,
      maxsize: maxSize,
      name: level,
      timestamp: timestampFormat
    });
  };

  fileTransportConfig('error', options.json, options.maxFile, options.maxSize, options.path.error),
  fileTransportConfig('info', options.json, options.maxFile, options.maxSize, options.path.information),
  fileTransportConfig('warn', options.json, options.maxFile, options.maxSize, options.path.warning)
@givan

How can a given transport once it logged a message to keep it only for itself and not pass it along to other transports? I want to prevent copying the same log message into multiple transports, if at least one handled it.

@indexzero indexzero reopened this Sep 23, 2014
@toddpi314

Thanks for this everyone. Works great!

@neckro

I bumped up against this issue within 5 minutes of trying to use winston in my project, and had to hunt for a solution here. The fact that winston doesn't like multiple transports of the same type isn't mentioned in the documentation, and neither is the name option.

Wanting to log different error levels to different files can't possibly be an obscure use case, and the transport docs suggest the transports are composable when in fact they rely on the transport having a unique name (which I assume defaults to the transport type's name). The docs could be much clearer on this point.

@indexzero indexzero added a commit that closed this issue Jan 6, 2015
@indexzero indexzero [api] Allow for transports to be removed by their string name
[test fix] Add test coverage for multiple transports of the same type added in #187.
[doc] Document using multiple transports of the same type

Fixes #101 (again), Fixes #301
270be86
@indexzero indexzero closed this in 270be86 Jan 6, 2015
@indexzero
winstonjs member

Fixed in master will go out in 0.9.0 once all of the 0.9.0 PRs have been merged.

@floatingLomas floatingLomas referenced this issue in bithavoc/express-winston Sep 29, 2015
Closed

Option 'statusLevels' in errorLogger #90

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment