Error Logging
debt(d7/e5/b7/t7)
Closest to 'only careful code review or runtime testing' (d7). The detection_hints.tools field is empty, so no specialist tool is cited from metadata. Missing or misconfigured error logging (e.g. display_errors=On in production, no log aggregation, no alerting) is not caught by the compiler, linter, or a standard SAST scan — it only becomes apparent when reviewing configuration files carefully or when a production incident reveals that no logs were captured. Slightly better than d9 because a code review of php.ini or bootstrap config will surface it.
Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix mentions setting error_reporting(E_ALL), log_errors=On, display_errors=Off, and adding Monolog with a file handler plus Sentry. This is more than a one-liner: it involves php.ini or runtime config changes, installing and wiring a logging library (Monolog), setting up Sentry integration, adding contextual data to existing log calls across the codebase, and configuring log rotation and alerting. That spans multiple files and components, landing squarely at e5.
Closest to 'strong gravitational pull' (b7). Error logging applies to both web and CLI contexts (applies_to: web, cli) and is a cross-cutting concern in any PHP application. Every component that handles errors, exceptions, or warnings must integrate with the chosen logging strategy. The choice of logging library (Monolog/PSR-3), log destination, and aggregation service shapes how every future feature is instrumented. Poorly set up logging silently degrades over time (file bloat, no alerting) affecting all work streams — a persistent, wide-reaching structural burden.
Closest to 'serious trap' (t7). The misconception field explicitly states: 'Logging errors means they are visible and actionable.' A competent developer naturally assumes that writing to a log file constitutes effective error management. The trap is that file-based logs accumulate unread, no alerting fires, errors go unnoticed for days, and the developer believes the system is monitored when it is not. This contradicts the intuitive expectation that 'I set up logging, therefore I will know about errors' — a serious, well-documented gotcha that most developers only learn after a painful production incident.
Also Known As
TL;DR
Explanation
PHP error logging has two layers: PHP's built-in error logging (configured via error_log in php.ini or error_log() function) and application-level logging (PSR-3 compatible libraries like Monolog, used by Laravel and Symfony). PHP logs errors to the file specified by error_log directive, or to the web server error log. Monolog supports structured logging with context arrays, multiple output handlers (file, Slack, email, Elasticsearch), and log levels following RFC 5424 (DEBUG, INFO, NOTICE, WARNING, ERROR, CRITICAL, ALERT, EMERGENCY). Production configuration: error_reporting(E_ALL), log_errors=On, display_errors=Off, log_errors_max_len=0. For exceptions: use a global exception handler (set_exception_handler()) or middleware to log uncaught exceptions before showing a generic error page. Error aggregation services (Sentry, Bugsnag, Flare) group duplicate errors, track frequency, and alert on new error types.
Common Misconception
Why It Matters
Common Mistakes
- Setting display_errors=On in production — exposes sensitive error details to end users and attackers.
- Not setting error_reporting(E_ALL) — missing E_NOTICE and E_DEPRECATED hides warnings about deprecated features that break on upgrade.
- Not including context in log messages — log('Payment failed') is useless; log('Payment failed', ['user_id' => $id, 'amount' => $amount, 'gateway_response' => $response]) is actionable.
- Logging sensitive data — never log passwords, full credit card numbers, or session tokens; log IDs and non-sensitive identifiers instead.
- Logging to stdout in CLI scripts without timestamps — makes post-mortem impossible; always prefix every line with a machine-parseable timestamp.
Code Examples
// display_errors=On in production — leaks internals
// No structured logging — useless for diagnosis
try {
$payment->charge($amount);
} catch (Exception $e) {
error_log($e->getMessage()); // no context
echo 'Error: ' . $e->getMessage(); // shown to user!!
}
// Structured logging with context
try {
$payment->charge($amount);
} catch (PaymentException $e) {
$this->logger->error('Payment charge failed', [
'user_id' => $user->id,
'amount' => $amount,
'gateway' => $payment->gateway(),
'gateway_code' => $e->getCode(),
'exception' => $e->getMessage(),
]);
// Show generic message to user
throw new UserFacingException('Payment could not be processed.');
}