Winston: Похоже, 3.0 регистрирует {} для объектов ошибок

Созданный на 19 мар. 2018  ·  12Комментарии  ·  Источник: winstonjs/winston

Всем привет
У меня возникли проблемы с тем, что winston 3.0 регистрирует пустые объекты ошибок, когда он использует формат json.

module.exports = winston.createLogger({
  format: format.combine(
    format.label({ label: 'my label'}),
    format.timestamp(),
    format.prettyPrint()
  ),
  transports: [
    new (winston.transports.Console)({
      level: error
    })
  ]
}); 

регистрирует ожидаемый

 {error: [stack trace here] }
 ```

 while 

module.exports = winston.createLogger ({
формат: format.combine (
format.label ({label: 'мой ярлык'}),
format.timestamp (),
format.json ()
),
транспорты: [
новый (winston.transports.Console) ({
уровень: ошибка
})
]
});

logs the erroneous

{ошибка: {} }

when it is passed 

logger.log ({
error: new Error ('мое сообщение об ошибке')
});

Manually creating a format with 

winston.format.printf
`` ''
также вернул ошибочный результат.

Кто-нибудь знает обходной путь для этого?

Самый полезный комментарий

Более лаконичная версия:

function format() {
  const replaceError = ({ label, level, message, stack }) => ({ label, level, message, stack });
  const replacer = (key, value) => value instanceof Error ? replaceError(value) : value;
  return combine(label({ label: 'ssr server log' }), format.json({ replacer }));
}

const logger = createLogger({
  format: format(),
});

Но это то, что я на самом деле делаю, чтобы иметь красивые логи локально и ошибки JSON в продакшене:

function prodFormat() {
  const replaceError = ({ label, level, message, stack }) => ({ label, level, message, stack });
  const replacer = (key, value) => value instanceof Error ? replaceError(value) : value;
  return combine(label({ label: 'ssr server log' }), format.json({ replacer }));
}

function devFormat() {
  const formatMessage = info => `${info.level} ${info.message}`;
  const formatError = info => `${info.level} ${info.message}\n\n${info.stack}\n`;
  const format = info => info instanceof Error ? formatError(info) : formatMessage(info);
  return combine(colorize(), printf(format))
}

const logger = createLogger({
  level: process.env.LOG_LEVEL || 'info',
  exitOnError: false,
  transports: [new transports.Console()],
  format: isProd ? prodFormat() : devFormat(),
});

что дает мне это в производстве

bildschirmfoto 2018-09-21 um 16 46 35

и это в разработке

bildschirmfoto 2018-09-21 um 16 47 04

Все 12 Комментарий

Обходной путь:

function errorReplacer(key, value) {
  if (value instanceof Error) {
    return { message: value.message, stack: value.stack };
  }
  return value;
}

const logFormat = winston.format.printf((info) => {
  return `${JSON.stringify(info, errorReplacer)}`;
});

module.exports = winston.createLogger({
  format: format.combine(
    format.label({ label: 'my label' }),
    format.timestamp(),
    logFormat
  ), ...

Надеюсь, это поможет.

У меня не сработало обходное решение (где-то теряется информация. Сообщение)

Вариант обходного пути:

const winston = require('winston')
const MESSAGE = Symbol.for('message')

/*
 * function replacer (key, value)
 * Handles proper stringification of Buffer output.
 */
const replacer = function (key, value) {
  return value instanceof Buffer
    ? value.toString('base64')
    : value
}

var json_log = winston.format(function (info, opts) {
  var display = info
  if (info._error) {
    display = Object.assign({}, info, { message: info._error })
    delete display._error
  }
  info[MESSAGE] = JSON.stringify(display, opts.replacer || replacer, opts.space)
  return info
})

var preserve_error_message = format(function (info, opts) {
  if (_.isError(info)) {
    info._error = info.message
  }
  return info
})

const logger = winston.createLogger({
  levels: ...,
  format: format.combine(format.timestamp(), preserve_error_message()),
  transports: [
    new transports.Console({
    level: this.config.console.level,
    format: json_log({ space: 2 })
  })
]

Это не кажется особенно элегантным, поэтому было бы идеальным сохранить info.message когда info - это Error (это работает, когда info является обычным Объект)

Я тоже сталкиваюсь с этим. Разве Winston не должен справиться с этим из коробки? @indexzero что ты об этом думаешь?

Посмотрев на реализацию json logform, я теперь вижу, как предполагается использовать opts.replacer, и я придумал другое решение при объединении этого сообщения stackoverflow с существующей строковой настройкой буфера:

'use strict';

const winston = require('../');

const logger = winston.createLogger({
    format: winston.format.combine(
        winston.format.json({ replacer: replaceErrors })
    ),
    transports: [
        new winston.transports.Console(),
    ]
});

function replaceErrors(key, value) {
    if (value instanceof Buffer) {
        return value.toString('base64');
    } else if (value instanceof Error) {
        var error = {};

        Object.getOwnPropertyNames(value).forEach(function (key) {
            error[key] = value[key];
        });

        return error;
    }

    return value;
}


var error = new Error('foooo');
error.my_custom_stuff = 'bar';

logger.log('error', 'Hello, this is a raw logging event', { error });

который печатает:

{"error":{"stack":"Error: foooo\n    at Object.<anonymous> (/home/dino/work/winston/examples/json.js:31:13)\n    at Module._compile (module.js:662:30)\n    at Object.Module._extensions..js (module.js:673:10)\n    at Module.load (module.js:575:32)\n    at tryModuleLoad (module.js:515:12)\n    at Function.Module._load (module.js:507:3)\n    at Function.Module.runMain (module.js:703:10)\n    at startup (bootstrap_node.js:193:16)\n    at bootstrap_node.js:660:3","message":"foooo","my_custom_stuff":"bar"},"level":"error","message":"Hello, this is a raw logging event"}

Я больше не думаю, что с этим следует обращаться нестандартно, потому что я думаю, что библиотека ведения журнала не должна определять, как ваша ошибка должна быть сериализована в сообщение журнала, вы определяете это сами.

Не уверен в вашем конкретном варианте использования, но почему вы не регистрируете ошибки напрямую:

logger.log(new Error('my error message'));

(Это работает с https://github.com/winstonjs/winston/pull/1234).

Если вам действительно нужен объект ошибки внутри более крупного объекта, который вы регистрируете, то стоит отметить, что Node.js Errors не являются объектами JSON, но есть такие вещи, как https://www.npmjs.com/package / utils-error-to-json или, возможно, сделать parse(stringify(error)) , который заставит эту работу работать с форматером JSON. Похоже, что именно это и делает решение

Собираясь отметить это закрытым, не стесняйтесь открывать повторно или создавать новый выпуск, если возникнут новые проблемы / вопросы! Спасибо!

Даже parse(stringify(error)) работает, поскольку вы все равно теряете трассировку стека.
Мне удалось выполнить эту работу, создав специальный модуль форматирования, подобный этому:

const formatErrorConverter = winston.format(
    info =>
        info instanceof Error
            ? Object.assign({ level: info.level, message: info.message, stack: info.stack }, info)
            : info,
);

И работает неплохо!

instance of Error работает только для средства форматирования верхнего уровня. Это НЕ работает для форматеров транспортного уровня. Кто-нибудь может объяснить почему?

Более лаконичная версия:

function format() {
  const replaceError = ({ label, level, message, stack }) => ({ label, level, message, stack });
  const replacer = (key, value) => value instanceof Error ? replaceError(value) : value;
  return combine(label({ label: 'ssr server log' }), format.json({ replacer }));
}

const logger = createLogger({
  format: format(),
});

Но это то, что я на самом деле делаю, чтобы иметь красивые логи локально и ошибки JSON в продакшене:

function prodFormat() {
  const replaceError = ({ label, level, message, stack }) => ({ label, level, message, stack });
  const replacer = (key, value) => value instanceof Error ? replaceError(value) : value;
  return combine(label({ label: 'ssr server log' }), format.json({ replacer }));
}

function devFormat() {
  const formatMessage = info => `${info.level} ${info.message}`;
  const formatError = info => `${info.level} ${info.message}\n\n${info.stack}\n`;
  const format = info => info instanceof Error ? formatError(info) : formatMessage(info);
  return combine(colorize(), printf(format))
}

const logger = createLogger({
  level: process.env.LOG_LEVEL || 'info',
  exitOnError: false,
  transports: [new transports.Console()],
  format: isProd ? prodFormat() : devFormat(),
});

что дает мне это в производстве

bildschirmfoto 2018-09-21 um 16 46 35

и это в разработке

bildschirmfoto 2018-09-21 um 16 47 04

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

const replacer = (key, value) => {
  if (value instanceof Error) {
    return Object.getOwnPropertyNames(value).reduce((all, valKey) => {
      if(valKey === 'stack') {
        return {
          ...all,
          at: value[valKey].split('\n').filter(va => va.trim().slice(0, 5) != 'Error').map((va, i) => `stack ${i} ${va.trim().slice(3).trim()}`)
        }
      } else {
        return {
          ...all,
          [valKey]: value[valKey]
        }
      }

    }, {});

  } else {
    return value;
  }
}

результат:

{"at":["stack 0 /Users/sarahriehl/Documents/code/boilerplate/logging/routes/log.js:24:15","stack 1 Layer.handle [as handle_request] (/Users/sarahriehl/Documents/code/boilerplate/logging/node_modules/express/lib/router/layer.js:95:5)","stack 2 next (/Users/sarahriehl/Documents/code/boilerplate/logging/node_modules/express/lib/router/route.js:137:13)","stack 3 Route.dispatch (/Users/sarahriehl/Documents/code/boilerplate/logging/node_modules/express/lib/router/route.js:112:3)","stack 4 Layer.handle [as handle_request] (/Users/sarahriehl/Documents/code/boilerplate/logging/node_modules/express/lib/router/layer.js:95:5)","stack 5 /Users/sarahriehl/Documents/code/boilerplate/logging/node_modules/express/lib/router/index.js:281:22","stack 6 Function.process_params (/Users/sarahriehl/Documents/code/boilerplate/logging/node_modules/express/lib/router/index.js:335:12)","stack 7 next (/Users/sarahriehl/Documents/code/boilerplate/logging/node_modules/express/lib/router/index.js:275:10)","stack 8 Function.handle (/Users/sarahriehl/Documents/code/boilerplate/logging/node_modules/express/lib/router/index.js:174:3)","stack 9 router (/Users/sarahriehl/Documents/code/boilerplate/logging/node_modules/express/lib/router/index.js:47:12)"],"message":"argh!!!","level":"error","timestamp":"Thu 2019-02-14 01:58:58 -0600"}

Я сделал пример для локальной среды разработки и GCP Stackdriver Logging .

https://github.com/mrdulin/blog/issues/75

Я столкнулся с той же проблемой, поэтому написал этот пакет utils-deep-clone . Проверить это.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги