如何让`winston`日志库像`console.log`一样工作?

问题描述 投票:0回答:3

winston 图书馆非常适合运输和灵活性。我想使用它来允许配置级别并重定向到文件,但想重现 console.log 行为以进行格式化,但遇到了麻烦。

这是我到目前为止所拥有的:

const log = winston.createLogger({
  level: 'debug',
  format: format.combine(
    format.timestamp({format: 'YYYY-MM-DD HH:mm:ss.SSS'}),
    format.splat(),
    format.colorize(),
    format.printf(({level, message, label, timestamp}) => `${timestamp} ${label || '-'} ${level}: ${message}`),
  ),
  transports: [
    new winston.transports.Stream({
      stream: process.stderr,
      level: 'debug',
    })
  ],
});

log.info("Hello, %s", "Bob");   // Works: outputs "Hello, Bob"

但这行不通:

log.info("Hello", "Bob");
log.info("Hello", 123, {someObj: 1});

我希望在

splat()
占用之后添加所有无关对象,以空格分隔,并最好使用
util.inspect()
转换为字符串。

javascript node.js logging winston
3个回答
28
投票

回答我自己的问题。问题在于

format.splat
——纯 util.format 提供了更简单、更符合预期的行为。将
format.splat
替换为
utilFormatter
可解决问题:

const util = require('util');

function transform(info, opts) {
  const args = info[Symbol.for('splat')];
  if (args) { info.message = util.format(info.message, ...args); }
  return info;
}

function utilFormatter() { return {transform}; }

我的问题中的例子看起来像这样:

const log = winston.createLogger({
  level: 'debug',
  format: format.combine(
    format.timestamp({format: 'YYYY-MM-DD HH:mm:ss.SSS'}),
    utilFormatter(),     // <-- this is what changed
    format.colorize(),
    format.printf(({level, message, label, timestamp}) => `${timestamp} ${label || '-'} ${level}: ${message}`),
  ),
  transports: [
    new winston.transports.Stream({
      stream: process.stderr,
      level: 'debug',
    })
  ],
});

log.info("Hello, %s", "Bob");          // Works: outputs "Hello, Bob"
log.info("Hello", "Bob");              // Works: outputs "Hello Bob"
log.info("Hello", 123, {someObj: 1});  // Works: outputs "Hello 123 { someObj: 1} "

6
投票

我遇到了类似的问题,经过多次尝试和错误,我想我有一个您可能感兴趣的解决方案。正如我在上次更新中提到的,我们最终构建了自己的记录器。好吧,周末我将这个记录器发布到了 npm,欢迎您查看。

它的输出应该与

console.log
或多或少相同。如果您发现任何不一致之处,请告诉我。

它还具有多种传输方式,您甚至可以传递自定义传输方式,甚至可以“包装”控制台功能以快速集成到您的项目中。

示例代码:

const {createLogger,wrapConsole,unwrapConsole} = require('@r3wt/log');
const log = createLogger({log_level:'info',transports:['console','file']});
wrapConsole(log);//wraps the console globally with the log instance, making integration into large existing project less painful

// NOTE: only the following 4 functions are wrapped. 
console.log('hi!');
console.warn('warning');
console.error('error');
console.info('info');

unwrapConsole();//unwrap console globally

如果您感兴趣,您可以在here找到该库以及更多代码示例和基本文档,并且欢迎和鼓励提供功能和修复的 PR。代码是 MIT,所以你可以自由分叉并创建你自己的版本:-)

祝你好运,我希望这会有所帮助。


0
投票

大部分摘自@D.S.的回答,添加了:

  • 使用 Typescript 和 ES 模块
  • 注释,处理第一个参数的格式
  • 使用 Winston
    Filtering 
    format Object
     文档中提到的 
    info
    函数(我并没有真正理解
    {transport}
    对象的魔力)
import { Logger, createLogger, transports, format } from 'winston';
import { TransformFunction } from 'logform';
import util from 'util';

const transform: TransformFunction = (info) => {
  const args = info[Symbol.for('splat')];
  const { message: rawMessage } = info;
  // Combine all the args with util.format
  // also do a util.format of the rawMessage which handles JSON
  const message = args ? util.format(rawMessage, ...args) : util.format(rawMessage);
  return {
    ...info,
    message,
  };
};

const utilFormatter = format(transform);

const log: Logger = createLogger({
  level: config?.logLevel || process.env.LOG_LEVEL || 'info',
  transports: [new transports.Console()],
  format: format.combine(
    format.timestamp({format: 'YYYY-MM-DD HH:mm:ss.SSS'}),
    utilFormatter(),
    format.colorize(),
    format.printf(({level, message, label, timestamp}) => `${timestamp} ${label || '-'} ${level}: ${message}`),
  ),
});

log.info("Hello, %s", "Bob");          // Works: outputs "Hello, Bob"
log.info("Hello", "Bob");              // Works: outputs "Hello Bob"
log.info("Hello", 123, {someObj: 1});  // Works: outputs "Hello 123 { someObj: 1 }"
log.info([{a:1}]);                     // Works: outputs "[ { a: 1 } ]"
© www.soinside.com 2019 - 2024. All rights reserved.