当逗号用作连接运算符时,Winston 不显示文本

Winston not displaying text when comma is used as concatenation operator

我的项目现在正在使用 winston logger 来记录到控制台。问题是,逗号在大多数地区被用作连接运算符, 喜欢logger.info("here is data", data )

数据始终是一个字符串,但记录的只是 "here is data" 而不是其他内容。

项目在大多数地方都使用逗号作为连接符,因此用“+”替换是乏味的。请赞成如何在逗号本身存在的情况下显示数据

你基本上有两种解决方法

1) 手动更改您的 logger.info 函数以获取多个参数,或者编写一个记录器包装器,在传递给 logger.info

之前连接字符串
info = (...args) => {
   const data = args.reduce((acc, item) => acc += item);
   // or such kind of manual concatenation logic
   logger.info(data);
}

2) 使用 es6 模板文字。所以不要使用 logger.info("here is data", data),而是使用

logger.info(`here is data ${data}`)

根据 Pressana 的回答,在我的 createLogger 函数中,它负责创建 winston 记录器并将其导出到需要记录的模块,我创建了一个记录器中间件。

这是一个例子

let env;

exports.createLogger = (envP) => {
  env = envP;
  const logger = winston.createLogger({
    level: 'debug',
    transports: [
      new winston.transports.File({
        filename: __dirname + '/error.log',
        level: 'error'
      }),
      new winston.transports.File({
        filename: __dirname + '/combined.log'
      })
    ],
    'colorize': true
  });

  const customLogger = getCustomLoggerMiddleware(logger);

  if (env !== 'production') {
    logger.add(new winston.transports.Console({
      format: winston.format.simple()
    }));
  }
  return customLogger;
}

function getCustomLoggerMiddleware(logger) {
  const customLogger = {};
  customLogger.error = reduceLogger(logger.error)
  customLogger.warn = reduceLogger(logger.warn)
  customLogger.info = reduceLogger(logger.info)
  customLogger.http = reduceLogger(logger.http)
  customLogger.verbose = reduceLogger(logger.verbose)
  customLogger.debug = reduceLogger(logger.debug)
  customLogger.silly = reduceLogger(logger.silly)
  return customLogger;
}

function reduceLogger(loggerFun) {
  return (...args) => {
    const data = args.reduce((acc, item) => acc += item);
    loggerFun(data);
  }
}

createLogger 函数是一个普通的 winston logger 构建器,魔法发生在 getCustomLoggerMiddleware

扩展 Mauricio 的回答是另一种观点。 区别在于它还记录了数组、对象(包括循环)。

logger.jsm

const path = require('path');
const winston = require('winston');
const safeStringify = require('fast-safe-stringify'); // comes with winston

const logger = (forceDev) => {
  //

  const DEVELOPMENT = forceDev || (process.env.NODE_ENV === 'development');

  const logger = winston.createLogger({
    level: (DEVELOPMENT) ? 'silly' : 'info',
    levels: winston.config.npm.levels,
    format: winston.format.combine(
      winston.format.timestamp(),
      winston.format.align(),
      winston.format.printf((info) => `${info.timestamp} [${info.level}] ${info.message}`)
    ),
    transports: DEVELOPMENT
      ? [
        // Output logs to console
        new winston.transports.Console({
          format: winston.format.combine(
            winston.format.colorize(),
            winston.format.timestamp(),
            winston.format.align(),
            winston.format.printf((info) => `${info.timestamp} [${info.level}] ${info.message}`)
          )
        })
      ]
      : [
        // Write all logs to files
        // With level `error` and below to `error.log`
        new winston.transports.File({
          filename: path.join(__dirname, '../logs/winston-error.log'),
          level: 'error'
        }),
        // With level `info` and below to `combined.log`
        new winston.transports.File({
          filename: path.join(__dirname, '../logs/winston-combined.log')
        })
      ]
  });

  process.on('unhandledRejection', (error) => {
    logger.error(error.stack);
  });

  process.on('uncaughtException', (error) => {
    logger.error(error.stack);
  });

  const wrapperFcn = (orgFcn, ...args) => {
    orgFcn(
      args
        // .filter((arg) => arg !== 'whatever') // custom filter
        .reduce((previous, current) => {
          const replacer = null;
          const space = null;
          return `${previous} ${(typeof current === 'string' || current instanceof String) ? current : safeStringify(current, replacer, space)}`;
        }, '')
    );
  };

  const getWrappedLogger = (loggerOrgObj) => {
    const wrappedObject = Object.create(loggerOrgObj);
    Object.assign(wrappedObject, {
      error: wrapperFcn.bind(wrapperFcn, loggerOrgObj.error),
      warn: wrapperFcn.bind(wrapperFcn, loggerOrgObj.warn),
      info: wrapperFcn.bind(wrapperFcn, loggerOrgObj.info),
      http: wrapperFcn.bind(wrapperFcn, loggerOrgObj.http),
      verbose: wrapperFcn.bind(wrapperFcn, loggerOrgObj.verbose),
      debug: wrapperFcn.bind(wrapperFcn, loggerOrgObj.debug),
      silly: wrapperFcn.bind(wrapperFcn, loggerOrgObj.silly)
    });
    return wrappedObject;
  };

  return getWrappedLogger(logger);
};

module.exports = logger;

index.js

const logger = require('./logger.jsm')(true);

const circ = {x: 1};
circ.circ = circ;

// example of non-overridden method, which still works
logger.log({
  level: 'info',
  message: 'Logger launching.'
});

// examples of overridden methods, new behaviour
logger.error('This', 'is', 'log', 'level', 'error', 1, [2, 3], true, {foo: 'bar'}, circ);
logger.warn('This', 'is', 'log', 'level', 'warn', 1, [2, 3], true, {foo: 'bar'}, circ);
logger.info('This', 'is', 'log', 'level', 'info', 1, [2, 3], true, {foo: 'bar'}, circ);
logger.http('This', 'is', 'log', 'level', 'http', 1, [2, 3], true, {foo: 'bar'}, circ);
logger.verbose('This', 'is', 'log', 'level', 'verbose', 1, [2, 3], true, {foo: 'bar'}, circ);
logger.debug('This', 'is', 'log', 'level', 'debug', 1, [2, 3], true, {foo: 'bar'}, circ);
logger.silly('This', 'is', 'log', 'level', 'silly', 1, [2, 3], true, {foo: 'bar'}, circ);

// console.log comparison
console.log('This', 'is', 'pure', 'console', 'test', 1, [2, 3], true, {foo: 'bar'}, circ);