web-dev-qa-db-fra.com

Winston n'affiche pas les détails de l'erreur

J'utilise winston pour la journalisation et la plupart du temps cela fonctionne bien, mais quand il y a une exception, il n'imprime tout simplement aucun détail.

Voici mon code pour configurer 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

J'utilise également Express et dans mon middleware de gestion des erreurs, j'ai ce code:

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.' })
}

Le problème est que lorsqu'une erreur se produit, tous les journaux winston sont:

{"niveau": "erreur"}

Alors que le bon vieux console.log() affiche:

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)

Comment puis-je obtenir winston pour enregistrer quelque chose comme ça, y compris la trace de la pile?

Merci beaucoup!

EDIT: Si je change la ligne logger.error (err) en logger.error (err.message), au moins j'obtiens ceci:

{"message": "Impossible de lire la propriété 'nom de fichier' non défini", "niveau": "erreur"}

Encore très loin de ce que je recherche.

12
Balázs Vincze

Un moyen rapide et sale serait de vous connecter err.stack:

logger.error(err.stack);

Une méthode plus élaborée serait d'implémenter un format personnalisé spécifiquement pour les instances Error. Il y a un exemple de code sur la façon de l'implémenter dans ce problème Github .

2
robertklep

En utilisant le format.

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" }),
    ],
});
1
Gary Shan

Je pense que ce qui vous manque est format.errors({ stack: true }) dans winston.createLogger.

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

Voir ce fil GitHub pour plus d'informations.

La raison en est que les propriétés intéressantes de l'objet Error, comme .stack, ne sont pas énumérables. Certaines fonctions vérifient si leurs paramètres sont des instances Error, comme console.error, et d'autres fonctions ignorent toutes les propriétés non énumérables, comme winston.<log-level> et 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'))
'{}'

Cela dit, il est horrible de pouvoir utiliser un enregistreur d'erreurs pour ignorer les erreurs ... Je viens de perdre trop de temps pour cela.

1
jtpeterson