Winston Logger

Ejemplo práctico para crear ficheros de logs con Winston para proyectos basados en Node.

Proyecto

  1. Descarga el repositorio.

    git clone https://github.com/AlexQuispe/winston-logger-example.git
    
  2. Ingresa a la carpeta del proyecto.

    cd winston-logger-example
    
  3. Instala las dependencias.

    npm install
    
  4. Ejecuta el script.

    node index.js
    
    30/04/2020 22:02:27 [info] Mensaje informativo
    30/04/2020 22:02:27 [warn] Mensaje de advertencia
    30/04/2020 22:02:27 [error] Mensaje de error
    30/04/2020 22:02:27 [info] Mensaje con datos { user: 'John Smith' }
    

Resultado

Antes de ejecutar el script.

app
  ├─ logger.js
  └─ index.js

Después de ejecutar el script.

app
  ├─ logs
  │     ├─ info.log
  │     ├─ warn.log
  │     └─ error.log
  ├─ logger.js
  └─ index.js

Y se habrán creado los siguientes fichero de logs:

logs/info.log

{"timestamp":"30/04/2020 22:02:27","level":"info","message":"Mensaje informativo","data":null}
{"timestamp":"30/04/2020 22:02:27","level":"warn","message":"Mensaje de advertencia","data":null}
{"timestamp":"30/04/2020 22:02:27","level":"error","message":"Mensaje de error","data":null}
{"timestamp":"30/04/2020 22:02:27","level":"info","message":"Mensaje con datos","data":"{ user: 'John Smith' }"}

logs/warn.log

{"timestamp":"30/04/2020 22:02:27","level":"warn","message":"Mensaje de advertencia","data":null}
{"timestamp":"30/04/2020 22:02:27","level":"error","message":"Mensaje de error","data":null}

logs/error.log

{"timestamp":"30/04/2020 22:02:27","level":"error","message":"Mensaje de error","data":null}

¿Cómo sucedió?

index.js

const Logger = require('./logger')

const logger = new Logger()

logger.info('Mensaje informativo')
logger.warn('Mensaje de advertencia')
logger.error('Mensaje de error')
logger.info('Mensaje con datos', { user: 'John Smith' })

logger.js

const util    = require('util')
const moment  = require('moment')
const winston = require('winston')

class Logger {
  constructor() { this.winstonLogger = winston.createLogger({ ... }) }

  info(message, data) { this.winstonLogger.info({ message, data }) }
  warn(message, data) { this.winstonLogger.warn({ message, data }) }
  error(message, data) { this.winstonLogger.error({ message, data }) }

  _createTransports() { ... }
  _consoleFormat () { ... }
  _fileFormat() { ... }
}

module.exports = Logger

[Fn] constructor

Crea una instancia de winstonLogger.

constructor() {
  this.winstonLogger = winston.createLogger({
    levels      : { error: 1, warn: 2, info: 3 },
    transports  : this._createTransports(),
    exitOnError : false,
  })
}

[Fn] _createTransports

Configura los tipos de logs a generar.

_createTransports() {
  const TRANSPORTS = []
  TRANSPORTS.push(new winston.transports.Console({
    format           : winston.format.printf(this._consoleFormat()),
    level            : 'info', // Muestra logs de nivel 3 o menor
    handleExceptions : false,
    colorize         : false,
    json             : false,
  }))
  Array.from(['info', 'warn', 'error']).forEach(level => {
    TRANSPORTS.push(new winston.transports.File({
      format           : winston.format.printf(this._fileFormat()),
      level            : level,
      handleExceptions : false,
      colorize         : false,
      json             : true,
      filename         : `logs/${level}.log`,
      maxsize          : 5242880, // 5242880 Bytes = 5 MB
      maxFiles         : 5,
    }))
  })
  return TRANSPORTS
}

[Fn] _consoleFormat

Describe el formato de salida para la consola.

_consoleFormat () {
  const COLORS = {
    error : `\x1b[91m`, // LIGHT_RED
    warn  : `\x1b[93m`, // LIGHT_YELLOW
    info  : `\x1b[96m`, // LIGHT_CYAN
    reset : `\x1b[0m`,  // Restaura al color por defecto
  }
  return (info) => {
    const START     = COLORS[info.level]
    const END       = COLORS.reset
    const TIMESTAMP = moment().format('DD/MM/YYYY HH:mm:ss')
    const LEVEL     = info.level
    const MESSAGE   = info.message
    const DATA      = info.data ? util.inspect(info.data, false, null) : ''
    return `${START} ${TIMESTAMP} [${LEVEL}] ${MESSAGE} ${DATA} ${END}`
  }
}

[Fn] _fileFormat

Describe el formato de salida para los ficheros de logs.

_fileFormat() {
  return (info)  => {
    const TIMESTAMP = moment().format('DD/MM/YYYY HH:mm:ss')
    const LEVEL     = info.level
    const MESSAGE   = info.message
    const DATA      = info.data ? util.inspect(info.data, false, null) : null
    return JSON.stringify({
      timestamp : TIMESTAMP,
      level     : LEVEL,
      message   : MESSAGE,
      data      : DATA,
    })
  }
}

Niveles de logs

Según la especificación RFC5424 (sobre la que se basa la librería winston) los niveles de logs se identifican numéricamente en orden ascendente desde el más importante hasta el menos importante.

Por ejemplo:

Tipo de errorNivelDescripciónColor (opcional)
fatal0Mensajes críticos\x1b[31m RED
error1Mensajes de error\x1b[91m LIGHT_RED
warn2Mensajes de advertencia\x1b[93m LIGHT_YELLOW
notice3Mensajes importantes\x1b[92m LIGHT_GREEN
info4Mensajes informativos\x1b[97m LIGHT_WHITE
verbose5Mensajes detallados\x1b[96m LIGHT_CYAN
debug6Mensajes para el depurador\x1b[94m LIGHT_BLUE
silly7Mensajes sin importancia\x1b[95m LIGHT_MAGENTA

Puede obtener una referencia completa de los colores en el sitio: https://github.com/shiena/ansicolor.

Referencias

Publicado: 26 de mayo de 2020