-
Notifications
You must be signed in to change notification settings - Fork 157
Open
Description
❗ Problem Description
When using DailyRotateFile for logging, the following warning is thrown after multiple operations:
[Nest] 10240 - 05/21/2025, 11:45:23 PM LOG [APP] App is running on port 3000!
(node:10240) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 finish listeners added to [DailyRotateFile]. Use emitter.setMaxListeners() to increase limit
(node:10240) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 finish listeners added to [DailyRotateFile]. Use emitter.setMaxListeners() to increase limit
This occurs when more than 10 listeners are attached to the finish event of a DailyRotateFile instance, potentially indicating a memory leak or improper event cleanup.
This my code:
import 'winston-daily-rotate-file';
import 'dotenv/config';
import * as path from 'path';
import * as util from 'util';
import * as winston from 'winston';
type LogLevel = 'error' | 'warn' | 'info' | 'debug' | 'verbose';
type AppType = 'APP' | 'WORKER';
const logIcons: Record<LogLevel, string> = {
error: '❌',
warn: '⚠️',
info: '🟢',
debug: '🐛',
verbose: '🔵',
};
const appTypeColors: Record<AppType, string> = {
APP: '\x1b[36m%s\x1b[0m', // Cyan
WORKER: '\x1b[35m%s\x1b[0m', // Magenta
};
const enumerateErrorFormat = winston.format((info) => {
if (info instanceof Error) {
info.message = `[${info.name}] ${info.message}`;
info.level = info.name;
}
return info;
});
const logFiles = {
error: path.join(__dirname, '../../logs/error.log'),
};
function getAppType(): AppType {
const isWorker = process.argv.some((arg) => arg.includes('worker'));
return isWorker ? 'WORKER' : 'APP';
}
export function getLogger(name: string) {
const appType = getAppType();
const loggerName = `${appType}:${name}`;
const coloredAppType = appTypeColors[appType].replace('%s', appType);
if (!winston.loggers.has(loggerName)) {
winston.loggers.add(loggerName, {
level: 'debug',
format: winston.format.combine(
enumerateErrorFormat(),
winston.format.colorize(),
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
winston.format.printf((info) => {
const { timestamp, level, message, stack, ...extra } = info;
const icon = logIcons[info[Symbol.for('level')] as LogLevel] || '';
const extraDetails = Object.keys(extra).length
? util.inspect(extra)
: '';
const stackTrace = stack ? `\nStack Trace:\n${stack}` : '';
return `${icon} [${coloredAppType}][${name}][${level}] - [${timestamp}]: ${message}${extraDetails}${stackTrace}`;
}),
),
transports: [
new winston.transports.Console({
stderrLevels: ['error', 'verbose'],
}),
// Rotate logs daily and keep them for 10 files
new winston.transports.DailyRotateFile({
filename: process.env.LOG_DIR || 'logs' + '/application-%DATE%.log',
datePattern: 'YYYY-MM-DD',
handleExceptions: true,
zippedArchive: true,
maxFiles: 10,
createSymlink: true,
symlinkName: 'application.log',
}),
new winston.transports.File({
filename: logFiles.error,
level: 'error',
}),
],
});
}
const logger = winston.loggers.get(loggerName);
return {
debug(msg: any) {
return logger.debug(msg);
},
info(msg: any) {
return logger.info(msg);
},
warn(msg: any) {
return logger.warn(msg);
},
error(msg: any, error?: Error) {
if (error) {
return logger.error({
message: msg,
stack: error.stack,
name: error.name,
});
}
return logger.error(msg);
},
verbose(msg: any, error?: Error) {
return logger.verbose(error ? `[${error.name}] ${error.message}` : msg);
},
};
}
Metadata
Metadata
Assignees
Labels
No labels