如何向 Symfony/Monolog 日志输出添加附加信息(主机、URL 等)?

How to add additional information (Host, URL, etc.) to Symfony/Monolog log output?

我正在开发我的第一个基于 Symfony 的 WebApp 项目。我已将 Symfony 配置为不仅将日志消息写入不同的日志文件,而且还可以立即通过电子邮件发送严重错误消息。这很好用。但是,我想在默认日志消息中添加一些附加信息,以便更容易找到实际的错误源。

示例: 一页的 Twig 文件从 .yml 文件加载本地化文本。文本包含一个 %about_link% 占位符,应将其替换为“关于”页面的 route/URL。我忘记了这个替换,所以 link 没有指向 URL 而是指向 %about_link% 。这会导致 NotFoundHttpException,因为找不到通往 %about_link% 的路径...

没什么大不了的。但是要找到包含此错误的实际 page/controller 有点棘手。默认日志消息显示如下:

[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% 的路线时抛出了异常。好吧,这并没有给我任何关于这个坏 link 所在页面的提示。

当然,对错误路由的调用根本不必位于任何页面上。用户可能直接输入了错误的 link。 Symfony 必须 store/remember 最后一页才能给出有关可能来源的任何提示。那么,是否可以包含这些信息?

此外,我想添加有关报告问题的主机的信息。我是 运行 WebApp 的两个实例:www.my_web_app.xybetatest.my_web_app.xy 如果日志消息显示来自 wwwbetatest

将此信息添加到我自己创建的日志消息中没有问题,但如何将此信息添加到由 Symfony 或第三方代码生成的消息中?在日志消息到达日志处理程序之前,我必须以某种方式拦截它。这可能吗?

您可以使用自定义格式化程序来更改写入 monolog 日志文件的输出。您可以在此处找到有关此主题的更多信息:http://symfony.com/doc/current/cookbook/logging/monolog.html#changing-the-formatter

简短版本:您可以创建一个实现 Monolog\Formatter\FormatterInterface 的自定义格式化程序 class,您可以通过以下方式在 config.yml 文件中启用它:

# app/config/config.yml
services:
    my_formatter:
        class: Monolog\Formatter\JsonFormatter
monolog:
    handlers:
        file:
            type: stream
            level: debug
            formatter: my_formatter

如果您想向日志条目添加额外的信息,您可以使用处理器来完成。使用处理器,您可以在格式化程序解析之前修改记录数组。额外的部分显示在日志条目的末尾。

<?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 }

不要重新发明轮子!无需编写自己的 WebProcessor,因为 Monolog already has it.

您唯一需要做的就是将其添加到您的服务中并用 monolog.processor 标记:

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

Monolog 甚至 more built-in processors 都可以使用。我决定在我的应用程序中添加多个处理器:

# 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: ~