Перезапись метки времени в пользовательском формате Winston logger

#node.js #logging #winston

#node.js #ведение журнала #winston

Вопрос:

Я использую winston logger версии 3.3.3 в приложении узла. У меня есть пользовательский форматировщик для вывода, который выглядит следующим образом:

 const winston = require('winston');
const jsonStr = require('fast-safe-stringify');

const customFormat = winston.format.printf(data => {
    const { level, message, timestamp } = data;
    const args = data[Symbol.for('splat')];

    let strArgs = '';

    if (args) {
        strArgs = args.map(jsonStr).join(' ');
    } 

    return `${timestamp} ${level}: ${message} ${strArgs}n`;
});

logger = winston.createLogger({
    level: 'debug',
    format: winston.format.combine(winston.format.timestamp(), customFormat),
    transports: [new winston.transports.Console()]
});

logger.log('debug', 'hi', 123, { a: 1, b: 'two' });
logger.log('debug', 'hi', { timestamp: 'this is bad' });
  

Это позволяет мне регистрировать данные с несколькими аргументами разных типов:

 logger.log('debug', 'hi', 123, { a: 1, b: 'two' });
> 2020-11-11T19:01:46.942Z debug: hi 123 {"a":1,"b":"two"}
  

чего я и хочу. Проблема в том, что если я регистрирую объект, который содержит вызываемое поле timestamp , он переопределяет timestamp поле в форматере.

 logger.log('debug', 'hi', { timestamp: 'this is bad' } );
> this is bad debug: hi {"timestamp":"this is bad"}
  

Итак, теперь временная метка регистратора — это строка "this is bad" , что плохо. Если я выведу data параметр в printf() метод, я увижу это:

 {
    timestamp: 'this is bad',
    level: 'debug',
    message: 'hi',
    [Symbol(level)]: 'debug',
    [Symbol(splat)]: [ { timestamp: 'this is bad' } ] }
}
  

Итак, вы можете видеть, что timestamp поле, по-видимому, перезаписывается аргументом, который я передаю. Это происходит только в том случае, если третьим аргументом log() метода является объект с вызываемым свойством timestamp . Так что это нормально:

 logger.log('debug', 'hi', 123, { timestamp: 'this is fine' } );

data: {
    level: 'debug',
    message: 'hi',
    timestamp: '2020-11-11T19:08:27.326Z',
    [Symbol(level)]: 'debug',
    [Symbol(splat)]: [ 123, { timestamp: 'this is fine' } ]
}
> 2020-11-11T19:08:27.326Z debug: hi 123 {"timestamp":"this is fine"}
  

Это ошибка в winston или мой printf() метод неправильный?

Обратите внимание, что у меня есть репозиторий git, который воспроизводит эту проблему здесь.

Ответ №1:

ну, простое решение — добавить формат или псевдоним для временной метки timeStamp.format() следующим образом

 logger = winston.createLogger({
    level: 'debug',
    format: winston.format.combine(
        winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), // can also alias
        customFormat
    ),
    transports: [new winston.transports.Console()]
});

logger.log('debug', 'hi', { timestamp: 'this is bad' } );

// outputs
2020-11-19 20:08:36 debug: hi {"timestamp":"this is bad"}
{
  timestamp: '2020-11-19 20:08:36',
  level: 'debug',
  message: 'hi',
  [Symbol(level)]: 'debug',
  [Symbol(splat)]: [ { timestamp: 'this is bad' } ]
}
  

переходя к части объяснения, я на самом деле не уверен, почему временная метка перезаписывается, это довольно странно.

Комментарии:

1. Отлично, это работает, спасибо. Но как вы узнали, что указание формата исправит это?

2.Я этого не делал, это была дикая догадка. Я только что просмотрел один из своих проектов и обнаружил, что предоставляю формат даты. Я добавил это в ваш фрагмент, и это сработало. вот несколько полезных ссылок medium.com/@ThreePotatoteers/…github.com/winstonjs/logform#readme

Ответ №2:

Привет) Я пытался воспроизвести ваш случай, но не смог воспроизвести. Попробуйте этот код

 const winston = require('winston');

const customFormat = winston.format.printf((data) => {
  const { level, message, timestamp } = data;
  console.log('data', data);
  const args = data[Symbol.for('splat')];

  let strArgs = '';

  if (args) {
    console.log('args', args);
    strArgs = args.map((argument) => JSON.stringify(argument)).join(' ');
  }

  return `${timestamp} ${level}: ${message} ${strArgs}n`;
});

const logger = winston.createLogger({
  format: customFormat,
  transports: [
    new winston.transports.Console({
      level: 'debug',
    }),
  ],
});

logger.log('debug', 'hi', 123, { a: 1, b: 'two' });
// logger.log('debug', 'hi', { timestamp: 'this is bad' });
  

Я проверил, в первом случае временная метка не определена. Во втором случае я получил временную метку: «это плохо». Winston не передает свою собственную временную метку в мою информацию журнала.

Комментарии:

1. Это потому, что в вашем format: свойстве не указано использовать включить временную метку. Попробуйте это (извините за форматирование): const logger = winston.createLogger({ format: winston.format.combine(winston.format.timestamp(), customFormat), transports: [ new winston.transports.Console({ level: 'debug' })]});

2. Я пошел дальше и включил более полный пример кода и репозиторий git в github.com/dland512/winston-formatting-issue