If I enable stack: true, then logged unhandled exceptions and rejections are undefined in the log files. Nothing is even printed via console. If I remove stack: true, then output is logged in files and printed via console BUT definitely loose the stack trace and message of the Error object.
The following is my config:
import { ENVIRONMENT } from '../config/constants'
import { createLogger, format, transports, addColors } from 'winston'
import path from 'path'
const { combine, timestamp, printf, errors, colorize } = format
// Log directory path
const logDirectory = path.join(__dirname, '../../logs')
// Log Formats
const httpRequestFormat = printf(i => {
const { timestamp, message } = i
const parsedMessage = JSON.parse(message)
const {
ip,
method,
url,
httpVersion,
headers
} = parsedMessage
// TODO Check if we are logging correct IP of user
return `[${timestamp}]: ${method} ${url} HTTP/${httpVersion} ${headers.referrer ?? '-'} ${headers['user-agent']} ${ip}`
})
const errorFormat = printf(i => {
const { timestamp, message, statusCode, stack } = i
return `[${timestamp}]: ${statusCode ?? ''} ${message} ${stack ?? ''}`
})
const consoleFormat = printf(i => {
const { timestamp, level, message, statusCode, stack } = i
if (/http/.test(level)) {
const parsedMessage = JSON.parse(message)
return `${level} [${timestamp}]: ${parsedMessage.method} ${parsedMessage.url}`
} else if (/error/.test(level)) {
return `${level} [${timestamp}]: ${statusCode ?? '---'} ${message} ${stack ?? '---'}`
} else {
return `${level} [${timestamp}]: ${message}`
}
})
// Filters
const httpFilter = format((info, opts) => {
return info.level === 'http' ? info : false
})
const errorFilter = format((info, opts) => {
return info.level === 'error' ? info : false
})
// Transports
const consoleTransport = new transports.Console({
format: combine(
colorize(),
timestamp({
format: 'YYYY-MM-DD HH:mm:ss'
}),
consoleFormat
)
})
const httpRequestTransport = new transports.File({
level: 'http',
filename: `${logDirectory}/httpRequests.log`,
format: combine(
httpFilter(),
timestamp({
format: 'YYYY-MM-DD HH:mm:ss'
}),
httpRequestFormat
)
})
const errorTransport = new transports.File({
level: 'error',
filename: `${logDirectory}/errors.log`,
format: combine(
errorFilter(),
timestamp({
format: 'YYYY-MM-DD HH:mm:ss'
}),
errorFormat
)
})
const exceptionTransport = new transports.File({
filename: `${logDirectory}/exceptions.log`
})
const rejectionTransport = new transports.File({
filename: `${logDirectory}/rejections.log`
})
const logger = createLogger({
level: ENVIRONMENT === 'PROD' ? 'info' : 'debug',
format: combine(
errors({ stack: true })
),
transports: [
httpRequestTransport,
errorTransport,
consoleTransport
],
exceptionHandlers: [exceptionTransport],
rejectionHandlers: [rejectionTransport],
handleExceptions: true,
handleRejections: true
})
addColors({
debug: 'yellow',
info: 'blue'
})
export default logger