Как добавить дополнительную информацию (хост, URL и т. д.) в вывод журнала Symfony/Monolog?

Я работаю над своим первым проектом WebApp на основе Symfony. Я настроил Symfony не только для записи сообщений журнала в различные файлы журнала, но и для немедленной отправки сообщений о критических ошибках по электронной почте. Это прекрасно работает. Однако я хотел бы добавить некоторую дополнительную информацию в сообщения журнала по умолчанию, чтобы упростить поиск фактического источника ошибки.

Пример: файл Twig одной страницы загружает локализованный текст из файла .yml. Тексты содержат %about_link%placeholder, который следует заменить маршрутом/URL на страницу «О программе». Я забыл об этой замене, поэтому ссылка указывала не на URL, а на %about_link%. Это приводит к NotFoundHttpException, так как путь к %about_link% не найден...

Ничего страшного. Но найти настоящую страницу/контроллер, содержащую эту ошибку, было немного сложно. Сообщение журнала по умолчанию показывает следующее:

[2015-12-14 17:19:36] request.ERROR: Uncaught PHP Exception Symfony\Component\HttpKernel\Exception\NotFoundHttpException: "No route found for "GET /%25about_link%25"" at /long/path/to/symfony/.../RouterListener.php line 176 []

Таким образом, исключение было выброшено в RouterListener.php при попытке найти маршрут к %about_link%. Хорошо, это не дает мне никакого намека на то, на какой странице находится эта неверная ссылка.

Конечно, вызов плохого маршрута вообще не обязательно должен находиться на какой-либо странице. Пользователь мог напрямую ввести неверную ссылку. Symfony пришлось бы хранить/запоминать последнюю страницу, чтобы дать какую-либо подсказку о возможном источнике. Так можно ли вообще включать эту информацию?

Кроме того, я хотел бы добавить информацию о хосте, о котором сообщалось о проблеме. Я запускаю два экземпляра WebApp: www.my_web_app.xy и betatest.my_web_app.xy, и было бы здорово, если бы сообщение журнала показывало, исходит ли оно от www или от betatest.

Добавление этой информации в сообщения журнала, которые я создаю для себя, не проблема, но как я могу добавить эту информацию в сообщения, созданные Symfony или сторонним кодом? Мне нужно было бы каким-то образом перехватить сообщение журнала, прежде чем оно достигнет обработчика журнала. Это возможно?


person Andrei Herford    schedule 15.12.2015    source источник


Ответы (3)


Если вы хотите добавить дополнительную информацию в записи журнала, вы можете сделать это с помощью процессора. С помощью процессора вы можете изменить массив записей до того, как он будет проанализирован средством форматирования. Дополнительная часть отображается в конце записи журнала.

<?php

namespace AppBundle\Monolog;

use Symfony\Component\HttpFoundation\RequestStack;

class WebProcessor
{
    private $requestStack;

    public function __construct(RequestStack $requestStack)
    {
        $this->requestStack = $requestStack;
    }

    public function processRecord(array $record)
    {
        $request = $this->requestStack->getCurrentRequest();

        if ($request) {
            $record['extra']['host'] = $request->getHost();
            $record['extra']['url'] = $request->getRequestUri();
            // ...
        }

        return $record;
    }
}

Теперь добавьте его в свой services.yml, чтобы зарегистрировать его для всех записей журнала:

app.monolog.processor.web:
    class: AppBundle\Monolog\WebProcessor
    arguments: ["@request_stack"]
    tags:
        - { name: monolog.processor, method: processRecord }
person Emii Khaos    schedule 15.12.2015
comment
Обратите внимание, что в приведенном выше (хорошем) примере $request также может быть null, например. при запуске команды Symfony. - person Czechnology; 31.07.2016
comment
@Czechnology: правда! Этот фрагмент должен быть одним из первых, что нужно сделать в проекте Symfony, стандартные журналы иногда бесполезны. - person COil; 06.01.2017

Не изобретайте велосипед! Нет необходимости писать свой собственный WebProcessor, так как Monolog уже есть.

Единственное, что вам нужно сделать, это добавить его в свои сервисы и пометить тегом monolog.processor:

# app/config/services.yml
services:
    Monolog\Processor\WebProcessor:
        tags: ['monolog.processor']

В Monolog есть даже больше встроенных процессоров, которые вы можете использовать. Я решил добавить несколько процессоров в свое приложение:

# app/config/services/monolog.yml (I included services/*.yml in config.yml)
services:
    _defaults:
        tags: ['monolog.processor']
    Monolog\Processor\WebProcessor: ~
    Monolog\Processor\GitProcessor: ~
    Monolog\Processor\MemoryUsageProcessor: ~
    Monolog\Processor\MemoryPeakUsageProcessor: ~
    Monolog\Processor\IntrospectionProcessor: ~
person Stephan Vierkant    schedule 14.09.2017
comment
Это не изобретение велосипеда. Monolog WebProcessor использует глобальный $_SERVER, в то время как приведенный выше код использует запрос Symfony. Таким образом, ответ по-прежнему актуален в контексте symfony и служит более расширенным примером для всех, кто ищет в целом, как добавить больше контекста в сообщения журнала. - person Emii Khaos; 15.09.2017

Вы можете использовать пользовательский модуль форматирования для изменения вывода, записанного в файлы журнала monolog. Дополнительную информацию по этому вопросу можно найти здесь: http://symfony.com/doc/current/cookbook/logging/monolog.html#change-the-formatter

Краткая версия: вы можете создать собственный класс форматирования, который реализует Monolog\Formatter\FormatterInterface, и вы можете включить его в своем файле config.yml следующим образом:

# app/config/config.yml
services:
    my_formatter:
        class: Monolog\Formatter\JsonFormatter
monolog:
    handlers:
        file:
            type: stream
            level: debug
            formatter: my_formatter
person Wouter Sioen    schedule 15.12.2015
comment
Я понятия не имею, почему за этот ответ проголосовали против, поскольку он действительно дает очень хорошую отправную точку. Спасибо @Wouter за то, что указали мне на форматтеры. Однако ответ Патрика Кариша немного ближе к тому, что мне нужно, к тому, что я соглашусь с этим. - person Andrei Herford; 15.12.2015
comment
Я проголосовал за него по нескольким причинам. 1. просто скопировано из документа symfony без указания значения. 2. пример кода также скопирован без предоставления полезного средства форматирования, как это сделать (знание данной записи $ трудно найти). 3. форматтеры - это не способ добавить дополнительную информацию. - person Emii Khaos; 15.12.2015
comment
Форматтеры тоже добавляют дополнительную информацию. Вы можете вводить вещи (например, запрос) в свой модуль форматирования, поскольку это просто служба, использующая внедрение зависимостей. и используйте его, чтобы добавить дополнительную информацию в свои журналы. - person Wouter Sioen; 16.12.2015
comment
Я также скопировал его из документов, чтобы убедиться, что ответ по-прежнему актуален, если ссылки изменятся. - person Wouter Sioen; 16.12.2015