Log Levels Best Practices
debt(d5/e3/b5/t7)
Closest to 'specialist tool catches it' (d5). The detection_hints list monolog, phpcs, and semgrep — these are specialist tools (a logging library, a code sniffer, and a SAST tool) that can flag patterns like everything-at-ERROR or DEBUG-in-production. This is not caught by the compiler or a default linter out-of-the-box, but semgrep rules and phpcs sniffs can be configured to detect the common code patterns listed.
Closest to 'simple parameterised fix' (e3). The quick_fix describes a mapping — replace ERROR with the appropriate level (WARNING, INFO, DEBUG) per category of event. This is a pattern-replacement across call sites (e.g., changing log(ERROR, ...) to log(WARNING, ...) for ValidationExceptions), which is more than a single-line patch but contained within logging call sites rather than a cross-cutting architectural change.
Closest to 'persistent productivity tax' (b5). The applies_to covers web, cli, and queue-worker contexts — all major PHP execution contexts. A missing or inconsistent logging strategy imposes an ongoing tax: alert fatigue slows incident response, on-call engineers develop pager-blindness, and every new feature requires a judgment call about levels with no agreed convention. This affects many work streams but doesn't fully define the system's shape.
Closest to 'serious trap' (t7). The misconception is explicit: developers believe logging everything at ERROR ensures nothing is missed, but the opposite is true — ERROR-level noise causes alert fatigue so real errors are ignored. This contradicts reasonable intuition ('more severe label = safer') and maps to how similar concepts work in other systems where verbosity is often considered harmless. The 'obvious' action (use ERROR to be safe) actively degrades production observability.
Also Known As
TL;DR
Explanation
PSR-3 defines 8 levels (emergency, alert, critical, error, warning, notice, info, debug). Practical usage: ERROR — something failed and needs attention (failed payment, unhandled exception), WARNING — something unexpected happened but recovered (cache miss, retry succeeded), INFO — normal business events (user logged in, order placed), DEBUG — detailed diagnostic data (SQL queries, API calls, method entries). Production should run at INFO or WARNING level. Never log DEBUG in production — it overwhelms aggregators and may expose sensitive data.
Common Misconception
Why It Matters
Common Mistakes
- Logging 404 responses as ERROR — 404 is expected user behaviour; use INFO or DEBUG.
- Logging all exceptions as ERROR — a ValidationException is a WARNING or INFO; an uncaught exception is ERROR.
- DEBUG logs in production — fills aggregators with noise and may log sensitive request data.
- No logging strategy — different team members log identical events at different levels.
Code Examples
// Everything at ERROR — alert fatigue:
$logger->error('User ' . $userId . ' visited /about'); // This is INFO at most
$logger->error('Cache miss for key ' . $key); // This is DEBUG
$logger->error('User provided invalid email'); // This is WARNING
// Real errors get lost in noise — on-call team ignores all alerts
// Correct levels:
$logger->debug('Cache miss', ['key' => $key]); // Diagnostic
$logger->info('User logged in', ['user_id' => $id]); // Business event
$logger->warning('Payment retry', ['attempt' => 2]); // Unexpected but OK
$logger->error('Payment failed permanently', [ // Needs attention
'order_id' => $orderId,
'error' => $e->getMessage(),
]);
// Production runs at INFO — DEBUG suppressed