Пакет · logger

Интеграция с фреймворком

Библиотека не зависит от инфраструктуры: она никогда не читает env-переменные и не определяет рантайм. Это делает ваш бутстрап — строит конфиг и подключает логгер. Вот разделение ответственности и точный порядок вызовов.

Кто что делает

Шаг Ответственность Кто вызывает
Разрешить env → конфиг (уровни, вывод, пути) инфраструктура ядро фреймворка
Собрать LoggerManager инфраструктура ядро фреймворка
setManager() зарегистрировать один раз ядро фреймворка
setDefaultChannel() выбрать активный канал точка входа
setContextStorage() выбрать стратегию изоляции точка входа (Swoole)

Ядро строит и регистрирует менеджер. Точка входаpublic/index.php, раннер Swoole или CLI-скрипт — знает реальный рантайм, поэтому задаёт канал по умолчанию и (для Swoole) хранилище контекста.

Бутстрап — зарегистрируйте менеджер один раз

bootstrap.php
<?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: [
      'sys'  => ['level' => Level::Warning, 'format' => 'line', 'output' => 'stderr',
                 'file_path' => null, 'file_max' => 30, 'syslog_ident' => 'winter'],
      'http' => ['level' => Level::Info,    'format' => 'line', 'output' => 'stderr',
                 'file_path' => null, 'file_max' => 30, 'syslog_ident' => 'winter'],
      'cli'  => ['level' => Level::Debug,   'format' => 'line', 'output' => 'stdout',
                 'file_path' => null, 'file_max' => 30, 'syslog_ident' => 'winter'],
  ],
);

LoggerFactory::setManager($manager);

Точки входа — выберите канал и хранилище под рантайм

Каждая точка входа подключает бутстрап, затем объявляет свой рантайм:

public/index.php — FPM
<?php

require '../bootstrap.php';

// FPM: один запрос = один процесс, ProcessContext уже правильный.
LoggerFactory::setDefaultChannel('http');
swoole_server.php — Swoole
<?php

require '../bootstrap.php';

use Flytachi\Winter\Logger\Context\CoroutineContext;

// Swoole: переключитесь на изолированный по корутинам контекст до приёма запросов.
LoggerFactory::setContextStorage(new CoroutineContext());
LoggerFactory::setDefaultChannel('http');
раннер CLI
<?php

require 'bootstrap.php';

// CLI-задачи / воркеры очередей / демоны.
LoggerFactory::setDefaultChannel('cli');

Порядок важен

setManager() — всегда первым. setContextStorage() и addChannel() работают с текущим менеджером, поэтому должны идти после него. Каждый из них также очищает поклассовый кэш логгеров, поэтому задавайте их на бутстрапе — не посреди запроса.

Использование из кода приложения

После подключения код приложения никогда не видит менеджер:

php
use Flytachi\Winter\Logger\LoggerFactory;
use Flytachi\Winter\Logger\Log;

// Логгер на класс на канале по умолчанию:
LoggerFactory::getLogger(self::class)->info('user created', ['id' => 42]);

// Быстрый однострочник:
Log::warning('rate limit hit');

Рекомендуемые каналы по умолчанию

Распространённая конвенция (как в winter-kernel):

Канал Типичное использование Вывод по умолчанию
sys системные события, фолбэк stderr
http контроллеры, сервисы (FPM/Swoole) stderr (FPM) / stdout (Swoole)
cli задачи, воркеры очередей, демоны stdout

stderr для FPM, stdout для Swoole

Под FPM php://stdout — это поток ответа FastCGI: запись в него после отключения клиента рискует broken pipe. Там предпочтителен stderr. Swoole обрабатывает ответы своим I/O, поэтому stdout безопасен. См. Вывод и broken pipe.

Сброс в тестах

LoggerFactory хранит статическое состояние. Пересоберите его в setUp(), чтобы тесты не делили менеджер:

php
protected function setUp(): void
{
  LoggerFactory::setManager($this->buildManager());
}

Связанное