Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Як налаштувати логи Laravel для продакшену: JSON у stdout, процесори Monolog і власні канали?

Файл storage/logs/laravel.log зручний локально, але на продакшені з кількома серверами чи контейнерами логи мають збиратися централізовано (Loki, ELK, CloudWatch, Datadog), і читати їх буде не людина в tail, а система пошуку.

1. Канал у stderr для контейнерів:

// config/logging.php
'stderr' => [
    'driver' => 'monolog',
    'level' => env('LOG_LEVEL', 'info'),
    'handler' => StreamHandler::class,
    'handler_with' => ['stream' => 'php://stderr'],
    'formatter' => env('LOG_STDERR_FORMATTER'),
    'processors' => [PsrLogMessageProcessor::class],
],
LOG_CHANNEL=stderr
LOG_STDERR_FORMATTER=Monolog\Formatter\JsonFormatter

Docker збирає stderr контейнера, а JSON - по одному об'єкту на рядок - збирачі розбирають без регулярних виразів: рівень, повідомлення, контекст стають полями для фільтрації.

2. Процесори Monolog - додають дані до кожного запису:

'processors' => [
    PsrLogMessageProcessor::class,   // підставляє {placeholders} з контексту в повідомлення
    WebProcessor::class,             // url, метод, ip
    MemoryUsageProcessor::class,
],

3. tap - довільне налаштування логера каналу класом:

'stack' => [
    'driver' => 'stack',
    'tap' => [App\Logging\AddHostname::class],
    'channels' => ['stderr'],
],
final class AddHostname
{
    public function __invoke(Logger $logger): void
    {
        foreach ($logger->getHandlers() as $handler) {
            $handler->pushProcessor(function (LogRecord $record): LogRecord {
                return $record->with(extra: [...$record->extra, 'host' => gethostname()]);
            });
        }
    }
}

4. Стек каналів - різні рівні в різні місця:

'stack' => ['driver' => 'stack', 'channels' => ['stderr', 'slack'], 'ignore_exceptions' => false],
'slack' => ['driver' => 'slack', 'url' => env('LOG_SLACK_WEBHOOK_URL'), 'level' => 'critical'],

Що ще важливо:

  • кореляція: Context::add('trace_id', ...) у middleware - і всі записи запиту та його завдань у черзі пов'язані одним ідентифікатором;
  • канал deprecations - окремо від основного логу, щоб попередження про застарілий код не тонули й не засмічували його;
  • рівень на продакшені - info чи warning; debug швидко генерує гігабайти;
  • локальні файли без ротації на сервері рано чи пізно заповнять диск - daily з days або зовнішній збирач;
  • логи - не сповіщення: про критичні помилки має повідомляти система моніторингу помилок, а лог - для розслідування.

Докладніше в документації: Логування: налаштування Monolog для каналів

Схожі питання