Файл ошибок PHP: как настроить логирование и анализировать сбои
Основные принципы работы с файлом ошибок PHP
Как настроить централизованное логирование всех ошибок PHP в отдельный файл?
Наиболее эффективный способ - изменить конфигурацию php.ini. Параметры log_errors, error_log и error_reporting определяют, какие ошибки и куда записываются.
Пример конфигурации в php.ini:
log_errors = On
error_log = /var/log/php_errors.log
error_reporting = E_ALLфайл ошибок php (файл ошибок php)
Пояснение: log_errors включает запись, error_log задаёт путь к файлу (убедитесь, что веб-сервер имеет права на запись), error_reporting указывает уровни ошибок (E_ALL - все, включая нотисы).
Типичная проблема: файл не создаётся или остаётся пустым. Решение: проверить права на каталог и файл, а также что уровень error_reporting включает логируемые ошибки. Также следует убедиться, что параметр display_errors отключён в рабочей среде (display_errors = Off), иначе ошибки выводятся на экран, но могут не попадать в лог.
Как включить логирование без доступа к php.ini?
Функция ini_set() позволяет менять директивы во время выполнения скрипта. Это удобно для хостингов с ограничениями.
ini_set('log_errors', '1');
ini_set('error_log', '/home/user/logs/php_errors.log');
ini_set('error_reporting', E_ALL & ~E_NOTICE);Php mysql ошибки (ошибки php mysql)
Примечание: директивы, помеченные как PHP_INI_SYSTEM, нельзя переопределить. log_errors и error_log обычно доступны (PHP_INI_ALL или PHP_INI_PERDIR).
Ошибка: вызывает только предупреждения, не фатальные ошибки, так как ini_set() может не сработать для некоторых директив. Рекомендуется проверять в документации.
Как настроить логирование через .htaccess в Apache?
Если используется mod_php, директивы можно задавать в .htaccess с помощью php_value и php_flag.
php_flag log_errors on
php_value error_log /home/site/errors.log
php_value error_reporting 32767
Значение 32767 соответствует E_ALL в десятичной системе. Для выбора уровней удобнее использовать константы.
Проблема: .htaccess не читается, если AllowOverride не разрешён. В таком случае обратиться к администратору сервера.
Как создать собственный обработчик для расширенного логирования?
Функция set_error_handler() позволяет перехватывать ошибки и записывать их в произвольном формате.
function customError($severity, $message, $file, $line) {
$log = "[" . date('Y-m-d H:i:s') . "] [$severity] $message в $file:$line\n";
file_put_contents(__DIR__ . '/custom_errors.log', $log, FILE_APPEND | LOCK_EX);
return true; // не передаём стандартному обработчику
}
set_error_handler('customError');
Цель: детализированный лог с временной меткой, возможность отправки уведомлений.
Ограничение: set_error_handler() не перехватывает фатальные ошибки (E_ERROR, E_CORE_ERROR и т.д.). Для них нужен shutdown handler.
Как ловить фатальные ошибки с помощью shutdown handler?
Регистрируется функция, вызываемая при завершении скрипта, и проверяется последняя ошибка через error_get_last().
register_shutdown_function(function() {
$error = error_get_last();
if ($error && ($error['type'] === E_ERROR || $error['type'] === E_USER_ERROR)) {
file_put_contents('fatal.log', print_r($error, true), FILE_APPEND);
}
});
Этот способ дополняет пользовательский обработчик для критических сбоев.
Как использовать syslog для централизованного сбора?
Параметр error_log можно установить в syslog. Тогда сообщения будут отправляться в системный лог.
ini_set('error_log', 'syslog');
Или в php.ini: error_log = syslog. Подходит для серверов с централизованным логированием.
Расширенные примеры настройки файла ошибок PHP
Далее представлены более неочевидные сценарии и приёмы.
Запись в разные файлы по типу ошибки
Можно разделить предупреждения и фатальные ошибки с помощью пользовательского обработчика.
function smartErrorHandler($severity, $message, $file, $line) {
$logDir = __DIR__ . '/logs';
if (!is_dir($logDir)) mkdir($logDir, 0777, true);
$logFile = ($severity & (E_ERROR | E_WARNING)) ? 'critical.log' : 'notice.log';
$entry = date('Y-m-d H:i:s') . " [$severity] $message в $file:$line" . PHP_EOL;
file_put_contents("$logDir/$logFile", $entry, FILE_APPEND | LOCK_EX);
}
set_error_handler('smartErrorHandler');
trigger_error('Тестовое уведомление', E_USER_NOTICE);
trigger_error('Тестовая ошибка', E_USER_WARNING);
Файл notice.log: 2025-03-22 12:00:00 [1024] Тестовое уведомление в /path/to/script.php:17 Файл critical.log: 2025-03-22 12:00:00 [512] Тестовая ошибка в /path/to/script.php:18
Класс тяжести 1024 - E_USER_NOTICE, 512 - E_USER_WARNING.
Автоматическая ротация логов с помощью cron
Логи могут занимать много места. Ротация по расписанию через системный cron или сам PHP.
// Скрипт rotate.php
$logFile = '/var/log/php_errors.log';
$maxSize = 10 * 1024 * 1024; // 10 MB
if (file_exists($logFile) && filesize($logFile) > $maxSize) {
$backup = $logFile . '.' . date('Y-m-d_H:i:s');
rename($logFile, $backup);
touch($logFile);
chmod($logFile, 0644);
echo "Ротация выполнена: $backup\n";
}
Выполнять по cron ежедневно: 0 3 * * * php /path/to/rotate.php
Логирование в формате JSON для анализатора
Современные системы (ELK, Graylog) лучше работают со структурированными данными.
function jsonErrorHandler($severity, $message, $file, $line) {
$entry = json_encode([
'timestamp' => date('c'),
'severity' => $severity,
'message' => $message,
'file' => $file,
'line' => $line
]) . PHP_EOL;
file_put_contents('errors.json', $entry, FILE_APPEND);
}
set_error_handler('jsonErrorHandler');
trigger_error('Пример JSON лога', E_USER_WARNING);
Содержимое errors.json:
{"timestamp":"2025-03-22T12:00:00+00:00","severity":512,"message":"Пример JSON лога","file":"...","line":10}
Отправка критических ошибок на email
Совмещение записи в файл и уведомления по почте.
function emailOnFatal($message, $file, $line) {
$to = 'admin@example.com';
$subject = 'Критическая ошибка на сайте';
$body = "Ошибка: $message\nФайл: $file\nСтрока: $line\n";
file_put_contents('errors.log', $body, FILE_APPEND);
mail($to, $subject, $body);
}
register_shutdown_function(function() {
$error = error_get_last();
if ($error && $error['type'] === E_ERROR) {
emailOnFatal($error['message'], $error['file'], $error['line']);
}
});
Важно: не злоупотреблять, чтобы не завалить почтовый ящик.
Интеграция с Monolog (комплексный подход)
Библиотека Monolog предоставляет гибкие каналы и форматирование.
// Установка: composer require monolog/monolog
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\NativeMailerHandler;
$log = new Logger('app');
$log->pushHandler(new StreamHandler(__DIR__ . '/app.log', Logger::WARNING));
$log->pushHandler(new NativeMailerHandler('admin@example.com', 'Ошибка', 'отладчик@example.com', Logger::CRITICAL));
$log->warning('Предупреждение: значение вне диапазона');
$log->error('Критическая ошибка базы данных');
В app.log: [2025-03-22T12:00:00+00:00] app.WARNING: Предупреждение: значение вне диапазона [] [] [2025-03-22T12:00:01+00:00] app.ERROR: Критическая ошибка базы данных [] []
Использование error_get_last для анализа последней ошибки
Позволяет извлечь информацию о последней произошедшей ошибке, даже если обработчик не перехватил её.
@file_get_contents('/несуществующий_файл');
$lastError = error_get_last();
if ($lastError) {
print_r($lastError);
}
Array
(
[type] => 2
[message] => file_get_contents(/несуществующий_файл): Failed to open stream: No such file or directory
[file] => /path/to/script.php
[line] => 2
)
Полезно для диагностики после выполнения сложного запроса.