Node.js - 记录 / 使用 morgan 和 winston

Posted

技术标签:

【中文标题】Node.js - 记录 / 使用 morgan 和 winston【英文标题】:Node.js - logging / Use morgan and 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? 【参考方案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 ));

【讨论】:

为什么很小而不是合并? 我无法再让它工作了。似乎输入不正确。 ***.com/questions/50048193/…【参考方案7】:

更新最后一行以删除警告

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

【讨论】:

以上是关于Node.js - 记录 / 使用 morgan 和 winston的主要内容,如果未能解决你的问题,请参考以下文章

Morgan(node.js):使用自定义格式时着色状态代码(如“dev”中)

尝试使用 Nodejs 库 morgan-body

需要 Morgan 和 Winston 使用 btyesize 记录 api 响应

收到请求时使用 morgan 记录 POST 正文大小

Node.js开发 ---- nodejs操作mysql

你应该如何在 TypeScript 中为 Morgan 创建 Winston 记录器流