Логирование доступа
OxPHP формирует структурированные access-логи в формате JSON для каждого HTTP-запроса и пишет их в stdout. Логирование выполняется асинхронно, поэтому никогда не блокирует обработку запросов.
Как это работает
Когда задана переменная ACCESS_LOG, OxPHP после каждого завершённого запроса пишет в stdout одну JSON-строку. Эти записи буферизуются в фоновом потоке-писателе, поэтому логирование никогда не блокирует конвейер обработки запросов.
Режим определяет, что именно записывается. ACCESS_LOG=all логирует каждый запрос; ACCESS_LOG=error логирует только ответы со статусом 400 и выше.
Каждая строка лога содержит поле request_id, которое связывает записи access-лога с логами вашего приложения. Когда включено распространение W3C Trace Context, записи также содержат поля trace_id и span_id.
Конфигурация
| Переменная | Значение по умолчанию | Описание |
|---|---|---|
ACCESS_LOG |
(не задано) | Режим access-лога. all логирует каждый запрос; error логирует только ответы 4xx и 5xx. Оставьте не заданной или пустой, чтобы отключить |
Допустимы только значения all и error. Задание нераспознанного значения приводит к записи предупреждения и отключает access-логирование.
Формат лога
Каждая запись access-лога — это одна JSON-строка, записываемая в stdout:
{
"timestamp": "2026-02-11T12:34:56.789012Z",
"level": "INFO",
"fields": {
"request_id": "67890abc12341a2b0042",
"method": "GET",
"path": "/api/users",
"status": 200,
"duration_us": 1234,
"remote_ip": "10.0.0.1",
"message": "request completed"
}
}Когда активен W3C Trace Context, поля trace_id и span_id включаются наряду со стандартными полями:
{
"timestamp": "2026-02-11T12:34:56.789012Z",
"level": "INFO",
"fields": {
"request_id": "67890abc12341a2b0042",
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
"span_id": "00f067aa0ba902b7",
"method": "POST",
"path": "/api/orders",
"status": 201,
"duration_us": 8421,
"remote_ip": "10.0.0.1",
"message": "request completed"
}
}Поля
| Поле | Тип | Описание |
|---|---|---|
request_id |
строка | Уникальный идентификатор запроса. См. Идентификаторы запросов |
method |
строка | HTTP-метод (GET, POST и т. д.) |
path |
строка | Путь URI запроса |
status |
число | Код статуса HTTP-ответа |
duration_us |
число | Общее время обработки запроса в микросекундах |
remote_ip |
строка | IP-адрес клиента (без порта). Когда настроена переменная TRUSTED_PROXIES, отображается реальный IP клиента, извлечённый из заголовков перенаправления, а не IP прокси |
trace_id |
строка | W3C trace ID (присутствует только при TRACE_CONTEXT=true) |
span_id |
строка | W3C span ID (присутствует только при TRACE_CONTEXT=true) |
Тонкая фильтрация
OxPHP использует внутреннюю цель логирования access_log для записей access-лога. Используйте переменную RUST_LOG, чтобы фильтровать access-логи независимо от остального вывода логов:
# Suppress general info messages, keep access logs
RUST_LOG=warn,access_log=infoЦель access_log используется для фильтрации через RUST_LOG, но не включается в JSON-вывод. Чтобы идентифицировать записи access-лога в нижестоящих системах, используйте поле "message": "request completed" и характерный набор полей (method, path, status, duration_us).
Устранение неполадок
Записи access-лога не появляются
Access-логирование отключено, когда переменная ACCESS_LOG не задана или пуста.
Решение: задайте переменной значение all или error:
ACCESS_LOG=allAccess-логи в режиме `error`, но успешные запросы отсутствуют
ACCESS_LOG=error логирует только ответы со статусом 400 и выше. Это ожидаемое поведение — проверьте значение и переключитесь на all, если нужно логировать все запросы.
Проверка: подтвердите активную настройку:
curl -s http://localhost:9090/config | jq '.access_log'Записи лога появляются без `trace_id` и `span_id`
Поля контекста трассировки присутствуют только при включённом распространении W3C Trace Context.
Решение: включите его так:
TRACE_CONTEXT=trueИ убедитесь, что вышестоящий клиент или балансировщик нагрузки отправляет заголовок traceparent в запросах.
Пример для Docker
services:
app:
image: ghcr.io/oxphp/oxphp:0.10.0
ports:
- "80:80"
- "9090:9090"
volumes:
- ./src:/var/www/html:ro
environment:
ACCESS_LOG: "all"
ENTRY_FILE: "index.php"
INTERNAL_ADDR: "0.0.0.0:9090"Рекомендации
- Используйте
ACCESS_LOG=errorв production, чтобы уменьшить объём логов, продолжая фиксировать все неудачные запросы. Успешные запросы не логируются, но ошибки с любым статусом 400+ фиксируются всегда. - Включайте идентификатор запроса в логи приложения через
oxphp_request_id(), чтобы связывать записи логов уровня PHP с записями access-лога. - Используйте структурированный агрегатор логов, такой как Elasticsearch, Loki или Datadog, для эффективного поиска и фильтрации JSON-строк логов.
Интеграция
Поскольку логи — это JSON-строки в stdout, они напрямую интегрируются с драйверами логов контейнеров и инструментами агрегации:
- Docker — собираются автоматически через драйвер логов контейнера (json-file, fluentd и другие)
- Kubernetes — подхватываются агентом логов на узле (Fluentd, Fluent Bit, Filebeat и другие)
- systemd — захватываются при запуске в виде службы systemd с логированием stdout через journald
Не требуется ни sidecar, ни доставка логов на основе файлов.
См. также
- Идентификаторы запросов — каждая запись лога содержит
request_idдля трассировки - Справочник по конфигурации — полный справочник переменных окружения