Пакет · logger

Быстрый старт

От установки до живой строки лога с контекстом запроса за пять минут: вы соберёте менеджер, зарегистрируете его один раз, зададите id запроса и увидите, как он автоматически появляется в каждой строке.

Время ~5 минУровень НачальныйТребования PHP 8.3+, Monolog

Что вы соберёте

Крошечный скрипт, который логирует из класса-сервиса и несёт request_id в каждой строке — тот же цикл, что вы будете использовать в реальном приложении: настроить → зарегистрировать → задать контекст → логировать.

Перед началом

Установите пакет вместе с Monolog, чтобы получить реальный вывод:

bash
composer require flytachi/winter-logger monolog/monolog

Шаг 1 — Соберите LoggerManager

Менеджер принимает готовый конфиг. В реальном приложении цель вывода и хранилище контекста определяет фреймворк; здесь вы передаёте их напрямую. Возьмите ProcessContext для FPM/CLI и пишите в stdout, чтобы видеть вывод в терминале.

log.php
<?php

require 'vendor/autoload.php';

use Monolog\Level;
use Flytachi\Winter\Logger\LoggerManager;
use Flytachi\Winter\Logger\Context\ProcessContext;

$manager = new LoggerManager(
  contextStorage: new ProcessContext(),
  channels: [
      'http' => [
          'level'        => Level::Debug,
          'format'       => 'line',     // 'line' | 'json'
          'output'       => 'stdout',   // 'stdout' | 'stderr' | 'syslog' | 'file' | 'null'
          'file_path'    => null,
          'file_max'     => 30,
          'syslog_ident' => 'winter',
      ],
  ],
);

Каждый ключ конфига описан в Справочнике конфига канала.

Шаг 2 — Зарегистрируйте его в LoggerFactory

Сделайте это один раз при бутстрапе. После этого любой код может логировать, не касаясь менеджера. Задайте канал по умолчанию, чтобы getLogger() и Log::*() знали, куда писать.

php
use Flytachi\Winter\Logger\LoggerFactory;

LoggerFactory::setManager($manager);
LoggerFactory::setDefaultChannel('http');

Шаг 3 — Задайте контекст запроса один раз

Задайте request_id в начале запроса. ContextInjectingProcessor — добавляемый к каждому каналу автоматически — вольёт его в каждую последующую строку.

php
LoggerFactory::contextStorage()->set('request_id', 'req-abc-123');

Шаг 4 — Логируйте откуда угодно

Используйте логгер на класс. Короткое имя класса появляется как (ClassName), а полный FQCN хранится в контексте для запросов в агрегаторах.

php
// Логгер на класс — в стиле Java:
LoggerFactory::getLogger('App\\Service\\UserService')->info('user created', ['id' => 42]);

// Однострочный шорткат к каналу по умолчанию:
use Flytachi\Winter\Logger\Log;

Log::warning('rate limit hit', ['ip' => '10.0.0.1']);

Запустите:

bash
php log.php

Вы увидите request_id в обеих строках, хотя задали его лишь однажды:

text
[2024-01-01 12:00:00] [INFO ] -http- [4821] (UserService): user created {"id":42,"class":"App\\Service\\UserService","request_id":"req-abc-123"}
[2024-01-01 12:00:00] [WARN ] -http- [4821]: rate limit hit {"ip":"10.0.0.1","request_id":"req-abc-123"}

Шаг 5 — Привяжите контекст к логгеру

Чтобы прикрепить поля только к одному логгеру (а не ко всему запросу), используйте withContext(). Он возвращает новый логгер; исходный не меняется.

php
$log = LoggerFactory::getLogger('App\\Service\\PaymentService')
  ->withContext(['order_id' => 5001]);

$log->info('payment started');  // несёт order_id
$log->info('payment done');     // несёт order_id

Всё целиком

log.php
<?php

require 'vendor/autoload.php';

use Monolog\Level;
use Flytachi\Winter\Logger\LoggerManager;
use Flytachi\Winter\Logger\LoggerFactory;
use Flytachi\Winter\Logger\Context\ProcessContext;

$manager = new LoggerManager(
  contextStorage: new ProcessContext(),
  channels: [
      'http' => [
          'level'        => Level::Debug,
          'format'       => 'line',
          'output'       => 'stdout',
          'file_path'    => null,
          'file_max'     => 30,
          'syslog_ident' => 'winter',
      ],
  ],
);

LoggerFactory::setManager($manager);
LoggerFactory::setDefaultChannel('http');

LoggerFactory::contextStorage()->set('request_id', 'req-abc-123');

LoggerFactory::getLogger('App\\Service\\UserService')->info('user created', ['id' => 42]);

Что произошло

  • Менеджер лениво построил один канал Monolog (http) и закэшировал его.
  • ContextInjectingProcessor (автоматический) влил request_id в контекст каждой строки.
  • Логгер на класс отрисовал (UserService) и сохранил FQCN под ключом class.
  • SpringLineFormatter сформировал читаемую строку — дату-время, уровень, канал, PID.

Дальше