Skip to content

MaxListenersExceededWarning on DailyRotateFile #402

@nguyennhukhanh

Description

@nguyennhukhanh

❗ 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

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions