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

Posted

技术标签:

【中文标题】你应该如何在 TypeScript 中为 Morgan 创建 Winston 记录器流【英文标题】:How are you supposed to create Winston logger stream for Morgan in TypeScript 【发布时间】: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'); 来解决此问题,但想知道您应该如何维护类型?

【问题讨论】:

【参考方案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

以上是关于你应该如何在 TypeScript 中为 Morgan 创建 Winston 记录器流的主要内容,如果未能解决你的问题,请参考以下文章

如何在 TypeScript 中为对象动态分配属性?

如何在 TypeScript 中为类属性动态分配值

如何在 TypeScript 中为 css 模块设置汇总

我们如何在 TypeScript 中为非全局接口创建扩展方法?

如何在 React Native 中为 useRef 钩子设置 Typescript 类型?

如何在 typescript 中为泛型类编写扩展作为 getter