Логирование
Rapira пишет записи лога в stderr. К ним относятся события сервера, решения мастер-процесса, события HTTP и gRPC, диагностика PHP и сообщения приложения. PHP отправляет свою диагностику в этот лог, когда параметр ini error_log пуст. Это значение по умолчанию.
Уровень по умолчанию - error, поэтому stderr содержит только ошибки. Измените секцию [log] или задайте RUST_LOG, чтобы выбрать другой уровень.
Уровни и формат
Секция [log] файла rapira.toml управляет логированием в stderr:
[log]
level = "error" # Use error, warn, info, debug, or trace. Default: error.
format = "plain" # Use plain or json. Default: plain.level задаёт минимальный уровень для всех целей. error показывает только ошибки, а каждый следующий уровень добавляет записи. trace показывает все записи. format выбирает читаемые строки или один объект JSON на строку.
Оба ключа и вся секция необязательны. Остальные секции файла описаны в разделе Конфигурация.
Уровни для отдельных целей
[log.targets] заменяет глобальный уровень для отдельных целей. Например, он может включить отладочные записи PHP и оставить выключенными отладочные записи HTTP:
[log]
level = "error"
[log.targets]
php = "debug"
http = "warn"Каждый ключ называет одну цель. Остальные цели используют level. Ключ сопоставляется по префиксу, поэтому h2 также соответствует путям модулей h2::codec и h2::proto зависимости. Подмодули перечислять не нужно.
Rapira использует эти цели:
| Цель | О чём пишет |
|---|---|
rapira | инициализация сервера, жизненный цикл воркеров, остановка |
master | состояние пулов, ошибки создания процессов, предупреждения о готовности при перезагрузке и таймаутах запросов |
http | слушатели HTTP, обработка полей запроса и ответа, остановка |
grpc | слушатели gRPC, сбои транспорта, остановка |
net | цикл приёма соединений слушателей HTTP и gRPC, сбои приёма |
observability | процесс метрик и проб: слушатель, завершение запросов, сбои |
php | вывод и диагностика от самого PHP |
app | записи, которые приложение пишет через \Rapira\log() |
Rapira не пишет журнал доступа с одной строкой для каждого запроса. Записи полей цели http описаны в разделе Запросы и ответы HTTP.
Зависимость записывает трассировку под путём своего модуля. К этим записям применяется тот же префиксный фильтр. Каждая запись содержит имя цели. Добавьте это имя в [log.targets], чтобы изменить уровень этой цели.
Цель master сообщает о состоянии пулов, ошибках создания процессов, предупреждениях о готовности при перезагрузке и таймаутах запросов. Надзор за пулами описан в разделе Модель процессов.
Диагностика PHP
Rapira направляет диагностику PHP в цель php. Каждый тип ошибки PHP соответствует уровню лога:
| Тип сообщения | Уровень |
|---|---|
Фатальные ошибки - E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR | error |
Предупреждения - E_WARNING, E_CORE_WARNING, E_COMPILE_WARNING, E_USER_WARNING | warn |
Уведомления - E_NOTICE, E_USER_NOTICE | info |
Сообщения об устаревании - E_DEPRECATED, E_USER_DEPRECATED | debug |
Сообщения об устаревании используют debug. Поэтому сообщения об устаревании из зависимостей не скрывают предупреждения и ошибки.
Rapira задаёт диагностике уровень trace, если error_reporting её исключает. Например:
<?php
error_reporting(E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED);Эта маска исключает сообщения об устаревании из зависимостей. Задайте level = "trace", чтобы записать их.
PHP не пишет диагностику, исключённую маской. В режимах Worker и Dispatcher Rapira пишет последнюю диагностику PHP в определённых точках. Режим Worker делает это после запуска инициализации, после каждого задания и при завершении входного скрипта. Режим Dispatcher делает это только при завершении входного скрипта. Поэтому Rapira пишет исключённую маской диагностику, только если она последняя перед одной из этих точек. Режим Classic не пишет диагностику, исключённую маской.
Фатальные ошибки всегда сохраняют уровень error, поэтому error_reporting(0) не скрывает их. Маска также не применяется к E_CORE_ERROR и E_CORE_WARNING, потому что PHP создаёт их до того, как скрипт может задать маску.
Rapira отправляет диагностику в лог, а не в ответы. Она задаёт значение по умолчанию 0 для display_errors и 1 для log_errors. Значение из php.ini заменяет эти значения по умолчанию.
Вывод PHP вне ответа попадает в цель php с уровнем info. Например, echo при запуске инициализации в режиме Worker попадает в лог. В режиме Dispatcher весь вывод echo попадает в лог, потому что ответы используют API диспетчера. Уровень по умолчанию error скрывает эти записи. Задайте php = "info" в [log.targets], чтобы показать их.
Логирование из приложения
\Rapira\log() пишет запись в цель app. Функция принимает сообщение, необязательный уровень и необязательный массив контекста. Функция доступна в каждом режиме выполнения:
<?php
\Rapira\log('order placed');
\Rapira\log('payment declined', \Rapira\LogLevel::Warning);
\Rapira\log('cache miss', \Rapira\LogLevel::Debug, ['key' => 'user:42', 'ttl' => 300]);Уровень - это случай перечисления \Rapira\LogLevel. Каждый случай соответствует уровню лога Rapira:
Случай LogLevel | Уровень записи |
|---|---|
Error | error |
Warning | warn |
Info | info |
Debug | debug |
Trace | trace |
\Rapira\log() использует Info, если параметр level не задан. Уровень по умолчанию error скрывает записи Info. Задайте app = "info" в [log.targets], чтобы записать их.
Rapira кодирует массив контекста как текст JSON и добавляет его как поле context. В выводе JSON fields.context - это строка, а не вложенный объект. Текст JSON сохраняет имена ключей и структуру вложенных массивов. Декодируйте эту строку в сборщике логов, чтобы прочитать ключи:
<?php
\Rapira\log('checkout failed', \Rapira\LogLevel::Error, [
'order' => 41,
'totals' => ['net' => 1250, 'tax' => 250],
]);Rapira раскрывает Throwable, который является значением верхнего уровня контекста. Это нужно, потому что json_encode() возвращает пустой объект для Throwable. Rapira не раскрывает Throwable во вложенном массиве, поэтому он кодируется как пустой объект. Раскрытое значение содержит класс, сообщение, код, файл и строку. Оно также содержит до четырёх исключений previous. Оно не содержит трассировку стека:
<?php
try {
$gateway->charge($order);
} catch (\Throwable $e) {
\Rapira\log('charge failed', \Rapira\LogLevel::Error, ['exception' => $e]);
}\Rapira\log() не бросает исключения. Если вызов jsonSerialize() для значения контекста бросает исключение, Rapira записывает для этого значения null. Другие ключи сохраняются.
Форматы
Rapira пишет оба формата в stderr. Большие записи из разных процессов могут перемешаться, когда эти процессы пишут в один канал stderr.
Перенаправьте stderr, чтобы записывать логи в файл. Менеджер служб может собирать stderr. Подробнее см. раздел Запуск в продакшене.
plain - это читаемый вывод для терминала. Он содержит отметку времени, уровень, цель и сообщение:
2026-07-30T09:12:34.567890Z ERROR php: …Rapira использует цвет, только когда stderr является терминалом. Задайте непустое значение NO_COLOR, чтобы отключить цвет в терминале.
json выводит один объект на строку для сборщика логов:
{"timestamp":…,"level":"ERROR","fields":{"message":…},"target":…}timestamp использует RFC 3339, UTC и микросекунды. Объект fields содержит сообщение и другие поля записи. Например, он может содержать поле приложения context. Rapira экранирует переводы строк в сообщениях, например в трассировках стека PHP. Поэтому каждая запись занимает ровно одну строку. Вывод JSON не использует цвет.
RUST_LOG
RUST_LOG задаёт фильтр логов stderr из окружения. Команды ниже изменяют фильтр и не изменяют файл конфигурации:
RUST_LOG=info rapira serve rapira.toml
RUST_LOG=error,rapira=debug,php=info rapira serve rapira.toml
RUST_LOG=warn,rapira=trace,master=trace rapira serve rapira.tomlПервая команда задаёт info для всех целей. Вторая задаёт debug для rapira, info для php и error для всех остальных целей. Третья задаёт warn для всех целей и trace для rapira и master.
Цель, которой не соответствует значение, не пишет записей. Например, RUST_LOG=php=info скрывает все ошибки целей master и http. Добавьте уровень без имени цели, например error, чтобы сохранить записи других целей.
Непустое значение RUST_LOG заменяет level и [log.targets]. Rapira не объединяет фильтры окружения и файла. Удалите переменную, чтобы использовать настройки файла конфигурации. Также можно задать переменной пустое значение. RUST_LOG не влияет на format.
Почему предупреждение PHP появляется в логе два раза?
В режимах Worker и Dispatcher Rapira также пишет последнюю диагностику PHP. Если эта диагностика не исключена маской, PHP тоже пишет её. Поэтому лог содержит две записи с одним уровнем и разными текстовыми форматами.
Как Rapira сериализует большие контексты логов?
Rapira кодирует контекст с флагом JSON_PARTIAL_OUTPUT_ON_ERROR. Ресурс или недопустимая строка UTF-8 становится null. NAN и INF становятся 0. Другие поля остаются в записи.
Rapira не сокращает массивы и строки. Передавайте идентификаторы вместо больших объектов.