Пакет · logger

Прикрепление контекста запроса

Задайте поля вроде request_id или user_id один раз в начале запроса или задачи — и они автоматически появятся в каждой строке лога, без прокидывания через каждый вызов.

Как это работает

Каждый канал строится с автоматически прикреплённым ContextInjectingProcessor. На каждой записи лога он вливает снимок текущего ContextStorage в extra записи, так что любое заданное поле показывается, пока вы его не очистите. Настройка не нужна.

Задайте поля в начале работы

Достаньте хранилище через менеджер или фабрику, затем set() свои поля:

php
use Flytachi\Winter\Logger\LoggerFactory;

// В начале запроса (фронт-контроллер / middleware в FPM):
$ctx = LoggerFactory::contextStorage();
$ctx->set('request_id', $_SERVER['HTTP_X_REQUEST_ID'] ?? uniqid('req_'));
$ctx->set('user_id',    $userId);
$ctx->set('method',     $_SERVER['REQUEST_METHOD']);

// Любой вызов лога дальше несёт все три поля:
LoggerFactory::getLogger(self::class)->info('processing');
text
[2024-01-01 12:00:00] [INFO ] -http- [4821] (OrderController): processing {"class":"App\\Http\\OrderController","request_id":"req_65a1...","user_id":42,"method":"POST"}

Очищайте поля в конце работы

В процессе, который обрабатывает больше одной единицы работы, очищайте контекст между ними — иначе поля протекут в следующий запрос. Под FPM процесс умирает после каждого запроса, поэтому register_shutdown_function — чистый хук:

php
register_shutdown_function(
  fn () => LoggerFactory::contextStorage()->clear()
);

Долгоживущие процессы протекают без clear()

FPM сносит процесс за вас, но CLI-демон или Swoole-воркер переиспользуют один процесс. Там всегда clear() в конце каждой итерации/запроса — иначе request_id предыдущей задачи поедет вместе с логами следующей.

Паттерн демона в цикле

Для CLI-воркера, крутящегося вечно, задавайте поля на итерацию и очищайте внизу:

php
while (true) {
  $ctx = LoggerFactory::contextStorage();
  $ctx->set('iteration_id', uniqid('iter_'));

  processNextJob();

  $ctx->clear();   // сбрасываем поля этой итерации; процесс продолжает работу
}

Привязанный контекст против контекста запроса

Две разные области видимости — выбирайте по времени жизни:

Хотите поля на… Используйте Заметки
каждом логгере этого запроса/задачи contextStorage()->set() вливается процессором в extra
только одном конкретном логгере ->withContext([...]) возвращает новый логгер; вливается в context
php
// Для всего запроса — видит каждый логгер:
LoggerFactory::contextStorage()->set('request_id', $id);

// Только для этого логгера — не влияет на другие:
$log = LoggerFactory::getLogger(self::class)->withContext(['order_id' => 5001]);
$log->info('charged');

Удаление одного поля

forget() сбрасывает один ключ, не трогая остальные:

php
LoggerFactory::contextStorage()->forget('user_id');

Связанное