Created
January 3, 2025 13:51
-
-
Save Avi-E-Koenig/5f4578bb3fea272aaba67ba5fb53f871 to your computer and use it in GitHub Desktop.
Winston file logger
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import winston from 'winston'; | |
import asyncLocalStorage from './request-context.js'; | |
// Custom format to handle errors properly | |
const errorStackFormat = winston.format((info) => { | |
if (info instanceof Error) { | |
return Object.assign({}, info, { | |
stack: info.stack, | |
message: info.message, | |
}); | |
} | |
return info; | |
}); | |
// Custom format to add request context | |
const addRequestContext = winston.format((info) => { | |
const context = asyncLocalStorage.getStore(); | |
if (context?.uuid) { | |
info.requestId = context.uuid; | |
} | |
return info; | |
}); | |
// Winston Logger Configuration | |
const logger = winston.createLogger({ | |
level: process.env.LOG_LEVEL || 'info', | |
format: winston.format.combine( | |
errorStackFormat(), | |
addRequestContext(), | |
winston.format.timestamp({ | |
format: 'YYYY-MM-DD HH:mm:ss', | |
}), | |
winston.format.errors({ stack: true }), | |
winston.format.splat(), | |
winston.format.json(), | |
winston.format.printf(({ timestamp, level, message, stack, ...metadata }) => { | |
// Remove internal Winston properties | |
delete metadata.splat; | |
delete metadata.level; | |
delete metadata.timestamp; | |
// Create metadata string if there are properties | |
const metaStr = Object.keys(metadata).length ? `\n${JSON.stringify(metadata, null, 2)}` : ''; | |
if (stack) { | |
return `${timestamp} [${level.toUpperCase()}]: ${message}${metaStr}\n${stack}\n`; | |
} | |
return `${timestamp} [${level.toUpperCase()}]: ${message}${metaStr}\n`; | |
}) | |
), | |
transports: [ | |
// File transport with rotation | |
new winston.transports.File({ | |
filename: 'logs/error.log', | |
level: 'error', | |
maxsize: 5242880, // 5MB | |
maxFiles: 5, | |
tailable: true, | |
}), | |
new winston.transports.File({ | |
filename: 'logs/combined.log', | |
maxsize: 5242880, // 5MB | |
maxFiles: 5, | |
tailable: true, | |
}), | |
], | |
}); | |
// Add console transport in non-production environments | |
if (process.env.NODE_ENV !== 'production') { | |
logger.add( | |
new winston.transports.Console({ | |
format: winston.format.combine( | |
winston.format.colorize(), | |
winston.format.printf(({ timestamp, level, message, stack, ...metadata }) => { | |
// Remove internal Winston properties | |
delete metadata.splat; | |
delete metadata.level; | |
delete metadata.timestamp; | |
// Create metadata string if there are properties | |
const metaStr = Object.keys(metadata).length ? ` ${JSON.stringify(metadata)}` : ''; | |
if (stack) { | |
// Include stack trace if present | |
return `${timestamp} [${level}]: ${message}${metaStr}\n${stack}`; | |
} | |
// Standard log format | |
return `${timestamp} [${level}]: ${message}${metaStr}`; | |
}) | |
), | |
}) | |
); | |
} | |
// Handling uncaught exceptions and unhandled rejections | |
logger.exceptions.handle(new winston.transports.File({ filename: 'logs/exceptions.log' })); | |
process.on('unhandledRejection', (error) => { | |
logger.error('Unhandled Rejection:', error); | |
}); | |
export default logger; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment