【问题标题】:How are you supposed to create Winston logger stream for Morgan in TypeScript你应该如何在 TypeScript 中为 Morgan 创建 Winston 记录器流
【发布时间】:2018-10-07 11:03:12
【问题描述】:

在 TypeScript 中创建将记录快速 Morgan 中间件日志记录的 winston 记录器的正确方法是什么?我找到了一些 JavaScript 示例,但在将它们转换为 TypeScript 时遇到了麻烦,因为我收到了一个错误 Type '{ write: (message: string, encoding: any) => {}; logger: any; }' is not assignable to type '(options?: any) => ReadableStream'. Object literal may only specify known properties, and 'write' does not exist in type '(options?: any) => ReadableStream'.

这是我的代码:

import { Logger, transports } from 'winston';

// http://tostring.it/2014/06/23/advanced-logging-with-nodejs/
// https://www.loggly.com/ultimate-guide/node-logging-basics/

const logger = new Logger({
    transports: [
        new (transports.Console)({
            level: process.env.NODE_ENV === 'production' ? 'error' : 'debug',
            handleExceptions: true,
            json: false,
            colorize: true
        }),
        new (transports.File)({
            filename: 'debug.log', level: 'info',
            handleExceptions: true,
            json: true,
            colorize: false
        })
    ],
    exitOnError: false,
});



if (process.env.NODE_ENV !== 'production') {
    logger.debug('Logging initialized at debug level');
}



// [ts]
// Type '{ write: (message: string, encoding: any) => {}; logger: any; }' is not assignable to type '(options?: any) => ReadableStream'.
//   Object literal may only specify known properties, and 'write' does not exist in type '(options?: any) => ReadableStream'.
logger.stream = {
    write: function (message: string, encoding: any) {
        logger.info(message);
    };
}


export default logger;

我已经能够通过调整我的代码以使用 const winston = require('winston'); 来解决此问题,但想知道您应该如何维护类型?

【问题讨论】:

    标签: node.js typescript winston morgan


    【解决方案1】:

    如果您将 TypeScript 类用于记录器,则可以声明一个 stream() 函数,该函数从 morgan 返回 StreamOptions 类型:

    import { StreamOptions } from 'morgan';
    
    //...rest of the class code
    
    public stream(): StreamOptions {
    return {
      write: (message: string): void => {
        this.info(message.trim());
      }
    };
    

    然后你可以在 express 中间件中使用这个流函数:

    app.use('combined', { stream: this.logger.stream()})
    

    【讨论】:

      【解决方案2】:

      最终我以这个作为解决方案。我用一种叫做 write 的方法创建了一个类

      export class LoggerStream {
          write(message: string) {
              logger.info(message.substring(0, message.lastIndexOf('\n')));
          }
      }
      

      然后在添加到 express 时,我创建了一个类的实例:

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

      这很适合我的情况

      【讨论】:

        【解决方案3】:

        感谢@estus 让我摆脱了挂断电话。这是我最终使用的解决方案:

        import { Logger, transports } from 'winston';
        import stream from 'stream';
        import split from 'split';
        
        // http://tostring.it/2014/06/23/advanced-logging-with-nodejs/
        // https://www.loggly.com/ultimate-guide/node-logging-basics/
        
        const logger = new Logger({
            transports: [
                new (transports.Console)({
                    level: process.env.NODE_ENV === 'production' ? 'error' : 'debug',
                    handleExceptions: true,
                    json: false,
                    colorize: true
                }),
                new (transports.File)({
                    filename: 'debug.log', level: 'info',
                    handleExceptions: true,
                    json: true,
                    colorize: false
                })
            ],
            exitOnError: false,
        });
        
        if (process.env.NODE_ENV !== 'production') {
            logger.debug('Logging initialized at debug level');
        }
        
        logger.stream = split().on('data', function (message: string) {
            logger.info(message);
        });
        
        export default logger;
        

        最终这个问题让我找到了最终的解决方案 - https://github.com/expressjs/morgan/issues/70

        【讨论】:

          【解决方案4】:

          stream 应该是返回流的工厂函数,而不是流本身。

          流应该是真正可读的流,而不是模仿它的对象。

          既然它也应该是可写的,它应该是双工的:

          logger.stream = (options?: any) => new stream.Duplex({
              write: function (message: string, encoding: any) {
                  logger.info(message);
              }
          });
          

          这是 Winston TS types 建议的解决方案。我无法确认它是否正常工作。

          【讨论】:

          • 感谢您的回复,它不太有效,您能指出您在哪里找到此信息吗?我导入了流import stream from 'stream'; 然后更改了我的代码以匹配您提供的内容。我收到TypeError: stream.write is not a function at logRequest (C:\projects\node-service-starter\node_modules\morgan\index.js:130:14)
          • 我检查了温斯顿的打字,github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/…。类型总是有可能是错误的。如果您确定 logger.stream = {..} 适用于您的情况,您可以随时拒绝类型检查并执行 logger.stream = <any>{..}
          • 好的...我找到了解决方案 - 这就是我最终要做的。我拉入拆分包并编写了我的 logger.stream 如下logger.stream = split().on('data', function (message: string) { logger.info(message); }); 我在弄清楚如何在控制台中删除额外的新行时发现了这个信息。 github.com/expressjs/morgan/issues/70
          • 我开始怀疑打字有问题,因为当创建一个 morgan.Options 对象然后将它传递给 morgan 构造函数时,你会得到一个 TS 错误。听起来他们将在 morgan 3 中捆绑打字。我必须添加 // @ts-ignore 以解决问题 // @ts-ignore const morganOptions: morgan.Options = { stream: logger.stream }; app.use(morgan('combined', morganOptions));
          • 和这个博客一起为我工作loggly.com/ultimate-guide/node-logging-basics
          猜你喜欢
          • 2015-09-26
          • 2019-06-12
          • 2015-03-10
          • 2019-11-16
          • 2019-11-12
          • 2018-07-19
          • 2015-09-17
          • 2021-09-14
          • 1970-01-01
          相关资源
          最近更新 更多