11
votes

Objet de journalisation Winston

J'utilise Winston pour ma journalisation backend Je ne peux pas enregistrer l'objet sans utiliser JSON.stringify ce qui est ennuyeux

const logger: Logger = createLogger({
    // change level if in dev environment versus production
    level: env === 'production' ? 'info' : 'debug',
    format: format.combine(
        format.label({label: path.basename(process.mainModule.filename)}),
        format.timestamp({format: 'YYYY-MM-DD HH:mm:ss'}),
        format.prettyPrint()
    ),
    transports: [
        new transports.Console({
            format: format.combine(format.colorize(), logFormat),
        }),
        new transports.File({
            filename,
            format: format.combine(format.json()),
        }),
    ],
    exitOnError: false,
})
logger.debug(`Register ${JSON.stringify(req.body)}`)

Pourriez-vous me montrer comment enregistrer un objet avec Winston. J'utilise la version 3.2.1


0 commentaires

5 Réponses :


16
votes

Vous essayez d'insérer un objet JSON directement dans la chaîne, il imprimera donc [Object Object] sans JSON.stringify .

Ce problème ne peut pas être résolu en configurant Winston, car ce problème se produit pendant la génération de la chaîne (avant que la fonction logger.debug ne la lise réellement), donc un appel console.log la même chose.

Le premier paramètre des fonctions logger.* Est le message (chaîne), vous pouvez ensuite passer un objet de métadonnées (JSON).

Pour utiliser les métadonnées dans votre fonction logFormat , mettez à jour votre instanciation Logger comme suit:

{
  message: 'Register Daniel Duuch with email daniel.duuch@greatmail.com',
  level: 'debug',
  timestamp: '2019-05-11 17:05:45',
  label: 'index.js',
  metadata: {
    name: 'Daniel Duuch',
    email: 'daniel.duuch@greatmail.com',
    password: 'myGreatPassword'
  }
}

Usage:

2019-05-11 17:05:45 debug [index.js]: Register Daniel Duuch with email daniel.duuch@greatmail.com

Sortie de la console:

const req = {
  body: {
    name: 'Daniel Duuch',
    email: 'daniel.duuch@greatmail.com',
    password: 'myGreatPassword'
  }
}

logger.debug(`Register ${req.body.name} with email ${req.body.email}`, { ...req.body, action: 'register' })

Sortie du fichier journal (joliment à la main, voir commentaire dans le format du fichier de transport):

const winston = require('winston')
const { format, transports } = winston
const path = require('path')

const logFormat = format.printf(info => `${info.timestamp} ${info.level} [${info.label}]: ${info.message}`)

const logger = winston.createLogger({
  level: process.env.NODE_ENV === 'production' ? 'info' : 'debug',
  format: format.combine(
    format.label({ label: path.basename(process.mainModule.filename) }),
    format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
    // Format the metadata object
    format.metadata({ fillExcept: ['message', 'level', 'timestamp', 'label'] })
  ),
  transports: [
    new transports.Console({
      format: format.combine(
        format.colorize(),
        logFormat
      )
    }),
    new transports.File({
      filename: 'logs/combined.log',
      format: format.combine(
        // Render in one line in your log file.
        // If you use prettyPrint() here it will be really
        // difficult to exploit your logs files afterwards.
        format.json()
      )
    })
  ],
  exitOnError: false
})

J'espère que cela résout votre problème.

Code pour cette réponse


7 commentaires

Je remplace le format de journal comme celui-ci const logFormat = format.printf (info => ${info.timestamp} ${info.level} [${info.label}]: ${info.message} ,)


@coinhndp me laisse plusieurs minutes pour tester certaines solutions que je pourrais avoir


@coinhndp réponse mise à jour :) J'ai un serveur Discord où nous nous entraidons , n'hésitez pas à le rejoindre: smiley: discord.gg/C2bVzgb


Merci pour votre aide. Vous pouvez utiliser format.splash (). Voir la réponse d'Anton Pastukhov


Je sais que le code n'est qu'un exemple, mais si jamais vous faites cela, vous devez vous assurer de ne pas enregistrer les mots de passe des gens n'importe où.


@SherloxTV pouvez-vous s'il vous plaît me dire comment puis-je obtenir le "nom de fonction" comme vous obtenez le nom de fichier (chemin.nom_bas (process.mainModule.filename)


@abdulrehmankk Je pense que c'est pour une autre question, vous devriez trouver ce que vous cherchez quelque part sur SO :) peace



6
votes

Vous pouvez utiliser format.splat() dans la configuration de votre enregistreur:

let myObj = { /* ... */ };
logger.info('This message will include a complete object: %O', myObj);

... et objet journal utilisant l'interpolation de chaîne:

const logger = createLogger({
    format: combine(
        ...
        format.splat(), // <--
        ...
    ),
    ...
});


5 commentaires

Merci. Au fait, savez-vous comment puis-je enregistrer le nom de fichier en tant qu'étiquette. Depuis que j'utilise le journal d'importation de '../../utils/logger', je ne sais pas comment le faire stackoverflow.com/questions/53655740/...


Intéressant car j'utilise dactylographié et utilise babel7 pour transformer les fichiers ts. Tous mes modules et erreurs de stacktrace pointent vers des fichiers dist / *. Js


@ anton-pastukhov @coinhndp Je suis désolé mais c'est une mauvaise pratique. J'ai suggéré à l'OP d'utiliser le paramètre de metadata pour une raison, à savoir que si jamais vous avez besoin d'utiliser votre journal dans le système de surveillance / d'analyse, il est préférable d'avoir un objet JSON directement dans les journaux, au lieu de rechercher des données via des chaînes. Et si les journaux doivent être rouges par une opération humaine, il est préférable d'analyser cet objet dans une chaîne lisible. C'est pourquoi ma solution donne une sortie de console optimisée pour la lisibilité des opérations humaines et une sortie de fichier journal optimisée pour le traitement des données. Veuillez ne pas encourager les mauvaises pratiques.


Remercier. Vous avez votre idée. J'utilise juste cela au niveau de débogage et les journaux dans les fichiers que j'utilise Json. Convenez avec vous que je devrais utiliser des métadonnées. Avez-vous de l'expérience dans React, avez beaucoup de questions à poser @SherloxFR


@coinhndp Je suis conscient que vous avez compris mon point, je suis juste préoccupé par les prochaines personnes qui viendront à votre question et feront la mauvaise chose dans le travail de qualité de production ^^ ouais j'ai de l'expérience avec React, je vous ai vu rejoint le Discord je t'aiderai là-bas



5
votes

J'ai dû combiner la solution fournie par @SherloxFR et @Anton.

logger.info('Content: %o', {...myObj});

Vous pouvez voir que j'ai ajouté à la fois format.splat() et format.json() à la configuration des options dans le code ci-dessus.

let myObj = {
   name: "StackOverflow",
};

logger.info('Content: %o', myObj);

C'est ainsi que j'ai utilisé l'objet de configuration d'options. Vous pouvez en fait écrire le code de format dans le tableau des transports mais je n'aime pas ça de cette façon. C'est ton choix de toute façon.

Après la configuration comme ça, voici comment je l'ai utilisé dans mon code

const logger = new Winston.createLogger({
    transports: [
        new Winston.transports.File(options.file),
        new Winston.transports.Console(options.console)
    ],
    exitOnError: false // do not exit on handled exceptions
});

Vous pouvez également le diffuser comme ça si vous le souhaitez

const Winston = require('winston');
const { format } = Winston;

const options = {
    file: {
        ....
        format: format.combine(
            format.splat(), 
            format.json()
        ),
        ...
    },
    console: {
        ...
        format: format.combine(
            format.splat(),
            format.json()
        ),
        ...
    }
};

C'est tout. Winston devrait enregistrer votre objet avec cette configuration.


0 commentaires

0
votes

Ou vous utilisez simplement le

printf

fonction en conjonction avec JSON.stringify

new winston.transports.Console({
  format: winston.format.combine(
    winston.format.colorize(),
    winston.format.simple(),
    winston.format.printf(context => {
      const msgstr = JSON.stringify(context.message, null, '\t')
      return `[${context.level}]${msgstr}`
    }),
  ),
})


0 commentaires

0
votes

Ma solution était d'utiliser ce type de formateur:

logger.info('plain text')
logger.info('plain text with object %o', { a:1, b: 2} )
logger.info({ a:1, b: 2 })

maintenant toutes ces options fonctionnent comme prévu:

const { format } = winston
const consoleFormat = format.combine(
  format.prettyPrint(),
  format.splat(),
  format.printf((info) => {
    if (typeof info.message === 'object') {
      info.message = JSON.stringify(info.message, null, 3)
    }

    return info.message
  })
)


0 commentaires