Skip to main content
ESLint Interlace
Plugin: operabilityRules

no-console-log

Disallow console.log with configurable remediation strategies and LLM-optimized output. This rule is part of eslint-plugin-operability and provides 4 auto-f

Keywords: console.log, logging, ESLint rule, production logging, structured logging, logger migration, auto-fix, LLM-optimized, code quality, debugging, observability, Winston, Pino

Disallow console.log with configurable remediation strategies and LLM-optimized output. This rule is part of eslint-plugin-operability and provides 4 auto-fix strategies for migrating from console.log to proper logging.

Quick Summary

AspectDetails
SeverityWarning (best practice)
Auto-Fixโœ… Yes (4 strategies: remove, convert, comment, warn)
CategoryDevelopment
ESLint MCPโœ… Optimized for ESLint MCP integration
Best ForProduction applications, teams migrating to structured logging
StrategiesRemove, Convert to logger, Comment out, Change to console.warn

Rule Details

Why This Matters

IssueImpactSolution
๐Ÿ”’ SecurityMay leak sensitive data in productionUse structured logging
๐Ÿ› DebuggingClutters console, hard to filterEnvironment-aware logging
โšก PerformanceUncontrolled logging impacts speedConfigurable log levels
๐Ÿ“Š ObservabilityCannot aggregate or analyze logsCentralized logging systems

Configuration

OptionTypeDefaultDescription
strategy'remove' | 'convert' | 'comment' | 'warn''remove'Remediation strategy
ignorePathsstring[][]Paths/patterns to ignore
loggerNamestring'logger'Logger object name (e.g., 'logger', 'winston')
maxOccurrencesnumberundefinedMax violations to report (0 = report all)
severityMapobject{}Map method names to logger methods (e.g., { log: 'info', debug: 'verbose' })
autoDetectLoggerbooleantrueAuto-detect logger import in file
sourcePatternsstring[]['console']Object names to match and replace (e.g., ['console', 'winston', 'oldLogger'])
customLoggerstring'logger'Deprecated: Use loggerName instead

Strategy Comparison

StrategyBehaviorUse CaseOutput
๐Ÿ—‘๏ธ removeDeletes statementProduction cleanupconsole.log("x") โ†’ (removed)
๐Ÿ”„ convertReplace with loggerMigration to proper loggingconsole.log("x") โ†’ logger.debug("x")
๐Ÿ’ฌ commentComments out codeTemporary debuggingconsole.log("x") โ†’ // console.log("x")
โšก warnChange to warningDowngrade severityconsole.log("x") โ†’ console.warn("x")

Examples

โŒ Incorrect

function processData(data: any) {
  console.log('Processing data:', data);
  return data.map((item) => item * 2);
}

class UserService {
  getUser(id: string) {
    console.log('Fetching user:', id);
    return this.db.users.find(id);
  }
}

โœ… Correct

import { logger } from './logger';

function processData(data: any) {
  logger.debug('Processing data:', { data });
  return data.map((item) => item * 2);
}

class UserService {
  getUser(id: string) {
    this.logger.debug('Fetching user', { userId: id });
    return this.db.users.find(id);
  }
}

Configuration Examples

Basic Usage (Default Strategy)

// eslint.config.mjs
export default [
  {
    rules: {
      'operability/no-console-log': 'error',
    },
  },
];

Output Format:

โš ๏ธ console.log | src/app.ts:42 | Strategy: remove

Strategy: Remove (Production Cleanup)

{
  rules: {
    'operability/no-console-log': ['error', {
      strategy: 'remove'
    }]
  }
}
// Before
function calculate() {
  console.log('Calculating...');
  return 42;
}

// After (auto-fixed)
function calculate() {
  return 42;
}

Strategy: Convert (Logger Migration)

{
  rules: {
    'operability/no-console-log': ['error', {
      strategy: 'convert',
      loggerName: 'logger',      // Replace 'console' with 'logger'
      loggerMethod: 'info'        // Replace '.log()' with '.info()'
    }]
  }
}
// Before
console.log('User logged in', userId);

// After (auto-fixed)
logger.info('User logged in', userId);

With Custom Logger (e.g., Winston):

{
  rules: {
    'operability/no-console-log': ['error', {
      strategy: 'convert',
      loggerName: 'winston',
      severityMap: {
        'log': 'info',      // console.log โ†’ winston.info
        'debug': 'debug',   // console.debug โ†’ winston.debug
        'error': 'error',   // console.error โ†’ winston.error
        'warn': 'warn'      // console.warn โ†’ winston.warn
      }
    }]
  }
}
// Before
console.log('Processing request');
console.debug('Debug details');
console.error('Something failed');

// After (auto-fixed)
winston.info('Processing request');
winston.debug('Debug details');
winston.error('Something failed');

Strategy: Comment (Temporary Disable)

{
  rules: {
    'operability/no-console-log': ['error', {
      strategy: 'comment'
    }]
  }
}
// Before
console.log('Debug info', data);

// After (auto-fixed)
// console.log("Debug info", data);

Strategy: Warn (Downgrade Severity)

{
  rules: {
    'operability/no-console-log': ['error', {
      strategy: 'warn'
    }]
  }
}
// Before
console.log('Important notice');

// After (auto-fixed)
console.warn('Important notice');

Ignore Specific Paths

{
  rules: {
    'operability/no-console-log': ['error', {
      strategy: 'remove',
      ignorePaths: [
        'test',           // Ignore test directories
        'scripts',        // Ignore scripts directory
        '*.test.ts',      // Ignore test files
        'src/debug.ts'    // Ignore specific file
      ]
    }]
  }
}

Limit Reported Violations

{
  rules: {
    'operability/no-console-log': ['error', {
      maxOccurrences: 10  // Only report first 10 violations
    }]
  }
}

Replace Multiple Logging Objects (Legacy Projects)

Perfect for migrating legacy projects with mixed logging approaches:

{
  rules: {
    'operability/no-console-log': ['error', {
      strategy: 'convert',
      loggerName: 'logger',                          // Target logger
      sourcePatterns: ['console', 'winston', 'oldLogger'],  // Replace all these
      severityMap: {
        log: 'info',
        debug: 'debug',
        error: 'error',
        warn: 'warn'
      }
    }]
  }
}
// Before (mixed legacy logging)
console.log('User action');
winston.info('Database query');
oldLogger.debug('Cache hit');

// After (auto-fixed to unified logger)
logger.info('User action');
logger.info('Database query');
logger.debug('Cache hit');

Safety: Uses exact string matching - won't accidentally match consoleUI or winstonConfig.

Custom Severity Mapping

Map specific console methods to different logger methods:

{
  rules: {
    'operability/no-console-log': ['error', {
      strategy: 'convert',
      loggerName: 'logger',
      loggerMethod: 'info',       // Default for unmapped methods
      severityMap: {
        'log': 'info',             // console.log โ†’ logger.info
        'debug': 'verbose',        // console.debug โ†’ logger.verbose
        'error': 'error',          // console.error โ†’ logger.error
        'warn': 'warn'             // console.warn โ†’ logger.warn
      }
    }]
  }
}

Result:

// Before
console.log('Info message');
console.debug('Debug message');
console.error('Error message');

// After (auto-fixed)
logger.info('Info message');
logger.verbose('Debug message');
logger.error('Error message');

Auto-Detect Logger

{
  rules: {
    'operability/no-console-log': ['error', {
      strategy: 'convert',
      autoDetectLogger: true,     // Auto-detect 'logger', 'log', etc. in imports
      loggerName: 'winston',      // Fallback if no logger detected
      loggerMethod: 'info'        // Method to use
    }]
  }
}

Auto-detection example:

// If you have this import
import { myLogger } from './utils';

// console.log will be converted to
myLogger.info(...)  // Auto-detected 'myLogger' (contains 'log')

Team-Specific Configurations

// Development environment
{
  rules: {
    'operability/no-console-log': ['warn', {
      strategy: 'comment',
      ignorePaths: ['test', 'scripts']
    }]
  }
}

// Production environment
{
  rules: {
    'operability/no-console-log': ['error', {
      strategy: 'convert',
      customLogger: 'logger',
      maxOccurrences: 0  // Report all violations
    }]
  }
}

Type-Safe Configuration (ESLint 9+ & 8)

ESLint 9+ (Flat Config)

import operability from 'eslint-plugin-operability';
import type { NoConsoleLogOptions } from 'eslint-plugin-operability/types';

const config: NoConsoleLogOptions = {
  strategy: 'remove',
  ignorePaths: ['src/logger/**', 'src/debug/**'],
  loggerName: 'logger',
  autoDetectLogger: true,
};

export default [
  {
    plugins: { operability },
    rules: {
      'operability/no-console-log': ['warn', config],
    },
  },
];

ESLint 8 (Legacy Config with JSDoc Types)

/** @type {import('eslint-plugin-operability/types').NoConsoleLogOptions} */
const config = {
  strategy: 'remove',
  ignorePaths: ['src/logger/**', 'src/debug/**'],
  loggerName: 'logger',
  autoDetectLogger: true,
};

module.exports = {
  plugins: ['operability'],
  rules: {
    'operability/no-console-log': ['warn', config],
  },
};

For more examples and patterns, see the package README.

LLM-Optimized Output

The rule provides minimal, actionable messages optimized for both humans and LLMs:

โš ๏ธ console.log | src/services/auth.ts:127 | Strategy: convert

Output Format Breakdown

ComponentPurposeExample
โš ๏ธ console.logIssue typeClear identification
src/services/auth.ts:127LocationFile path + line number
Strategy: convertActionRemediation method

Multi-Strategy Suggestions

When a violation is detected, all strategies are available as suggestions:

โš ๏ธ console.log | src/app.ts:42 | Strategy: remove

Suggestions:
  ๐Ÿ—‘๏ธ Remove console.log statement
  ๐Ÿ”„ Convert to logger.debug()
  ๐Ÿ’ฌ Comment out console.log
  โšก Replace with console.warn()

Migration Patterns

From console.log to Structured Logging

Step-by-Step Migration

PhaseConfigurationGoal
1. Discoverystrategy: 'comment'Identify all occurrences
2. Setup LoggerImport logging libraryAdd infrastructure
3. Convertstrategy: 'convert'Auto-migrate code
4. Cleanupstrategy: 'remove'Remove debugging logs

Advanced Usage

Monorepo Configuration

// apps/web/eslint.config.mjs
{
  rules: {
    'operability/no-console-log': ['error', {
      strategy: 'remove',
      ignorePaths: ['test']
    }]
  }
}

// apps/api/eslint.config.mjs
{
  rules: {
    'operability/no-console-log': ['error', {
      strategy: 'convert',
      customLogger: 'winston',
      ignorePaths: ['scripts', 'migrations']
    }]
  }
}

CI/CD Integration


- name: Lint with auto-fix
  run: |
    npm run lint -- --fix
    git diff --exit-code || echo "Console.log violations auto-fixed"

When Not To Use

ScenarioRecommendation
๐Ÿงช PrototypingDisable or use warn severity
๐Ÿ“š TutorialsAdd to ignorePaths
๐Ÿ”ง Build ScriptsUse ignorePaths: ['scripts']
๐Ÿงช Test FilesUse ignorePaths: ['*.test.ts']

Comparison with Other Solutions

Featurequality/no-console-logeslint-plugin-no-consoleeslint built-in
โœ… Auto-fixโœ… 4 strategiesโŒ NoโŒ No
๐ŸŽฏ Suggestionsโœ… All strategiesโŒ NoโŒ No
๐Ÿ“ ignorePathsโœ… Pattern matchingโŒ Noโš ๏ธ Limited
๐Ÿค– LLM-optimizedโœ… YesโŒ NoโŒ No
๐Ÿ”„ Logger migrationโœ… ConfigurableโŒ NoโŒ No

Error Message Format

The rule provides LLM-optimized error messages (Compact 2-line format) with actionable security guidance:

โš ๏ธ [CWE-532](https://cwe.mitre.org/data/definitions/532.html) OWASP:A09 CVSS:5.3 | Log Information Exposure detected | MEDIUM [GDPR,HIPAA,PCI-DSS,SOC2]
   Fix: Review and apply the recommended fix | https://owasp.org/Top10/A09_2021/

Message Components

ComponentPurposeExample
Risk StandardsSecurity benchmarksCWE-532 OWASP:A09 CVSS:5.3
Issue DescriptionSpecific vulnerabilityLog Information Exposure detected
Severity & ComplianceImpact assessmentMEDIUM [GDPR,HIPAA,PCI-DSS,SOC2]
Fix InstructionActionable remediationFollow the remediation steps below
Technical TruthOfficial referenceOWASP Top 10

When Not To Use

ScenarioRecommendation
PrototypingDisable or use warn severity
TutorialsAdd to ignorePaths
Build ScriptsUse ignorePaths: ['scripts']
Test FilesUse ignorePaths: ['*.test.ts']
DebuggingUse strategy: 'comment' to temporarily disable

Comparison with Alternatives

Featureno-console-logeslint-plugin-no-consoleESLint built-in no-console
Auto-Fixโœ… Yes (4 strategies)โŒ NoโŒ No
Logger Migrationโœ… ConfigurableโŒ NoโŒ No
ignorePathsโœ… Pattern matchingโŒ Noโš ๏ธ Limited
LLM-Optimizedโœ… YesโŒ NoโŒ No
ESLint MCPโœ… OptimizedโŒ NoโŒ No
Strategy Optionsโœ… 4 strategiesโŒ NoโŒ No

Further Reading

Known False Negatives

The following patterns are not detected due to static analysis limitations:

Dynamic Variable References

Why: Static analysis cannot trace values stored in variables or passed through function parameters.

// โŒ NOT DETECTED - Value from variable
const value = externalSource();
processValue(value); // Variable origin not tracked

Mitigation: Implement runtime validation and review code manually. Consider using TypeScript branded types for validated inputs.

Wrapped or Aliased Functions

Why: Custom wrapper functions or aliased methods are not recognized by the rule.

// โŒ NOT DETECTED - Custom wrapper
function myWrapper(data) {
  return internalApi(data); // Wrapper not analyzed
}
myWrapper(unsafeInput);

Mitigation: Apply this rule's principles to wrapper function implementations. Avoid aliasing security-sensitive functions.

Imported Values

Why: When values come from imports, the rule cannot analyze their origin or construction.

// โŒ NOT DETECTED - Value from import
import { getValue } from './helpers';
processValue(getValue()); // Cross-file not tracked

Mitigation: Ensure imported values follow the same constraints. Use TypeScript for type safety.