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

Posted

技术标签:

【中文标题】如何向 Symfony/Monolog 日志输出添加附加信息(主机、URL 等)?【英文标题】:How to add additional information (Host, URL, etc.) to Symfony/Monolog log output? 【发布时间】:2016-03-20 22:21:52 【问题描述】:

我正在开发我的第一个基于 Symfony 的 WebApp 项目。我已将 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 []

因此,在尝试查找到%about_link% 的路由时,RouterListener.php 中引发了异常。好的,这并没有给我任何关于这个坏链接位于哪个页面的提示。

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

此外,我想添加有关报告问题的主机的信息。我正在运行 WebApp 的两个实例:www.my_web_app.xybetatest.my_web_app.xy,如果日志消息显示它是来自 www 还是来自 betatest,这将是一个很大的帮助。

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

【问题讨论】:

【参考方案1】:

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

【讨论】:

我不知道为什么这个答案被否决了,因为它实际上提供了一个很好的起点。感谢@Wouter 将我指向格式化程序。然而,Patrik Karisch 的回答更接近我的需要,我会接受这个。 由于几个原因,我否决了它。 1. 从 symfony 文档中简单复制,不提供任何价值。 2. 代码示例也被复制,但没有提供有用的格式化程序如何去做(知道给定的 $record 很难找到)。 3.格式化程序不是添加额外信息的方式。 格式化程序也是一种添加额外信息的方法。您可以在格式化程序中注入东西(如请求),因为它只是使用依赖注入的普通服务。并使用它为您的日志添加额外信息。 我还从文档中复制了它,以确保如果链接发生变化,答案仍然相关。【参考方案2】:

如果您想在日志条目中添加额外信息,您可以使用处理器来执行此操作。使用处理器,您可以在格式化程序解析记录数组之前对其进行修改。额外的部分显示在日志条目的末尾。

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

【讨论】:

请注意,在上面的(好)示例中,$request 也可以为 null,例如运行 Symfony 命令时。 @Czechnology:真的!这个 sn-p 应该是 Symfony 项目中首先要做的事情之一,“标准”日志有时是如此无用。【参考方案3】:

不要重新发明***!无需编写自己的 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: ~

【讨论】:

这不是重新发明***。 Monolog WebProcessor 使用$_SERVER 全局,而上面的代码使用 Symfony 请求。因此,答案在 symfony 上下文中仍然有效,并且可以作为一个更扩展的示例,供大家搜索如何为日志消息添加更多上下文。

以上是关于如何向 Symfony/Monolog 日志输出添加附加信息(主机、URL 等)?的主要内容,如果未能解决你的问题,请参考以下文章

配置 symfony monolog 保留 apache 日志

Graylog2 与 Symfony 2 (Monolog)

Symfony2 Monolog 配置为使用 raven 处理程序(Sentry)

向 lambda 函数添​​加多个表达式,以获取 if/else 输出

使用 numpy.npv 函数的输出向数据框中添加一列

向熊猫数据框添加一列