如何使用Winston将日志发送到不同的传输?

时间:2016-10-19 08:05:25

标签: node.js logging winston

我在系统中发生了不同的事件,并希望将其中一些事件记录到一个文件中,将其他事件记录到另一个文件中。

例如:

  • 服务器事件如'start','stop'将转到'server.log',并使用名为'ServerLogger'的传输。
  • 用户事件'login','logout','register'将与UsersLogger放在'users.log'中
  • “付费”,“拒绝”等付款事件将在PaymentsLogger的“payments.log”中显示。

在系统中我会运行它:

logger.log(ServerLogger, 'start');
logger.log(UsersLogger, 'login','john');
logger.log(PaymentsLogger, 'paid','100', 'john');

如何让它像这样工作,这样当我想登录某个特定的记录器时,它会被使用?

我应该将每个记录器注册为像这样的新winston实例吗?

const serverLogger = new winston.Logger()
const usersLogger = new winston.Logger()
const paymentsLogger = new winston.Logger()

2 个答案:

答案 0 :(得分:0)

虽然它可能不是完美的解决方案,但我发现自己处于类似情况。我有不同的文件可能活动也可能不活动,管理应用程序的不同部分。

我的解决方案是让我自己拥有"记录器,基于温斯顿。由于每个源代码文件都需要一个记录器来记录不同的文件,并且需要一个" common"文件,我做了一个"生成器"我打电话而不是直接要求温斯顿:

log.js:

'use strict';

const util = require('util'),
    winston = require('winston'),
    config = require('./config.json');

//If I don't want to log in files and only in console
let testMode = (config.log.mode === 'test');

//"Common" log file
const fileTransport = new (winston.transports.File)({
        timestamp: true,
        name: config.log.all.file,
        filename: config.log.all.file,
        level: config.log.all.level
    }),
//"Common" error log file
    errorTransport = new (winston.transports.File)({
        timestamp: true,
        name: config.log.error.file,
        filename: config.log.error.file,
        level: 'error'
    });

//Logs are also sent in mongoDB, with the same schema as in the files
let mongoTransport = {},
    mongoErrorTransport = {};

if(!testMode) {
    //Add winston.transport.MongoDB
    require('winston-mongodb');

    mongoTransport = new (winston.transports.MongoDB)({
        name: 'all',
        host: config.log.db.host,
        safe: config.log.db.safe,
        collection: 'all',
        level: config.log.all.level,
        db: config.log.db.db
    });
    mongoErrorTransport = new (winston.transports.MongoDB)({
        name: 'error',
        host: config.log.db.host,
        safe: config.log.db.safe,
        collection: 'error',
        level: 'error',
        db: config.log.db.db
    });
}

function getTransports(file) {
    let transports = [];

//Log in the console
    transports.push(new (winston.transports.Console)({
        timestamp: true,
        level: config.log.all.level,
        formatter: (args) => {
            let d = new Date();
            return d.getFullYear() +
                    '/' + d.getMonth(), +
                    '/' + d.getDate(), +
                    ' ' + d.getHours(), +
                    ':' + d.getMinutes(), +
                    ':' + d.getSeconds(), +
                    ':' + d.getMilliseconds(), +
                    ' - ' + file +
                    ' - ' + args.level + 
                    ' -\t' + args.message + 
                    '\t' + util.inspect(args.meta);
        }
    }));

    if(testMode) {
        return transports;
    }

    let name,
        level,
        filename;

    transports.push(fileTransport);
    transports.push(errorTransport);
    transports.push(mongoTransport);
    transports.push(mongoErrorTransport);

//Module specific logs

    if(config.log[file] && config.log[file].file) {
        name = config.log[file].file;
    } else {
        name = file;
    }
    if(config.log[file] && config.log[file].level) {
        level = config.log[file].level;
    } else if(config.log.default && config.log.default.level) {
        level = config.log.default.level;
    } else {
        level = 'info';
    }
    if(config.log[file] && config.log[file].file) {
        filename = config.log[file].file;
    } else if(config.log.default && config.log.default.file) {
        filename = config.log.default.path + file + '.log';
    } else if(config.log.default && config.log.default.path) {
        filename = config.log.default.file;
    } else {
        filename = './log/' + file + '.log';
    }

//Module specific log file

    transports.push(new (winston.transports.File)(
        {
            timestamp: true,
            name: name,
            level: level,
            filename: filename
        }
    ));

//Module specific Mongo collection for logs

    transports.push(new (winston.transports.MongoDB)({
        name: 'mongo' + file,
        host: config.log.db.host,
        safe: config.log.db.safe,
        collection: file,
        level: level,
        db: config.log.db.db
    }));

    return transports;
}

//Generator
module.exports = (file) => {
    let transports = getTransports(file);
    return new (winston.Logger)({
        rewriters: [
            (level, msg, meta) => {
                meta.app = file + '.js';
                return meta;
            }
        ],
        transports: transports
    });
};

被称为:

'use strict';

const Logger = require('./log.js'),
    logger = Logger('myModule');

logger.debug('Hi');
logger.error('Oops');

虽然它远非一个完美的解决方案,并且可能不适用于您的特定问题,但类似的东西可能比手动创建每个记录器更清晰。

答案 1 :(得分:0)

想出了一个稍微不同的解决方案,它可以解决类似但不匹配的问题。我想将作业开始和完成的两条日志消息发送到 cloudwatch,同时在进程运行时做更多的日志记录,以不同的方式处理。 (cloudwatch 环境与我们的监控有关,我们有几百个作业通过 cloudwatch 报告失败)。

因此,当我将日志记录到 cloudwatch 时,我只是添加和删除传输:

function logSomethingForMonitoring(msg){
  try{
      parentLogger.add(cloudwatch)
      parentLogger.info(msg)
  } finally {
    parentLogger.remove(cloudwatch)
  }
}

我怀疑这不是超级性能,所以它可能是正常日志的最佳解决方案,但如果这不是正常日志,它似乎工作正常。还没有真正测试过,因为就像我说的,我只将它用于两条消息。