【问题标题】:Node.js - logging / Use morgan and winstonNode.js - 记录 / 使用 morgan 和 winston
【发布时间】:2015-03-10 11:43:38
【问题描述】:

我们使用morgan 来记录我们的快速转换:

var morgan  = require('morgan');
morgan('combined');
// a format string
morgan(':remote-addr :method :url :uuid');
// a custom function
morgan(function (req, res) {
  return req.method + ' ' + req.url + ' ' + req.uuid;
})

此外,我们使用winston 来记录我们的其他日志记录:

var winston = require('winston');
var logger = new (winston.Logger)({
  transports: [
         new (winston.transports.Console)({ level: 'info' }),
          new (winston.transports.File)({ filename: '/var/log/log-file.log' })
  ]
});

有没有办法将两个记录器结合在一起?现在的情况是morgan 写入我的标准输出,而winston 写入/var/log/log-file.log

我希望记录器文件将结合快速转换信息和我想要的其他信息 (logger.info())..

【问题讨论】:

  • 这样做有什么意义,我的意思是,你为什么一开始就需要摩根,为什么不写一个winston middlewrare for express?

标签: node.js logging express winston


【解决方案1】:

受这个问题的启发,这是我易于定制的记录器。

import * as winston from "winston";
import * as morgan from "morgan";

export const logger = winston.createLogger({
  transports: [
    new winston.transports.Console({
      level: 'debug',
      handleExceptions: true,
      format: winston.format.combine(
        winston.format.timestamp({ format: 'HH:mm:ss:ms' }),
        winston.format.colorize(),
        winston.format.printf(
          (info) => `${info.timestamp} ${info.level}: ${info.message}`,
        ),
        //  winston.format.simple(),
      ),
    }),
  ],
  exitOnError: false,
});

if (process.env.NODE_ENV === "dev") {
  logger.add(
    new winston.transports.File({
      level: 'info',
      filename: './logs/all-logs.log',
      handleExceptions: true,
      format: winston.format.combine(
        winston.format.timestamp({
          format: 'YYYY-MM-DD HH:mm:ss',
        }),
        winston.format.errors({ stack: true }),
        winston.format.printf(
          (info) => `${info.timestamp} ${info.level}: ${info.message}`,
        ),
        // winston.format.splat(),
        // winston.format.json()
      ),
      maxsize: 5242880, //5MB
      maxFiles: 5,
    }));
}
logger.info("logging started");

app.use(morgan(function (tokens, req, res) {
    const msg = [
        tokens.method(req, res),
        tokens.url(req, res),
        tokens.status(req, res),
        tokens.res(req, res, 'content-length'), '-',
        tokens['response-time'](req, res), 'ms',
    ].join(' ');
    logger.http(msg);
    return null;
    // return msg;
})
);

样本输出

# console
16:32:30:3230 http: GET /users/614daca689f8773a247af93d 200 417 - 1087.858 ms 

# file 
2021-09-24 16:40:08 http: GET /users/614daca689f8773a247af93d 200 417 - 856.263 ms

【讨论】:

    【解决方案2】:

    最简单将数据记录到nodejs后端文件中的方法 @grdon/logger

    这里是例子

     const logger = require('@grdon/logger')({
      defaultLogDirectory : __dirname + "/myLogDir",
    })
    // ...
    
    logger(arg1, 'logfile1.log')
    logger([arg1, arg2 ,...], 'lofgfile2.log')
    

    【讨论】:

      【解决方案3】:

      Morgan 的坏习惯是用 \n 结束消息,因此为了使事情井井有条,您可能需要在将其写给 winston 之前将其删除。

      这可以通过多种不同的方式完成,例如在 winston 中的格式方面,或者通过更新您的流以不写入 \n

      class MyStream {
          write(text: string) {
              logger.info(text.replace(/\n$/, ''));
          }
      }
      let myStream = new MyStream()
      app.use(morgan('tiny', { stream: myStream }));
      

      【讨论】:

        【解决方案4】:

        这篇文章非常适合您想做的事情。

        http://tostring.it/2014/06/23/advanced-logging-with-nodejs/

        对于您的特定代码,您可能需要这样的东西:

        var logger = new winston.Logger({
            transports: [
                new winston.transports.File({
                    level: 'info',
                    filename: './logs/all-logs.log',
                    handleExceptions: true,
                    json: true,
                    maxsize: 5242880, //5MB
                    maxFiles: 5,
                    colorize: false
                }),
                new winston.transports.Console({
                    level: 'debug',
                    handleExceptions: true,
                    json: false,
                    colorize: true
                })
            ],
            exitOnError: false
        });
        
        logger.stream = {
            write: function(message, encoding){
                logger.info(message);
            }
        };
        
        app.use(require("morgan")("combined", { "stream": logger.stream }));
        

        这将设置 Winston 将日志和文件写入控制台。然后,您可以使用最后一个表达式将 morgan 中间件的输出传递给 winston。

        【讨论】:

        • 我们可以在这个过程中使用时间戳吗?
        • 似乎没有必要覆盖 logger.stream.. 就我而言,我能够做到 app.use(morgan("combined", { stream: { write: message => logger.info(message) }}));
        • 如果您使用@DevonSams 的方法,您将在记录的行之间得到一个空行,因为morgan 和winston 都在记录的消息末尾添加了换行符。您可以使用logger.info(message.trim()) 简单地从消息中删除换行符
        • 如果服务器响应为 500,我想使用 logger.error 而不是 logger.info 怎么办?
        • 对于winston: ^3.0.0 使用winston.createLogger 而不是new winston.Logger
        【解决方案5】:

        对于 Typescript,另一种无需创建类的方法是

        let logger = new (winston.Logger)({
            exitOnError: false,
            level: 'info',
            transports: [
                new (winston.transports.Console)(),
                new (winston.transports.File)({ filename: 'app.log'})
            ]
        })
        
        const myStream = {
            write: (text: string) => {
                logger.info(text)
            }
        }
        
        app.use(morgan('combined', { stream: myStream }));
        

        此解决方案来自此 Github 页面 https://github.com/winstonjs/winston/issues/1385。但是,重要的是要注意我们的代码之间存在细微差别。而不是:

        app.use(morgan('combined', { myStream }));
        

        我用:

        app.use(morgan('combined', { stream: myStream }));
        

        这帮助了我,因为我在创建类方面并不太擅长。

        【讨论】:

          【解决方案6】:

          在打字稿中:

          let logger = new (winston.Logger)({
              exitOnError: false,
              level: 'info',
              transports: [
                  new (winston.transports.Console)(),
                  new (winston.transports.File)({ filename: 'app.log'})
              ]
          })
          
          class MyStream {
              write(text: string) {
                  logger.info(text)
              }
          }
          let myStream = new MyStream()
          app.use(morgan('tiny', { stream: myStream }));
          

          【讨论】:

          【解决方案7】:

          更新最后一行以删除警告

          app.use(require("morgan")("combined", { stream: logger.stream }));
          

          【讨论】:

            猜你喜欢
            • 2019-06-12
            • 2015-09-17
            • 2019-11-12
            • 2015-09-26
            • 2019-11-16
            • 2019-07-03
            • 2015-04-15
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多