CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-loglevel

Minimal lightweight logging for JavaScript, adding reliable log level methods to any available console.log methods

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

plugins.mddocs/

Plugin System

Extend loglevel with custom logging behavior through the method factory system, enabling advanced features like remote logging, custom formatting, and output redirection.

Capabilities

methodFactory

/**
 * Plugin API entry point for custom method factories
 * Called for each enabled method when level is set
 * @type {MethodFactory}
 */
methodFactory: MethodFactory;

/**
 * Method factory function type
 * @param {string} methodName - Log method name ('trace', 'debug', 'info', 'warn', 'error')
 * @param {number} level - Current logging level (0-5)
 * @param {string | symbol} loggerName - Name of the logger (undefined for root logger)
 * @returns {Function} Logging method implementation
 */
type MethodFactory = (
  methodName: 'trace' | 'debug' | 'info' | 'warn' | 'error',
  level: number,
  loggerName: string | symbol | undefined
) => (...message: any[]) => void;

Usage Examples:

import log from 'loglevel';

// Basic method factory override
const originalFactory = log.methodFactory;
log.methodFactory = function(methodName, level, loggerName) {
  const rawMethod = originalFactory(methodName, level, loggerName);
  
  return function(...args) {
    // Add timestamp prefix
    const timestamp = new Date().toISOString();
    rawMethod(`[${timestamp}]`, ...args);
  };
};

// Apply the factory
log.setLevel(log.getLevel()); // Rebuilds methods with new factory
log.info('This message has a timestamp'); // [2023-10-01T12:00:00.000Z] This message has a timestamp

rebuild

/**
 * Rebuild logging methods using current methodFactory
 * Forces regeneration of all logging methods
 * Updates child loggers if called on root logger
 */
rebuild(): void;

Usage Examples:

import log from 'loglevel';

// Change method factory
log.methodFactory = customFactory;

// Rebuild methods to apply changes
log.rebuild();

// For root logger, also rebuilds all child loggers
const childLogger = log.getLogger('child');
log.rebuild(); // Updates both root and child logger methods

Plugin Examples

Prefix Plugin

Add prefixes to all log messages:

import log from 'loglevel';

function createPrefixPlugin(prefix) {
  const originalFactory = log.methodFactory;
  
  log.methodFactory = function(methodName, level, loggerName) {
    const rawMethod = originalFactory(methodName, level, loggerName);
    
    return function(...args) {
      const loggerPrefix = loggerName ? `[${String(loggerName)}]` : '';
      rawMethod(`${prefix}${loggerPrefix}`, ...args);
    };
  };
  
  log.rebuild();
}

// Usage
createPrefixPlugin('[MyApp] ');

const dbLogger = log.getLogger('DB');
log.info('Application started');     // [MyApp] Application started
dbLogger.warn('Connection slow');    // [MyApp] [DB] Connection slow

Remote Logging Plugin

Send logs to a remote server:

import log from 'loglevel';

function createRemotePlugin(endpoint) {
  const originalFactory = log.methodFactory;
  
  log.methodFactory = function(methodName, level, loggerName) {
    const rawMethod = originalFactory(methodName, level, loggerName);
    
    return function(...args) {
      // Local logging
      rawMethod(...args);
      
      // Remote logging for errors and warnings
      if (level >= log.levels.WARN) {
        fetch(endpoint, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            level: methodName,
            logger: loggerName,
            message: args.join(' '),
            timestamp: Date.now(),
            url: window.location?.href
          })
        }).catch(err => {
          // Fail silently to avoid logging loops
        });
      }
    };
  };
  
  log.rebuild();
}

// Usage
createRemotePlugin('/api/logs');
log.error('Critical error'); // Logs locally AND sends to server

Conditional Logging Plugin

Add conditional logging based on environment or feature flags:

import log from 'loglevel';

function createConditionalPlugin(shouldLog) {
  const originalFactory = log.methodFactory;
  
  log.methodFactory = function(methodName, level, loggerName) {
    const rawMethod = originalFactory(methodName, level, loggerName);
    
    return function(...args) {
      // Check condition before logging
      if (shouldLog(methodName, level, loggerName, args)) {
        rawMethod(...args);
      }
    };
  };
  
  log.rebuild();
}

// Usage examples
// Only log in development
createConditionalPlugin(() => process.env.NODE_ENV === 'development');

// Only log specific modules
createConditionalPlugin((method, level, logger) => {
  return !logger || logger === 'database' || logger === 'api';
});

// Rate limiting
const logCounts = new Map();
createConditionalPlugin((method, level, logger, args) => {
  const key = `${logger}-${method}`;
  const count = logCounts.get(key) || 0;
  logCounts.set(key, count + 1);
  return count < 100; // Max 100 logs per method per logger
});

Formatting Plugin

Custom message formatting and structured logging:

import log from 'loglevel';

function createFormattingPlugin() {
  const originalFactory = log.methodFactory;
  
  log.methodFactory = function(methodName, level, loggerName) {
    const rawMethod = originalFactory(methodName, level, loggerName);
    
    return function(...args) {
      // Structured logging format
      const logEntry = {
        timestamp: new Date().toISOString(),
        level: methodName.toUpperCase(),
        logger: loggerName || 'root',
        message: args.length === 1 && typeof args[0] === 'string' 
          ? args[0]
          : args.map(arg => typeof arg === 'object' ? JSON.stringify(arg) : String(arg)).join(' ')
      };
      
      // Format as JSON for structured logging
      rawMethod(JSON.stringify(logEntry));
    };
  };
  
  log.rebuild();
}

// Usage
createFormattingPlugin();
log.info('User logged in', { userId: 123 });
// {"timestamp":"2023-10-01T12:00:00.000Z","level":"INFO","logger":"root","message":"User logged in {\"userId\":123}"}

Plugin Best Practices

Preserve Original Functionality

Always wrap the original method factory to maintain loglevel's reliability:

const originalFactory = log.methodFactory;
log.methodFactory = function(methodName, level, loggerName) {
  const rawMethod = originalFactory(methodName, level, loggerName);
  
  return function(...args) {
    // Your custom logic here
    try {
      // Custom processing
      processCustomLogic(methodName, args);
    } catch (error) {
      // Don't break logging if plugin fails
    }
    
    // Always call original method
    return rawMethod(...args);
  };
};

Handle Errors Gracefully

Plugin failures shouldn't break logging:

log.methodFactory = function(methodName, level, loggerName) {
  const rawMethod = originalFactory(methodName, level, loggerName);
  
  return function(...args) {
    try {
      // Plugin logic
      customBehavior(...args);
    } catch (error) {
      // Silently fail or use fallback
      console.error('Logging plugin error:', error);
    }
    
    return rawMethod(...args);
  };
};

Support All Loggers

Ensure plugins work with both root and named loggers:

log.methodFactory = function(methodName, level, loggerName) {
  const rawMethod = originalFactory(methodName, level, loggerName);
  
  return function(...args) {
    // Handle both root logger (loggerName === undefined) and named loggers
    const prefix = loggerName ? `[${String(loggerName)}]` : '[ROOT]';
    return rawMethod(prefix, ...args);
  };
};

// Rebuild all loggers
log.rebuild();

Memory Management

Be aware of memory usage in plugins:

// Avoid memory leaks in stateful plugins
const logCache = new Map();

log.methodFactory = function(methodName, level, loggerName) {
  const rawMethod = originalFactory(methodName, level, loggerName);
  
  return function(...args) {
    // Limit cache size
    if (logCache.size > 1000) {
      logCache.clear();
    }
    
    // Cache logic here
    return rawMethod(...args);
  };
};

docs

basic-logging.md

index.md

level-control.md

multi-logger.md

plugins.md

tile.json