Skip to content

Логирование ​

Rapira пишет записи лога в stderr. К ним относятся события сервера, решения мастер-процесса, события HTTP и gRPC, диагностика PHP и сообщения приложения. PHP отправляет свою диагностику в этот лог, когда параметр ini error_log пуст. Это значение по умолчанию.

Уровень по умолчанию - error, поэтому stderr содержит только ошибки. Измените секцию [log] или задайте RUST_LOG, чтобы выбрать другой уровень.

Уровни и формат ​

Секция [log] файла rapira.toml управляет логированием в stderr:

toml
[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:

toml
[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_ERRORerror
Предупреждения - E_WARNING, E_CORE_WARNING, E_COMPILE_WARNING, E_USER_WARNINGwarn
Уведомления - E_NOTICE, E_USER_NOTICEinfo
Сообщения об устаревании - E_DEPRECATED, E_USER_DEPRECATEDdebug

Сообщения об устаревании используют debug. Поэтому сообщения об устаревании из зависимостей не скрывают предупреждения и ошибки.

Rapira задаёт диагностике уровень trace, если error_reporting её исключает. Например:

php
<?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
<?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Уровень записи
Errorerror
Warningwarn
Infoinfo
Debugdebug
Tracetrace

\Rapira\log() использует Info, если параметр level не задан. Уровень по умолчанию error скрывает записи Info. Задайте app = "info" в [log.targets], чтобы записать их.

Rapira кодирует массив контекста как текст JSON и добавляет его как поле context. В выводе JSON fields.context - это строка, а не вложенный объект. Текст JSON сохраняет имена ключей и структуру вложенных массивов. Декодируйте эту строку в сборщике логов, чтобы прочитать ключи:

php
<?php

\Rapira\log('checkout failed', \Rapira\LogLevel::Error, [
    'order' => 41,
    'totals' => ['net' => 1250, 'tax' => 250],
]);

Rapira раскрывает Throwable, который является значением верхнего уровня контекста. Это нужно, потому что json_encode() возвращает пустой объект для Throwable. Rapira не раскрывает Throwable во вложенном массиве, поэтому он кодируется как пустой объект. Раскрытое значение содержит класс, сообщение, код, файл и строку. Оно также содержит до четырёх исключений previous. Оно не содержит трассировку стека:

php
<?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 - это читаемый вывод для терминала. Он содержит отметку времени, уровень, цель и сообщение:

text
2026-07-30T09:12:34.567890Z ERROR php: …

Rapira использует цвет, только когда stderr является терминалом. Задайте непустое значение NO_COLOR, чтобы отключить цвет в терминале.

json выводит один объект на строку для сборщика логов:

text
{"timestamp":…,"level":"ERROR","fields":{"message":…},"target":…}

timestamp использует RFC 3339, UTC и микросекунды. Объект fields содержит сообщение и другие поля записи. Например, он может содержать поле приложения context. Rapira экранирует переводы строк в сообщениях, например в трассировках стека PHP. Поэтому каждая запись занимает ровно одну строку. Вывод JSON не использует цвет.

RUST_LOG ​

RUST_LOG задаёт фильтр логов stderr из окружения. Команды ниже изменяют фильтр и не изменяют файл конфигурации:

sh
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 не сокращает массивы и строки. Передавайте идентификаторы вместо больших объектов.