winstonjs / winston

A logger for just about everything.
http://github.com/winstonjs/winston
MIT License
22.73k stars 1.81k forks source link

log.error not logging #1704

Open tiagonapoli opened 5 years ago

tiagonapoli commented 5 years ago

Please tell us about your environment:

What is the problem?

log.error(new Error('error message')) doesn't log anything.

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

const { combine } = format

const errorFormatter = format((info) => {
  console.log(info)
  return info
})

const consoleTransport = new transports.Console({
  format: combine(errorFormatter()),
})

const logger = createLogger({
  transports: [
    consoleTransport,
  ],
})

try {
  throw new Error('Error message')
} catch(err) {
  logger.error(err) // info doesnt have the error object
  logger.error('', err) // info have the error object
}

What do you expect to happen instead?

The error to be logged

tiagonapoli commented 5 years ago

Changed the formatter and now info is instance of error

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

const { combine } = format

const errorFormatter = format((info) => {
  if(info instanceof Error) console.log("IS ERROR") // this is printed
  console.log(info.message)
  console.log(info.stack)
  return ''
})

const logger = createLogger({
  format: combine(errorFormatter()),
  transports: [
    new transports.Console(),
  ],
})

try {
  throw new Error('Error message')
} catch(err) {
  logger.error(err) // info has the error object
}
tiagonapoli commented 5 years ago

I found two solutions, the first one is to use format.errors, mentioned on logform in the parent logger, then create a messageFormatter using format.printf and conditionally add a stack field extracted from info (format.errors({ stack: true}) will add that).

The other solution, that I preferred was hack into winston level loggers:

const addArgs = format((info) => {
  const args: any[] = info[Symbol.for('splat')]
  info.args = args ? [...args] : []
  return info
})

const messageFormatter = format.printf(info => {
  const { timestamp: timeString = '', message, args = [] } = info
  const formattedMsgWithArgs = util.formatWithOptions({ colors: true }, message, ...args)
  const msg = `${timeString} - ${info.level}: ${formattedMsgWithArgs}`
  return msg
})

const logger = createLogger({
  format: format.combine(
    addArgs(),
    format.timestamp({ format: 'HH:mm:ss.SSS' })
  ),

  transports: [
    new transports.Console({
      format: format.combine(format.colorize(), messageFormatter),
    }),
  ],
})

const levels = ['debug', 'info', 'error']
levels.forEach((level) => {
  logger[level] = (msg: any, ...remains: any) => {
    if(typeof msg != "string") {
      return logger.log(level, '', msg, ...remains)
    }

    logger.log(level, msg, ...remains)
  }  
})

It seems this way I can get error logging similar to console.log