Быстрый старт
От установки до живой строки лога с контекстом запроса за пять минут: вы соберёте менеджер, зарегистрируете его один раз, зададите id запроса и увидите, как он автоматически появляется в каждой строке.
Что вы соберёте
Крошечный скрипт, который логирует из класса-сервиса и несёт request_id в каждой строке —
тот же цикл, что вы будете использовать в реальном приложении: настроить → зарегистрировать
→ задать контекст → логировать.
Перед началом
Установите пакет вместе с Monolog, чтобы получить реальный вывод:
composer require flytachi/winter-logger monolog/monologШаг 1 — Соберите LoggerManager
Менеджер принимает готовый конфиг. В реальном приложении цель вывода и хранилище контекста
определяет фреймворк; здесь вы передаёте их напрямую. Возьмите ProcessContext для FPM/CLI и
пишите в stdout, чтобы видеть вывод в терминале.
<?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::*() знали, куда писать.
use Flytachi\Winter\Logger\LoggerFactory;
LoggerFactory::setManager($manager);
LoggerFactory::setDefaultChannel('http');Шаг 3 — Задайте контекст запроса один раз
Задайте request_id в начале запроса. ContextInjectingProcessor — добавляемый к каждому
каналу автоматически — вольёт его в каждую последующую строку.
LoggerFactory::contextStorage()->set('request_id', 'req-abc-123');Шаг 4 — Логируйте откуда угодно
Используйте логгер на класс. Короткое имя класса появляется как (ClassName), а полный FQCN
хранится в контексте для запросов в агрегаторах.
// Логгер на класс — в стиле 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']);Запустите:
php log.phpВы увидите request_id в обеих строках, хотя задали его лишь однажды:
[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(). Он возвращает новый логгер; исходный не меняется.
$log = LoggerFactory::getLogger('App\\Service\\PaymentService')
->withContext(['order_id' => 5001]);
$log->info('payment started'); // несёт order_id
$log->info('payment done'); // несёт order_idВсё целиком
<?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.
Дальше
- Ментальная модель — три идеи, из которых следует всё
- Контекст запроса — задание и очистка полей запроса
- Корутины Swoole — изоляция контекста на запрос
- Динамические каналы — добавление каналов в рантайме
- Справочник API — каждый класс и метод