PHP error_log configuration, Xdebug with VS Code, step debugging, slow query detection, and the common error patterns we see across 12 production sites.
The Debugging Toolkit
When something breaks in production at 2 AM, you need to diagnose and fix it fast. Our debugging toolkit for JekCMS has three layers: error logs for catching exceptions, Xdebug for stepping through complex logic, and profiling for finding performance bottlenecks.
PHP Error Log Configuration
JekCMS configures error logging based on environment:
// Production: log errors, never display
ini_set('display_errors', 0);
ini_set('log_errors', 1);
ini_set('error_log', ROOT_PATH . '/logs/php-error.log');
error_reporting(E_ALL);
// Development: display and log
ini_set('display_errors', 1);
ini_set('log_errors', 1);
error_reporting(E_ALL);
The log file is in logs/php-error.log, protected from web access by .htaccess rules. We rotate logs weekly to prevent them from growing unbounded.
JekCMS Log Structure
Beyond PHP errors, JekCMS logs application events:
// Custom logging
function cms_log(string $level, string $message, array $context = []): void
{
$logFile = ROOT_PATH . '/logs/cms-' . date('Y-m-d') . '.log';
$entry = sprintf(
"[%s] [%s] %s %s
",
date('Y-m-d H:i:s'),
strtoupper($level),
$message,
$context ? json_encode($context, JSON_UNESCAPED_UNICODE) : ''
);
file_put_contents($logFile, $entry, FILE_APPEND | LOCK_EX);
}
// Usage
cms_log('error', 'Post publish failed', ['post_id' => 42, 'reason' => $e->getMessage()]);
cms_log('info', 'Cache cleared by admin', ['user' => $currentUser['name']]);
cms_log('warning', 'Rate limit approaching', ['ip' => $clientIp, 'count' => $requestCount]);
Xdebug Setup with VS Code
Xdebug is the standard PHP debugging extension. Install it, configure php.ini, and connect VS Code:
; php.ini
[xdebug]
zend_extension=xdebug
xdebug.mode=debug,profile
xdebug.start_with_request=trigger
xdebug.client_port=9003
xdebug.client_host=127.0.0.1
In VS Code, install the PHP Debug extension, add a launch configuration for "Listen for Xdebug", set breakpoints in your PHP files, and trigger debugging with the XDEBUG_TRIGGER cookie or query parameter.
Step debugging is invaluable for complex issues like "why does this post show the wrong category?" Set a breakpoint in the post query, step through the code, inspect variables at each step, and find the exact line where the logic diverges from expectations.
Slow Query Detection
JekCMS's Database class measures query execution time:
public function query(string $sql, array $params = []): PDOStatement
{
$start = microtime(true);
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);
$duration = microtime(true) - $start;
if ($duration > 0.5) { // Queries over 500ms
cms_log('warning', 'Slow query', [
'sql' => $sql,
'duration' => round($duration, 3) . 's',
'params' => $params,
]);
}
return $stmt;
}
This catches unoptimized queries in production without any performance overhead (the timing adds microseconds). We review slow query logs weekly and add indexes or optimize queries as needed.
Common Error Patterns
- 500 Internal Server Error: Usually a PHP syntax error or fatal exception. Check
logs/php-error.logfirst. - Headers Already Sent: HTML output before a
header()call orsession_start(). Move POST processing before any output. - CSRF Token Mismatch: Session expired or browser back button. Regenerate token on the form page.
- Session Lost After Login: Cross-site session (site_hash mismatch). Check SESSION_NAME is unique per site.
- Images Not Loading: Check file permissions (755 for directories, 644 for files) and verify the uploads path in the database does not have a double
uploads/prefix.
Production Monitoring
For production sites, we check logs daily using a simple script that emails us if any ERROR-level entries appear in the last 24 hours. This catches issues before users report them. The script runs as a cron job at 8 AM every morning.