Настройка файла error.log для логирования ошибок PHP

Раздел: Администрирование PHP -> Логирование и отладка

Файл ошибок PHP (error.log)

Как настроить централизованное логирование всех ошибок PHP в отдельный файл?

Наиболее эффективный способ - использование встроенной функции error_log() в сочетании с директивами php.ini. Это позволяет перехватывать все ошибки, предупреждения и уведомления и записывать их в единый файл, не мешая пользовательскому интерфейсу.

; php.ini
log_errors = On
error_log = /var/log/php_errors.log
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
; или E_ALL для продакшена можно E_ALL & ~E_DEPRECATED & ~E_NOTICE

Log файл php (работа с лог-файлами в php)

После изменения php.ini перезапустите веб-сервер (Apache, Nginx, PHP-FPM). Убедитесь, что файл /var/log/php_errors.log существует и доступен для записи пользователю, от которого работает PHP.

Типичная ошибка: файл не создаётся из-за недостаточных прав. Решение: выполнить touch /var/log/php_errors.log && chmod 666 /var/log/php_errors.log или изменить владельца на пользователя веб-сервера.

Другая проблема: логи не пишутся, но права в порядке. Проверьте, включена ли директива log_errors = On и что display_errors отключено (иначе ошибки могут выводиться на экран, но не в лог).

Для явной записи сообщений используйте:

<?php
error_log('Произошла ошибка: ' . $message, 3, '/tmp/myapp.log');
?>

файл error php (файл ошибок php (error.log))

Параметр 3 означает запись в файл. Если указать 0 - в системный лог (syslog).

Как сделать ротацию логов, чтобы не переполнить диск?

Используйте системную утилиту logrotate. Создайте конфигурационный файл для вашего лога:

/var/log/php_errors.log {
    daily
    rotate 7
    compress
    delaycompress
    missingok
    notifempty
    create 0640 www-data adm
}

Логи будут ежедневно архивироваться, храниться 7 дней, сжиматься. После ротации PHP должен открыть новый файл (можно использовать copytruncate или перезагружать php-fpm).

Проблема: после ротации PHP продолжает писать в старый удалённый файл. Решение: настроить copytruncate или использовать сигнал USR1 для PHP-FPM.

Как записывать ошибки в разные файлы в зависимости от уровня ошибки?

Стандартный error_log пишет всё в один файл. Для разделения можно создать свой обработчик через set_error_handler():

<?php
function customError($severity, $message, $file, $line) {
    if (error_reporting() & $severity) {
        $logFile = ($severity & E_WARNING) ? '/var/log/php_warnings.log' : '/var/log/php_errors.log';
        error_log("[$severity] $message in $file:$line", 3, $logFile);
    }
}
set_error_handler('customError');
?>

Фильтруйте по битам: E_WARNING, E_NOTICE, E_USER_ERROR и т.д.

Как использовать error_log() вместе с фреймворками (Laravel, Symfony)?

Фреймворки имеют собственные системы логирования (Monolog). Но если нужно дополнительно записать в файл error.log, можно вызвать error_log() напрямую или через фасад Log:: с указанием канала:

// Laravel
Log::channel('single')->error('Ошибка в контроллере');
// конфигурация config/logging.php -> 'single' => [ 'path' => storage_path('logs/laravel.log'), ... ]

Для записи в системный error.log PHP настройте канал 'syslog'.

Как мониторить ошибки в реальном времени из терминала?

Используйте tail -f /var/log/php_errors.log для просмотра новых записей. Для цветного вывода и фильтрации:

tail -f /var/log/php_errors.log | grep -E 'Fatal|Warning' --color=always

Можно написать скрипт, отправляющий уведомления при появлении ошибок определённого уровня.

Расширенные примеры работы с error.log PHP

1. Пример записи с трассировкой стека через debug_backtrace()

Пример
<?php
function logErrorWithTrace($message) {
    $trace = debug_backtrace();
    $log = date('[Y-m-d H:i:s] ') . $message . "\n";
    foreach ($trace as $i => $call) {
        $log .= "#$i " . ($call['file'] ?? 'unknown') . "(" . ($call['line'] ?? '?') . "): " . ($call['function'] ?? '?') . "\n";
    }
    error_log($log, 3, '/var/log/php_trace.log');
}

try {
    throw new Exception('Тестовая ошибка');
} catch (Exception $e) {
    logErrorWithTrace($e->getMessage());
}
?>
[2025-03-27 12:00:00] Тестовая ошибка
#0 /var/www/test.php(10): throw
#1 /var/www/test.php(14): {main}

Пояснение: функция собирает стек вызовов и записывает в лог дополнительно к сообщению. Помогает при отладке сложных багов.

2. Пример записи только фатальных ошибок через shutdown-функцию

Пример
<?php
register_shutdown_function(function() {
    $error = error_get_last();
    if ($error !== null && ($error['type'] === E_ERROR || $error['type'] === E_USER_ERROR)) {
        $log = sprintf("[FATAL] %s in %s:%d\n", $error['message'], $error['file'], $error['line']);
        error_log($log, 3, '/var/log/php_fatal.log');
    }
});
// вызов несуществующей функции
undefinedFunction();
?>
[FATAL] Call to undefined function undefinedFunction() in /var/www/test.php:12

Пояснение: shutdown-функция выполняется после завершения скрипта, и позволяет перехватить последнюю фатальную ошибку, не обрабатываемую error_handler.

3. Пример использования error_log() с разными типами сообщений (syslog, mail)

Пример
<?php
// запись в syslog с приоритетом LOG_ERR
error_log('Критическая ошибка базы данных', 0);
// отправка по email (малоэффективно для продакшена)
error_log('Срочная ошибка', 1, 'admin@example.com');
// запись в свой файл
error_log('Предупреждение', 3, '/var/log/php_warn.log');
?>

Пояснение: параметр 1 отправляет письмо (требуется настроенный sendmail), 0 - в syslog (обычно /var/log/syslog или /var/log/messages).

4. Пример настройки лога для конкретного виртуального хоста в Apache

Пример
<VirtualHost *:80>
    ServerName example.com
    php_admin_value error_log /var/log/apache2/example_php.log
    php_admin_flag log_errors on
    php_admin_value error_reporting E_ALL & ~E_DEPRECATED
</VirtualHost>

Пояснение: директивы php_admin_value позволяют переопределить настройки php.ini только для конкретного хоста. Удобно, когда на сервере несколько сайтов.

5. Пример ротации логов с помощью cron и скрипта на PHP

Пример
<?php
// rotate.php
$logFile = '/var/log/php_errors.log';
if (file_exists($logFile) && filesize($logFile) > 10*1024*1024) {
    $i = 1;
    while (file_exists($logFile . '.'.$i)) $i++;
    rename($logFile, $logFile.'.'.$i);
    touch($logFile);
    chmod($logFile, 0644);
}
?>
// crontab -e: 0 0 * * * /usr/bin/php /path/to/rotate.php

Пояснение: простая реализация ротации по размеру. Каждый день проверяется размер файла; если превышает 10 МБ, он переименовывается с индексом.

6. Пример логирования запросов к API с микротаймом

Пример
<?php
$start = microtime(true);
// ... обработка запроса ...
$duration = microtime(true) - $start;
$logLine = sprintf("[%s] %s %s %.4f сек\n", date('c'), $_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI'], $duration);
error_log($logLine, 3, '/var/log/api_requests.log');
?>
[2025-03-27T12:00:00+00:00] GET /api/users 0.0234 сек

Пояснение: помогает отслеживать медленные запросы и общую нагрузку.

Файл ошибок PHP (error.log) - comments

En
файл error php (php)