Настройка файла error.log для логирования ошибок 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_NOTICELog файл 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 сек
Пояснение: помогает отслеживать медленные запросы и общую нагрузку.