Файл ошибок PHP: как настроить логирование и анализировать сбои

Раздел: PHP -> Ошибки и отладка 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
)

Полезно для диагностики после выполнения сложного запроса.

Файл ошибок PHP - comments

En
файл ошибок php (php)