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.
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 .
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" }),
],
});
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.