自定义HandlerWrapper与MonologBu​​ndle

Ema*_*ter 8 php symfony monolog

我正在使用Symfony 3.1,我尝试以这种方式配置Monolog,不会记录来自Googlebot的请求.为此我写了一个UserAgentProcessor已按预期工作的.在下一步中,我尝试编写BotFilter,如下所示:

<?php

namespace AppBundle\Handler;

use Monolog\Handler\HandlerWrapper;

class FilterBotsHandler extends HandlerWrapper
{

    /**
     * {@inheritdoc}
     */
    public function isHandling(array $record)
    {
        if (stripos($record['extra']['userAgent'], 'bot') !== false){
            return false;
        } else {
            return $this->handler->isHandling($record);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是受到HandlerWrapper抽象类中的注释的启发(请看这里).

现在我想将该过滤器添加到我的monolog yml-configuration中.我尝试将它添加到我的服务中,但这不可能,HandlerWrapper因为它的构造函数需要一个Handler实例.我研究了如何在没有服务的情况下使用过滤器,但据我所知,monolog bundle只接受内置类型和通用服务类型.

现在的问题是:我如何在配置中使用过滤器?

yce*_*uto 5

我正在使用Symfony 3.1,我尝试以这种方式配置Monolog,不会记录来自GoogleBot的请求...


  1. 防止机器人访问您网站的快速方法是将这两行放入/robots.txt服务器上的文件中.robots.txt在"web"目录中创建一个文件并粘贴以下内容:

    User-agent: *
    Disallow: /
    
    Run Code Online (Sandbox Code Playgroud)

    https://support.google.com/webmasters/answer/6062608?hl=en&visit_id=1-636097099675465769-3677253464&rd=1

    当您需要完全避免访问时,这是推荐的选项,这意味着您的网站将不再被搜索引擎和其他机器人索引.您无需在应用程序中配置/实现任何内容即可实现它.


  1. 现在,如果你需要机器人进入,但你不想在日志中注册它.不是在某处编写日志文件,而是使用一些处理程序来过滤或修改日志条目,然后再将它们发送给其他处理程序.默认情况下fingers_crossed,在prod环境中使用一个强大的内置处理程序.它在请求期间存储所有日志消息,但只有在其中一条消息到达时才将它们传递给第二个处理程序action_level:

    # app/config/config.yml
    monolog:
        handlers:
            filter_for_errors:
                type: fingers_crossed
                # if *one* log is error or higher, pass *all* to file_log
                action_level: error
                handler: file_log
    
            # now passed *all* logs, but only if one log is error or higher
            file_log:
                type: stream
                path: "%kernel.logs_dir%/%kernel.environment%.log"
    
    Run Code Online (Sandbox Code Playgroud)

    因此,在您的prod.log文件中只会注册包含一些错误的消息/请求,因此机器人在此级别中没有效果.

    有关此http://symfony.com/doc/current/logging.html的更多详细信息


  1. 您尝试做的是不可取的,因为处理程序将依赖于http请求而不是日志记录,这将不在上下文中,但您可以轻松地在Symfony中注册自己的处理程序:

    让我们创建自定义处理程序类:

    namespace AppBundle\Monolog\Handler;
    
    use Monolog\Handler\AbstractHandler;
    
    class StopBotLogHandler extends AbstractHandler
    {
        public function isBotRequestDetected()
        {
            // here your code to detect Bot requests, return true or false
            // something like this: 
            // return isset($_SERVER['HTTP_USER_AGENT']) && preg_match('/bot|crawl|slurp|spider/i', $_SERVER['HTTP_USER_AGENT']);
        }
    
        /**
         * Checks whether the given record will be handled by this handler.
         *
         * This is mostly done for performance reasons, to avoid calling processors for nothing.
         *
         * Handlers should still check the record levels within handle(), returning false in isHandling()
         * is no guarantee that handle() will not be called, and isHandling() might not be called
         * for a given record.
         *
         * @param array $record Partial log record containing only a level key (e.g: array('level' => 100) for DEBUG level)
         *
         * @return bool
         */
        public function isHandling(array $record)
        {
            return $this->isBotRequestDetected();
        }
    
        /**
         * Handles a record.
         *
         * All records may be passed to this method, and the handler should discard
         * those that it does not want to handle.
         *
         * The return value of this function controls the bubbling process of the handler stack.
         * Unless the bubbling is interrupted (by returning true), the Logger class will keep on
         * calling further handlers in the stack with a given log record.
         *
         * @param array $record The record to handle
         *
         * @return bool true means that this handler handled the record, and that bubbling is not permitted.
         *              false means the record was either not processed or that this handler allows bubbling.
         */
        public function handle(array $record)
        {
            // do nothing, just returns true whether the request is detected as "bot", this will break the handlers loop.
            //             else returns false and other handler will handle the record.
    
            return $this->isBotRequestDetected();
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    每当您向记录器添加记录时,它都会遍历处理程序堆栈.每个处理程序决定它是否完全处理记录,如果是,则记录的传播在那里结束.

    重要提示:阅读phpdoc isHandling()handle()方法以获取更多详细信息.

    接下来,让我们将该类注册为"无标签"服务:

    # app/config/services.yml
    services:
        monolog.handler.stop_bot_log:
            class: AppBundle\Monolog\Handler\StopBotLogHandler
            public: false
    
    Run Code Online (Sandbox Code Playgroud)

    然后,将其处理程序添加到handlers列表:

    # app/config/config_prod.yml
    monolog:
        handlers:
            # ...
    
            stopbotlog:
                type: service
                id: monolog.handler.stop_bot_log
                priority: 1
    
    Run Code Online (Sandbox Code Playgroud)

    注意该type属性必须等于service,id必须是定义之前的服务名称,并且priority必须大于0以确保其处理程序将在该任何其他处理程序之前执行.

    GoogleBot对网站应用stopbotlog 程序执行请求时,处理程序将停止其后的所有处理程序,并且不会注册任何日志消息.

    请记住,这不是推荐的方法!根据您的需求,实施选项1或2就足够了.


如果要忽略对处理程序组的bot请求,可以覆盖monolog.handler.group.class容器参数并覆盖组handler行为:

namespace AppBundle\Handler;

use Monolog\Handler\GroupHandler;

class NoBotGroupHandler extends GroupHandler
{
    public function isBotRequestDetected()
    {
        // here your code to detect Bot requests, return true or false
    }

    public function handle(array $record)
    {
        if ($this->isBotRequestDetected()) {
            // ignore bot request for handlers list
            return false === $this->bubble;
        }

        return parent::handle($record);
    }
}
Run Code Online (Sandbox Code Playgroud)

在你config_prod.ymlservices.yml:

parameters:
    monolog.handler.group.class: AppBundle\Handler\NoBotGroupHandler
Run Code Online (Sandbox Code Playgroud)

而已!现在,您可以停止自定义句柄列表的bot日志:

# config_prod.yml
monolog:
    handlers:
        grouped:
            type: group
            members: [main, console, chromephp]
Run Code Online (Sandbox Code Playgroud)

最后,如果您难以分析日志文件,我建议使用这个神奇的工具:https://github.com/EasyCorp/easy-log-handler