Уинстон не отображает детали ошибки

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

Вот мой код для настройки winston:

// Create logger
const logger = winston.createLogger()

// Create timestamp format
const tsFormat = () => (new Date()).toLocaleTimeString()

// Attach transports based on app mode
if (process.env.APP_MODE === 'production') {
  // Log to file
  logger.add(new (winston.transports.DailyRotateFile)({
    filename: path.join(__dirname, '../logs/errors-%DATE%.log'),
    datePattern: 'YYYY-MM-DD-HH',
    zippedArchive: true,
    format: winston.format.json(),
    handleExceptions: true
  }))
} else {
  // Log to the console
  logger.add(new (winston.transports.Console)({
    timestamp: tsFormat,
    colorize: true,
    handleExceptions: true
  }))
}

module.exports = logger

Я также использую Express и в моем промежуточном программном обеспечении обработки ошибок у меня есть этот код:

const logger = require('../config/winston')
function (err, req, res, next) {
    console.log(err)
    logger.error(err)
    res.status(500).send({ error: 'Please try again later.' })
}

Проблема в том, что при возникновении ошибки все winston логи это:

{ "Уровень": "ошибка"}

Пока старый добрый console.log() дисплеи:

TypeError: Cannot read property 'filename' of undefined
    at router.post (/Users/balazsvincze/Desktop/testapi/app/routes/upload.js:16:33)
    at Layer.handle [as handle_request] (/Users/de/Desktop/testapi/node_modules/express/lib/router/layer.js:95:5)
    at next (/Users/balazsvincze/Desktop/testapi/node_modules/express/lib/router/route.js:137:13)
    at Immediate.<anonymous> (/Users/balazsvincze/Desktop/testapi/node_modules/multer/lib/make-middleware.js:53:37)
    at runCallback (timers.js:814:20)
    at tryOnImmediate (timers.js:768:5)
    at processImmediate [as _immediateCallback] (timers.js:745:5)

Как я могу получить winston войти что-то вроде этого, включая трассировку стека?

Большое спасибо!

РЕДАКТИРОВАТЬ: если я изменю строку logger.error(err) на logger.error(err.message), по крайней мере, я получу это:

{"message": "Невозможно прочитать свойство 'filename' из undefined", "level":"error"}

Все еще очень далеко от того, что я после.

5 ответов

Я думаю, что тебе не хватает format.errors({ stack: true }) в winston.createLogger.

const logger = winston.createLogger({
  level: 'debug',
  format: format.combine(
    format.errors({ stack: true }),
    print,
  ),
  transports: [new transports.Console()],
});

Смотрите эту ветку GitHub для получения дополнительной информации.

Причина этого в том, что интересный Error свойства объекта, например .stack, не перечислимы. Некоторые функции проверяют, соответствуют ли их параметрыError экземпляры, такие как console.error, а другие функции игнорируют все неперечислимые свойства, например winston.<log-level> а также JSON.stringify.

> console.error(new Error('foo'))
Error: foo
    at repl:1:15
    at Script.runInThisContext (vm.js:124:20)
    ...(abbr)

> JSON.stringify(new Error('foo'))
'{}'

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

Быстрый и грязный способ будет войти err.stack:

logger.error(err.stack);

Более сложным методом будет реализация специального формата специально для Error экземпляров. В этом выпуске Github приведен пример кода.

Используя формат.

const { combine, timestamp, label, printf } = winston.format;
const myFormat = printf(info => {
    if(info instanceof Error) {
        return `${info.timestamp} [${info.label}] ${info.level}: ${info.message} ${info.stack}`;
    }
    return `${info.timestamp} [${info.label}] ${info.level}: ${info.message}`;
});
winston.createLogger({
    level: "info",
    format: combine(
        winston.format.splat(),
        label({ label: filename}),
        timestamp(),
        myFormat,
    ),
    transports: [
    //
    // - Write to all logs with level `info` and below to `combined.log`
    // - Write all logs error (and below) to `error.log`.
    //
        new winston.transports.File({ filename: path.join(os.tmpdir(), "test", "test.log"), level: "info" }),
    ],
});

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

Вы должны убедиться, что когда вы выполняете деструктурирование массива для формата, вы включаете «ошибки».

      const { combine, timestamp, json, errors } = format;

В документации Winston говорится

Формат ошибок позволяет передавать экземпляр ошибки JavaScript непосредственно в регистратор. Это позволяет вам указать, следует ли включать трассировку стека.

      const errorsFormat = errors({ stack: true })

Полный код ниже приведен для справки. Это модуль, который я использую для записи некоторой информации в файл и некоторой в базу данных mysql.

      require('dotenv').config();
const {createLogger, transports, format} = require('winston');
const { combine, timestamp, json, errors } = format;
const winstonMysql = require('winston-mysql');
const logform  = require('logform');


const errorsFormat = errors({ stack: true })


const options_default = {
    host: 'localhost',
    user: process.env.MYSQL_USER,
    password: process.env.MYSQL_LOGIN,
    database: process.env.MYSQL_DATABASE,
    table: 'sys_logs_default'
};

const logger = createLogger({
    level: 'info',
    format: format.json(),
    defaultMeta: { service: 'user-service' },
    transports: [
        new transports.Console({
            format: combine(timestamp(), json(), errorsFormat)
        }),
        // or use: options_custom / options_json
        new winstonMysql(options_default),
    ],
    exceptionHandlers: [
    new transports.File({ filename: 'exception.log' }),
  ],
  rejectionHandlers: [
    new transports.File({ filename: 'rejections.log' }),
  ],
});



module.exports = logger;

Раньше я сталкивался с той же проблемой, и я знаю, что это немного, но люди, которые все еще ищут решение, могут использовать utils-deep-cloneпакет. Просто добавлен слой над Winston для обработки объектов ошибок.

const winston = require('winston')
const { toJSON } = require('utils-deep-clone')

const winstonLogger = new (winston.Logger)({
  transports: [
    new (winston.transports.Console)()
  ]
})

const log = (message, payload) => {
  try {
    payload = toJSON(payload)
    return winstonLogger.log('info', message, payload)
  } catch(error) {
    console.error('some error occured while consoling')
  }
}

const testObj = {
  error: new Error('It should work')
}

log('Testing few bugs', testObj)

Результат будет:

info: Testing few bugs message=It should work, stack=Error: It should work
    at Object.<anonymous> (/Users/atishay/Desktop/utils-error-deep-log/logger.js:20:10)
    at Module._compile (module.js:652:30)
    at Object.Module._extensions..js (module.js:663:10)
    at Module.load (module.js:565:32)
    at tryModuleLoad (module.js:505:12)
    at Function.Module._load (module.js:497:3)
    at Function.Module.runMain (module.js:693:10)
    at startup (bootstrap_node.js:188:16)
    at bootstrap_node.js:609:3

Другие вопросы по тегам