Log4js

Node.js logging library inspired by Java Log4j library. Provides familiar API for Java developers, facilitating transition to Node.js. Design that ports concepts like log levels, appenders, and layouts to JavaScript.

Logging LibraryJavaScriptNode.jsAppendersConfiguration-Based

GitHub Overview

log4js-node/log4js-node

A port of log4js to node.js

Stars5,826
Watchers109
Forks768
Created:January 17, 2010
Language:JavaScript
License:Other

Topics

javascriptlog4js-node

Star History

log4js-node/log4js-node Star History
Data as of: 7/17/2025, 10:01 AM

Library

Log4js

Overview

Log4js is a Log4j-style logging library for JavaScript. It transplants the design philosophy of Log4j, familiar to Java developers, into the JavaScript ecosystem, providing enterprise-grade features such as hierarchical loggers, multiple appenders, configuration-based management, and log level control. It works in both Node.js and browser environments, excelling at handling complex logging requirements through detailed control via configuration files and rich appenders.

Details

Log4js 6.9.1 is positioned as an important choice for JavaScript development in enterprise environments and development teams with Java backgrounds as of 2025. It applies Log4j's mature logging patterns to JavaScript, achieving declarative configuration through XML/JSON configuration files, category-based logger hierarchy, diverse appenders (File, Console, Database, Network, etc.), and format control through layout patterns. It provides scalable log management from Node.js server-side applications to complex enterprise systems.

Key Features

  • Hierarchical Logger System: Category-based logger inheritance and hierarchical configuration management
  • Rich Appenders: Diverse output destinations including File, Console, Date File, SMTP, Database, etc.
  • Configuration File-Driven: Declarative configuration through JSON/XML with hot reload support
  • Layout Patterns: Flexible format control through Log4j-like pattern strings
  • Cluster Support: Multi-process support through integration with Node.js cluster module
  • Real-time Configuration Changes: Dynamic configuration updates through file monitoring

Pros and Cons

Pros

  • Extremely low learning cost for Java developers (direct utilization of Log4j knowledge)
  • Easy runtime log level changes and appender additions through configuration files
  • Capability to handle detailed log control and audit requirements demanded in enterprise environments
  • Flexibility of simultaneous output through multiple appenders (file, database, email, etc.)
  • Stable log management in Node.js cluster multi-process environments
  • Compatibility with existing Log4j-based monitoring tools

Cons

  • Configuration may feel verbose to modern JavaScript developers
  • Understanding and management costs required for JSON/XML configuration files
  • Performance may be slightly inferior compared to Winston or pino
  • Limited support for structured logging (JSON output) compared to other libraries
  • Features may be overkill for lightweight applications
  • Some features (file output, etc.) are restricted in browser environments

References

Code Examples

Installation and Basic Setup

# Install Log4js
npm install log4js

# TypeScript type definitions (automatically included in latest versions)
npm install @types/log4js  # Only when using TypeScript
// Simplest usage example
const log4js = require('log4js');
const logger = log4js.getLogger();

logger.level = 'debug';
logger.debug('Some debug messages');
logger.info('Information message');
logger.warn('Warning message');
logger.error('Error message');
logger.fatal('Fatal error message');

Basic Logging Operations (Levels, Formatting)

const log4js = require('log4js');

// Basic configuration
log4js.configure({
  appenders: { 
    console: { type: 'console' },
    file: { type: 'file', filename: 'app.log' }
  },
  categories: { 
    default: { appenders: ['console', 'file'], level: 'info' }
  }
});

const logger = log4js.getLogger('application');

// Log output at each level
logger.trace('Entering function');
logger.debug('Debug information');
logger.info('Application started');
logger.warn('This is a warning');
logger.error('Error occurred', new Error('Sample error'));
logger.fatal('Fatal system error');

// Formatted logging
logger.info('User %s logged in with ID %d', 'john_doe', 12345);
logger.error('Database connection failed: %s', err.message);

// Object logging
logger.info('User data:', { id: 123, name: 'John', role: 'admin' });

// Category-specific loggers
const dbLogger = log4js.getLogger('database');
const apiLogger = log4js.getLogger('api');

dbLogger.info('Database query executed');
apiLogger.warn('API rate limit approached');

Advanced Configuration and Customization (Appenders, Layouts)

const log4js = require('log4js');
const path = require('path');

// Complex configuration example
log4js.configure({
  appenders: {
    // Console output (with colors)
    console: {
      type: 'console',
      layout: {
        type: 'pattern',
        pattern: '%[[%d{yyyy-MM-dd hh:mm:ss}] [%p] %c%] - %m'
      }
    },
    
    // General log file
    fileAppender: {
      type: 'file',
      filename: 'logs/application.log',
      maxLogSize: 10485760, // 10MB
      backups: 5,
      compress: true,
      layout: {
        type: 'pattern',
        pattern: '[%d{ISO8601}] [%p] [%c] - %m'
      }
    },
    
    // Date-based rotation
    dateFile: {
      type: 'dateFile',
      filename: 'logs/daily.log',
      pattern: '.yyyy-MM-dd',
      compress: true,
      keepFileExt: true,
      layout: {
        type: 'pattern',
        pattern: '[%d] [%p] [%c{2}] %m'
      }
    },
    
    // Error-specific log
    errorFile: {
      type: 'file',
      filename: 'logs/errors.log',
      layout: {
        type: 'pattern',
        pattern: '[%d{ISO8601}] [%p] [%c] [%f{1}:%l] - %m%n%s'
      }
    },
    
    // JSON format log
    jsonFile: {
      type: 'file',
      filename: 'logs/json.log',
      layout: { type: 'json' }
    },
    
    // Network appender (for Logstash, etc.)
    tcp: {
      type: '@log4js-node/tcp',
      host: 'localhost',
      port: 5000,
      layout: { type: 'json' }
    }
  },
  
  categories: {
    // Default category
    default: { 
      appenders: ['console', 'fileAppender'], 
      level: 'info' 
    },
    
    // Database operation logs
    database: { 
      appenders: ['console', 'dateFile'], 
      level: 'debug' 
    },
    
    // Error logs
    error: { 
      appenders: ['console', 'errorFile'], 
      level: 'error' 
    },
    
    // API-related logs
    api: { 
      appenders: ['console', 'jsonFile', 'tcp'], 
      level: 'info' 
    },
    
    // Production environment (no console output)
    production: { 
      appenders: ['fileAppender', 'errorFile'], 
      level: 'warn' 
    }
  }
});

// Get category-specific loggers
const defaultLogger = log4js.getLogger();
const dbLogger = log4js.getLogger('database');
const apiLogger = log4js.getLogger('api');
const errorLogger = log4js.getLogger('error');

// Usage examples
defaultLogger.info('Application initialized');
dbLogger.debug('SQL query: SELECT * FROM users WHERE id = ?', [123]);
apiLogger.info('API request', { method: 'GET', url: '/users', status: 200 });
errorLogger.error('Uncaught exception', new Error('Sample error'));

Structured Logging and Modern Observability Support

const log4js = require('log4js');

// Structured logging configuration
log4js.configure({
  appenders: {
    // JSON output for ELK Stack
    elk: {
      type: 'file',
      filename: 'logs/elk.log',
      layout: {
        type: 'json',
        separator: ',',
        include: ['timestamp', 'level', 'category', 'data']
      }
    },
    
    // For Prometheus metrics
    metrics: {
      type: 'file',
      filename: 'logs/metrics.log',
      layout: {
        type: 'pattern',
        pattern: 'timestamp=%d level=%p category=%c method=%X{method} duration=%X{duration}ms %m'
      }
    },
    
    // Custom JSON layout
    customJson: {
      type: 'file',
      filename: 'logs/custom.json',
      layout: {
        type: 'json',
        static: {
          service: 'my-service',
          version: '1.0.0'
        },
        include: ['timestamp', 'level', 'category', 'data', 'static']
      }
    }
  },
  
  categories: {
    default: { appenders: ['elk'], level: 'info' },
    metrics: { appenders: ['metrics'], level: 'info' },
    structured: { appenders: ['customJson'], level: 'debug' }
  }
});

const logger = log4js.getLogger('structured');
const metricsLogger = log4js.getLogger('metrics');

// Structured data logging
logger.info('User operation', {
  userId: 'user_123',
  operation: 'login',
  timestamp: new Date().toISOString(),
  metadata: {
    ip: '192.168.1.100',
    userAgent: 'Mozilla/5.0...',
    sessionId: 'sess_456'
  }
});

// Recording metrics information
logger.addContext('method', 'POST');
logger.addContext('duration', 245);
metricsLogger.info('API call completed');

// Logging with trace information
logger.addContext('traceId', 'trace_789');
logger.addContext('spanId', 'span_012');
logger.debug('Processing request step', { step: 'validation', result: 'success' });

// Logging with custom fields
const contextLogger = log4js.getLogger('structured');
contextLogger.addContext('environment', 'production');
contextLogger.addContext('region', 'us-east-1');
contextLogger.info('Service health check', { 
  status: 'healthy', 
  checks: ['database', 'redis', 'external-api'] 
});

Error Handling and Performance Optimization

const log4js = require('log4js');
const cluster = require('cluster');

// Cluster-compatible configuration
if (cluster.isMaster) {
  // Master process configuration
  log4js.configure({
    appenders: {
      master: {
        type: 'file',
        filename: 'logs/master.log',
        layout: {
          type: 'pattern',
          pattern: '[%d] [MASTER] [%p] %m'
        }
      }
    },
    categories: {
      default: { appenders: ['master'], level: 'info' }
    }
  });
} else {
  // Worker process configuration
  log4js.configure({
    appenders: {
      worker: {
        type: 'file',
        filename: `logs/worker-${cluster.worker.id}.log`,
        layout: {
          type: 'pattern',
          pattern: '[%d] [WORKER-' + cluster.worker.id + '] [%p] %m'
        }
      },
      
      // High-performance log file
      highPerformance: {
        type: 'file',
        filename: 'logs/performance.log',
        writeMode: 'append',
        flags: 'a',
        encoding: 'utf8',
        maxLogSize: 52428800, // 50MB
        backups: 10
      }
    },
    categories: {
      default: { appenders: ['worker'], level: 'info' },
      performance: { appenders: ['highPerformance'], level: 'debug' }
    }
  });
}

const logger = log4js.getLogger();
const perfLogger = log4js.getLogger('performance');

// Error handling example
function handleDatabaseOperation(query, params) {
  const startTime = Date.now();
  logger.debug('Database operation started', { query, params });
  
  try {
    // Execute database operation
    const result = executeQuery(query, params);
    const duration = Date.now() - startTime;
    
    perfLogger.info('Query executed', {
      query,
      duration,
      rowCount: result.length,
      success: true
    });
    
    return result;
  } catch (error) {
    const duration = Date.now() - startTime;
    
    logger.error('Database operation failed', {
      query,
      params,
      duration,
      error: error.message,
      stack: error.stack
    });
    
    // Re-throw error
    throw error;
  }
}

// Asynchronous error handling
async function asyncOperationWithLogging(operation) {
  const operationId = Math.random().toString(36).substr(2, 9);
  logger.addContext('operationId', operationId);
  
  try {
    logger.info('Async operation started');
    const result = await operation();
    logger.info('Async operation completed successfully');
    return result;
  } catch (error) {
    logger.error('Async operation failed', {
      error: error.message,
      stack: error.stack,
      operationId
    });
    throw error;
  } finally {
    logger.removeContext('operationId');
  }
}

// Performance monitoring
function createPerformanceMonitor() {
  const startTimes = new Map();
  
  return {
    start(label) {
      startTimes.set(label, Date.now());
      perfLogger.debug(`Performance monitor started: ${label}`);
    },
    
    end(label) {
      const startTime = startTimes.get(label);
      if (startTime) {
        const duration = Date.now() - startTime;
        perfLogger.info(`Performance monitor: ${label}`, { duration });
        startTimes.delete(label);
        return duration;
      }
    }
  };
}

const monitor = createPerformanceMonitor();

// Usage example
monitor.start('user-authentication');
// Authentication process...
monitor.end('user-authentication');

Framework Integration and Practical Examples

// Express.js integration example
const express = require('express');
const log4js = require('log4js');

// Express logging configuration
log4js.configure({
  appenders: {
    access: {
      type: 'dateFile',
      filename: 'logs/access.log',
      pattern: '.yyyy-MM-dd',
      layout: {
        type: 'pattern',
        pattern: '%h %l %u %d{ISO8601} "%r" %s %b "%{Referer}i" "%{User-Agent}i"'
      }
    },
    
    app: {
      type: 'file',
      filename: 'logs/app.log',
      layout: {
        type: 'pattern',
        pattern: '[%d] [%p] [%c] %m'
      }
    },
    
    error: {
      type: 'file',
      filename: 'logs/error.log',
      layout: {
        type: 'pattern',
        pattern: '[%d] [%p] %m%n%s'
      }
    }
  },
  
  categories: {
    default: { appenders: ['app'], level: 'info' },
    access: { appenders: ['access'], level: 'info' },
    error: { appenders: ['error'], level: 'error' }
  }
});

const app = express();
const logger = log4js.getLogger();
const errorLogger = log4js.getLogger('error');

// Access log middleware
app.use(log4js.connectLogger(log4js.getLogger('access'), { level: 'auto' }));

// Request logging middleware
app.use((req, res, next) => {
  req.logger = log4js.getLogger('api');
  req.logger.addContext('requestId', Math.random().toString(36).substr(2, 9));
  req.logger.info('Request received', {
    method: req.method,
    url: req.url,
    ip: req.ip,
    userAgent: req.get('User-Agent')
  });
  next();
});

// Error handling middleware
app.use((error, req, res, next) => {
  errorLogger.error('Unhandled error', {
    error: error.message,
    stack: error.stack,
    url: req.url,
    method: req.method,
    ip: req.ip
  });
  
  res.status(500).json({ error: 'Internal Server Error' });
});

// Socket.IO integration example
const http = require('http');
const socketIo = require('socket.io');

const server = http.createServer(app);
const io = socketIo(server);

const socketLogger = log4js.getLogger('socket');

io.on('connection', (socket) => {
  socketLogger.info('Socket connected', { socketId: socket.id });
  
  socket.on('message', (data) => {
    socketLogger.debug('Message received', { socketId: socket.id, data });
  });
  
  socket.on('disconnect', () => {
    socketLogger.info('Socket disconnected', { socketId: socket.id });
  });
  
  socket.on('error', (error) => {
    socketLogger.error('Socket error', { socketId: socket.id, error: error.message });
  });
});

// Dynamic configuration file reload
const fs = require('fs');

function setupConfigWatcher() {
  const configFile = 'log4js.json';
  
  fs.watchFile(configFile, (curr, prev) => {
    logger.info('Log configuration file changed, reloading...');
    
    try {
      const newConfig = JSON.parse(fs.readFileSync(configFile, 'utf8'));
      log4js.configure(newConfig);
      logger.info('Log configuration reloaded successfully');
    } catch (error) {
      logger.error('Failed to reload log configuration', error);
    }
  });
}

// Application startup
const PORT = process.env.PORT || 3000;

server.listen(PORT, () => {
  logger.info(`Server started on port ${PORT}`);
  setupConfigWatcher();
});

// Graceful shutdown
process.on('SIGTERM', () => {
  logger.info('SIGTERM received, shutting down gracefully');
  log4js.shutdown(() => {
    process.exit(0);
  });
});

process.on('SIGINT', () => {
  logger.info('SIGINT received, shutting down gracefully');
  log4js.shutdown(() => {
    process.exit(0);
  });
});

External Configuration Files and Advanced Features

// log4js.json configuration file example
{
  "appenders": {
    "out": {
      "type": "stdout",
      "layout": {
        "type": "colored"
      }
    },
    
    "app": {
      "type": "dateFile",
      "filename": "logs/app.log",
      "pattern": ".yyyy-MM-dd-hh",
      "compress": true,
      "layout": {
        "type": "pattern",
        "pattern": "[%d{ISO8601}] [%p] [%c{2}] %m"
      }
    },
    
    "errorFile": {
      "type": "file",
      "filename": "logs/errors.log",
      "layout": {
        "type": "pattern",
        "pattern": "[%d{ISO8601}] [%p] [%c] %m%n%s"
      }
    },
    
    "errors": {
      "type": "logLevelFilter",
      "level": "error",
      "appender": "errorFile"
    }
  },
  
  "categories": {
    "default": { 
      "appenders": ["out", "app", "errors"], 
      "level": "info" 
    },
    "development": { 
      "appenders": ["out"], 
      "level": "debug" 
    },
    "production": { 
      "appenders": ["app", "errors"], 
      "level": "warn" 
    }
  }
}
// Initialization using configuration file
const log4js = require('log4js');
const path = require('path');

// Load configuration file based on environment
const env = process.env.NODE_ENV || 'development';
const configFile = path.join(__dirname, `config/log4js-${env}.json`);

try {
  log4js.configure(configFile);
} catch (error) {
  console.error('Failed to load log4js configuration:', error);
  process.exit(1);
}

// Create custom appender
function createDatabaseAppender(config) {
  const { connectionString, tableName } = config;
  
  return (loggingEvent) => {
    // Database write process
    const logData = {
      timestamp: loggingEvent.startTime,
      level: loggingEvent.level.levelStr,
      category: loggingEvent.categoryName,
      message: loggingEvent.data.join(' ')
    };
    
    // Actual DB save process
    saveToDatabase(connectionString, tableName, logData);
  };
}

// Register custom appender
log4js.addAppender(createDatabaseAppender({
  connectionString: 'mongodb://localhost:27017/logs',
  tableName: 'application_logs'
}), 'database');

const logger = log4js.getLogger();
logger.info('Custom appender example');