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
| Aspect | Details |
|---|---|
| Severity | Warning (best practice) |
| Auto-Fix | โ Yes (4 strategies: remove, convert, comment, warn) |
| Category | Development |
| ESLint MCP | โ Optimized for ESLint MCP integration |
| Best For | Production applications, teams migrating to structured logging |
| Strategies | Remove, Convert to logger, Comment out, Change to console.warn |
Rule Details
Why This Matters
| Issue | Impact | Solution |
|---|---|---|
| ๐ Security | May leak sensitive data in production | Use structured logging |
| ๐ Debugging | Clutters console, hard to filter | Environment-aware logging |
| โก Performance | Uncontrolled logging impacts speed | Configurable log levels |
| ๐ Observability | Cannot aggregate or analyze logs | Centralized logging systems |
Configuration
| Option | Type | Default | Description |
|---|---|---|---|
strategy | 'remove' | 'convert' | 'comment' | 'warn' | 'remove' | Remediation strategy |
ignorePaths | string[] | [] | Paths/patterns to ignore |
loggerName | string | 'logger' | Logger object name (e.g., 'logger', 'winston') |
maxOccurrences | number | undefined | Max violations to report (0 = report all) |
severityMap | object | {} | Map method names to logger methods (e.g., { log: 'info', debug: 'verbose' }) |
autoDetectLogger | boolean | true | Auto-detect logger import in file |
sourcePatterns | string[] | ['console'] | Object names to match and replace (e.g., ['console', 'winston', 'oldLogger']) |
customLogger | string | 'logger' | Deprecated: Use loggerName instead |
Strategy Comparison
| Strategy | Behavior | Use Case | Output |
|---|---|---|---|
| ๐๏ธ remove | Deletes statement | Production cleanup | console.log("x") โ (removed) |
| ๐ convert | Replace with logger | Migration to proper logging | console.log("x") โ logger.debug("x") |
| ๐ฌ comment | Comments out code | Temporary debugging | console.log("x") โ // console.log("x") |
| โก warn | Change to warning | Downgrade severity | console.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: removeStrategy: 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: convertOutput Format Breakdown
| Component | Purpose | Example |
|---|---|---|
โ ๏ธ console.log | Issue type | Clear identification |
src/services/auth.ts:127 | Location | File path + line number |
Strategy: convert | Action | Remediation 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
| Phase | Configuration | Goal |
|---|---|---|
| 1. Discovery | strategy: 'comment' | Identify all occurrences |
| 2. Setup Logger | Import logging library | Add infrastructure |
| 3. Convert | strategy: 'convert' | Auto-migrate code |
| 4. Cleanup | strategy: '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
| Scenario | Recommendation |
|---|---|
| ๐งช Prototyping | Disable or use warn severity |
| ๐ Tutorials | Add to ignorePaths |
| ๐ง Build Scripts | Use ignorePaths: ['scripts'] |
| ๐งช Test Files | Use ignorePaths: ['*.test.ts'] |
Comparison with Other Solutions
| Feature | quality/no-console-log | eslint-plugin-no-console | eslint 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
| Component | Purpose | Example |
|---|---|---|
| Risk Standards | Security benchmarks | CWE-532 OWASP:A09 CVSS:5.3 |
| Issue Description | Specific vulnerability | Log Information Exposure detected |
| Severity & Compliance | Impact assessment | MEDIUM [GDPR,HIPAA,PCI-DSS,SOC2] |
| Fix Instruction | Actionable remediation | Follow the remediation steps below |
| Technical Truth | Official reference | OWASP Top 10 |
When Not To Use
| Scenario | Recommendation |
|---|---|
| Prototyping | Disable or use warn severity |
| Tutorials | Add to ignorePaths |
| Build Scripts | Use ignorePaths: ['scripts'] |
| Test Files | Use ignorePaths: ['*.test.ts'] |
| Debugging | Use strategy: 'comment' to temporarily disable |
Comparison with Alternatives
| Feature | no-console-log | eslint-plugin-no-console | ESLint 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
- ESLint Rules Documentation - Complete ESLint rules reference
- Best Practices for Logging in Node.js - Production logging guide
- Structured Logging with Winston - Popular Node.js logging library
- MDN: Console API - Console API reference
- ESLint MCP Setup - Enable AI assistant integration
Related Rules
no-sql-injection- Prevents SQL injection vulnerabilitiesdetect-non-literal-fs-filename- Prevents path traversal
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 trackedMitigation: 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 trackedMitigation: Ensure imported values follow the same constraints. Use TypeScript for type safety.