# No console.log in production code

- **Pattern:** `ab-002145` (`code-quality-essentials.testing.no-console-log`)
- **Severity:** low
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-002145
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-002145)

## Why it matters

Debug `console.log` statements left in production code expose internal data structures, user data, and system internals in the browser console and server logs — visible to anyone who opens DevTools or has log access. ISO 25010:2011 §6.5.2 classifies this as a maintainability defect. Beyond the information exposure risk, uncontrolled log output fills log aggregators with noise, makes filtering for real errors harder, and signals to engineers that the codebase lacks basic hygiene standards.

## Severity rationale

Low because console.log leakage is primarily a hygiene and information-exposure issue rather than an immediate exploitable vulnerability, but it degrades log quality and can expose sensitive internal state.

## Remediation

Remove debug `console.log` statements from production source files. For intentional production logging, use a level-aware logger so output can be controlled by environment:

```typescript
// src/lib/logger.ts
const isDev = process.env.NODE_ENV === 'development'

export const logger = {
  info: (msg: string, data?: unknown) => {
    if (isDev) console.info('[info]', msg, data)
  },
  error: (msg: string, error?: unknown) => {
    console.error('[error]', msg, error) // always log errors
  },
}
```

Enforce via ESLint so it is caught in CI:
```json
{ "rules": { "no-console": ["error", { "allow": ["error", "warn"] }] } }
```

## Detection

- **ID:** `no-console-log`
- **Severity:** `low`
- **What to look for:** Search all files in `src/`, `app/`, `lib/`, and `pages/` directories for `console.log(` — excluding test files (`*.test.*`, `*.spec.*`, `__tests__/`) and development-only files. Each `console.log` found in production code is a debugging artifact that was left in accidentally. Production applications should use a structured logger (e.g., `pino`, `winston`, `consola`, or a custom logger utility) so output can be controlled by log level and configured per environment. Also check for `console.error` and `console.warn` — these are acceptable for logging actual errors in production, but raw `console.log` with debugging strings is not. Check the ESLint config for `no-console` rule presence.
- **Pass criteria:** Count all `console.log` occurrences in production source files. No `console.log` calls in production source files, OR ESLint is configured with `no-console: error` to prevent this automatically with at least 1 verified location.
- **Fail criteria:** `console.log` calls present in production source files outside of test utilities.
- **Skip (N/A) when:** Never — this applies to all projects with a build step.
- **Detail on fail:** `"Found N instances of console.log in production code (e.g., src/components/Header.tsx, src/lib/api.ts)"` (substitute actual locations)
- **Remediation:** Remove debugging `console.log` statements. For logging that should remain in production, use a level-aware logger:

  ```typescript
  // src/lib/logger.ts
  const isDev = process.env.NODE_ENV === 'development'

  export const logger = {
    info: (msg: string, data?: unknown) => {
      if (isDev) console.info('[info]', msg, data)
    },
    error: (msg: string, error?: unknown) => {
      console.error('[error]', msg, error) // always log errors
    },
  }
  ```

  To catch this in CI, add the ESLint rule:
  ```json
  { "rules": { "no-console": ["error", { "allow": ["error", "warn"] }] } }
  ```

## External references

- iso-25010 maintainability.analysability

Taxons: code-quality

HTML version: https://auditbuffet.com/patterns/ab-002145
