# Structured logging library is used

- **Pattern:** `ab-002314` (`saas-logging.app-logging.structured-logging`)
- **Severity:** high
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-002314
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-002314)

## Why it matters

CWE-778 (Insufficient Logging) and OWASP A09 (Security Logging & Monitoring Failures) both identify the absence of structured, machine-readable logs as a root cause of failed incident detection. When logging is ad-hoc `console.log` calls, production log platforms cannot parse, index, or alert on log data — a single exception swallowed in unstructured output can leave a breach undetected for days. NIST AU-2 requires that audit-relevant events be logged in a format that supports analysis; plain-text console output fails that bar. Structured JSON logs (with timestamp, level, message, and context fields) are what log aggregation platforms like Better Stack, Axiom, and Datadog index and query against.

## Severity rationale

High because unstructured logs disable the entire observability pipeline — alerting, search, and incident response all depend on parseable log entries.

## Remediation

Replace ad-hoc `console.log` calls with a central structured logger. For Next.js, Pino is the standard choice — fast, JSON-native, and supported by all major log platforms.

Create `lib/logger.ts`:
```ts
import pino from 'pino'
const logger = pino({
  level: process.env.LOG_LEVEL ?? 'info',
  ...(process.env.NODE_ENV === 'development'
    ? { transport: { target: 'pino-pretty' } }
    : {})
})
export default logger
```
Then replace every `console.log(...)` in server-side code with `logger.info(...)`, `logger.error(...)`, etc. Run a search for `console.log` in `app/api/` and `lib/` to find all call sites.

## Detection

- **ID:** `structured-logging`
- **Severity:** `high`
- **What to look for:** Enumerate all relevant files and Check `package.json` for structured logging libraries: winston, pino, bunyan, consola, loglevel, @opentelemetry/api, @logtail/node, axiom-node, or any cloud provider logging SDK. Also check for a custom logger module (`lib/logger.*`, `utils/logger.*`) that wraps `console` with structured output (JSON format with level, timestamp, and message fields). Plain `console.log` scattered throughout the codebase without a wrapper does not pass. Quote the exact code pattern or configuration value found.
- **Pass criteria:** At least 1 conforming pattern must exist. A structured logging library is present in dependencies, OR a custom logger module exists that produces JSON-formatted log entries with at minimum a timestamp, level, and message field. Usage of the logger is visible in server-side code (API routes, middleware, server components/actions).
- **Fail criteria:** No structured logging library found; logging is exclusively raw `console.log` / `console.error` calls spread throughout the codebase with no central logger abstraction. A partial or incomplete implementation does not count as pass.
- **Skip (N/A) when:** Project is a static site with no server-side code — no API routes, server components, server actions, or backend logic of any kind. Signal: no `app/api/` or `pages/api/` directory, no server functions, framework reports as static-only.
- **Cross-reference:** For security evaluation of log data handling and access controls, the Security Headers audit covers information exposure and data protection.
- **Detail on fail:** List the logging approach found. Example: `"No structured logging library in package.json; logging is ad-hoc console.log calls found in 12+ API route files with no central logger module"`
- **Remediation:** Ad-hoc `console.log` calls produce unstructured output that is hard to search, filter, and alert on in production log systems. A structured logger produces machine-readable JSON entries that platforms like Better Stack, Axiom, Datadog, and Sentry can index and query.

  For a Next.js project, install Pino (fast, JSON-native):
  ```bash
  npm install pino pino-pretty
  ```
  Create a central logger at `lib/logger.ts`:
  ```ts
  import pino from 'pino'
  const logger = pino({
    level: process.env.LOG_LEVEL || 'info',
    ...(process.env.NODE_ENV === 'development' ? { transport: { target: 'pino-pretty' } } : {})
  })
  export default logger
  ```
  Then import and use `logger.info(...)`, `logger.error(...)` instead of `console.log`.

  Verify by running the app and confirming log output is JSON in production mode.

## External references

- cwe CWE-778
- owasp A09
- nist AU-2
- iso-25010 maintainability

Taxons: observability

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