如何通过Processor向日志信息添加额外数据

3.4 版本
维护中的版本

Monolog 允许你在记录日志之前处理其内容以添加某些额外数据(extra data)。一个processor(处理器)可以作用于整个控制器堆栈(handler stack),或者仅作用于一个指定的handler。

Processor就是个callable,把取出的记录作为自己的第一个参数。Processor透过 monolog.processor DIC标签进行配置。请见 关于它的参数

为session/request添加一个Token 

有时,要说出日志文件的哪个入口属于哪个session和/或请求,是非常困难的。下例将使用一个processor来把一个唯一token添加到每一个请求中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
namespace AppBundle;
 
use Symfony\Component\HttpFoundation\Session\Session;
 
class SessionRequestProcessor
{
    private $session;
    private $token;
 
    public function __construct(Session $session)
    {
        $this->session = $session;
    }
 
    public function processRecord(array $record)
    {
        if (null === $this->token) {
            try {
                $this->token = substr($this->session->getId(), 0, 8);
            } catch (\RuntimeException $e) {
                $this->token = '????????';
            }
            $this->token .= '-' . substr(uniqid(), -8);
        }
        $record['extra']['token'] = $this->token;
 
        return $record;
    }
}
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# app/config/config.yml
services:
    monolog.formatter.session_request:
        class: Monolog\Formatter\LineFormatter
        arguments:
            - "[%%datetime%%] [%%extra.token%%] %%channel%%.%%level_name%%: %%message%% %%context%% %%extra%%\n"

    monolog.processor.session_request:
        class: AppBundle\SessionRequestProcessor
        arguments:  ['@session']
        tags:
            - { name: monolog.processor, method: processRecord }

monolog:
    handlers:
        main:
            type: stream
            path: '%kernel.logs_dir%/%kernel.environment%.log'
            level: debug
            formatter: monolog.formatter.session_request
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<!-- app/config/config.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:monolog="http://symfony.com/schema/dic/monolog"
    xsi:schemaLocation="http://symfony.com/schema/dic/services
        http://symfony.com/schema/dic/services/services-1.0.xsd
        http://symfony.com/schema/dic/monolog
        http://symfony.com/schema/dic/monolog/monolog-1.0.xsd">
 
    <services>
        <service id="monolog.formatter.session_request"
            class="Monolog\Formatter\LineFormatter">
 
            <argument>[%%datetime%%] [%%extra.token%%] %%channel%%.%%level_name%%: %%message%% %%context%% %%extra%%&#xA;</argument>
        </service>
 
        <service id="monolog.processor.session_request"
            class="AppBundle\SessionRequestProcessor">
 
            <argument type="service" id="session" />
            <tag name="monolog.processor" method="processRecord" />
        </service>
    </services>
 
    <monolog:config>
        <monolog:handler
            name="main"
            type="stream"
            path="%kernel.logs_dir%/%kernel.environment%.log"
            level="debug"
            formatter="monolog.formatter.session_request"
        />
    </monolog:config>
</container>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// app/config/config.php
use AppBundle\SessionRequestProcessor;
use Monolog\Formatter\LineFormatter;
 
$container
    ->register('monolog.formatter.session_request', LineFormatter::class)
    ->addArgument('[%%datetime%%] [%%extra.token%%] %%channel%%.%%level_name%%: %%message%% %%context%% %%extra%%\n');
 
$container
    ->register('monolog.processor.session_request', SessionRequestProcessor::class)
    ->addArgument(new Reference('session'))
    ->addTag('monolog.processor', array('method' => 'processRecord'));
 
$container->loadFromExtension('monolog', array(
    'handlers' => array(
        'main' => array(
            'type'      => 'stream',
            'path'      => '%kernel.logs_dir%/%kernel.environment%.log',
            'level'     => 'debug',
            'formatter' => 'monolog.formatter.session_request',
        ),
    ),
));

如果你使用了若干种handlers,你也可以向“控制器级别(handler level)”或“频道级别(channel level)”来注册processor,而不是全局注册之(见下文)。

注册Processors到每个控制器 

通过 monolog.processor 的tags选项的 handler 属性,你可以逐控制器地注册processor:

1
2
3
4
5
6
7
# app/config/config.yml
services:
    monolog.processor.session_request:
        class: AppBundle\SessionRequestProcessor
        arguments:  ['@session']
        tags:
            - { name: monolog.processor, method: processRecord, handler: main }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!-- app/config/config.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:monolog="http://symfony.com/schema/dic/monolog"
    xsi:schemaLocation="http://symfony.com/schema/dic/services
        http://symfony.com/schema/dic/services/services-1.0.xsd
        http://symfony.com/schema/dic/monolog
        http://symfony.com/schema/dic/monolog/monolog-1.0.xsd">
 
    <services>
        <service id="monolog.processor.session_request"
            class="AppBundle\SessionRequestProcessor">
 
            <argument type="service" id="session" />
            <tag name="monolog.processor" method="processRecord" handler="main" />
        </service>
    </services>
</container>
1
2
3
4
5
6
7
8
9
10
// app/config/config.php
 
// ...
$container
    ->register(
        'monolog.processor.session_request',
        SessionRequestProcessor::class
    )
    ->addArgument(new Reference('session'))
    ->addTag('monolog.processor', array('method' => 'processRecord', 'handler' => 'main'));

注册Processors到每个频道 

通过 monolog.processor 的tags选项的 channel 属性,你可以逐频道地注册processor:

1
2
3
4
5
6
7
# app/config/config.yml
services:
    monolog.processor.session_request:
        class: AppBundle\SessionRequestProcessor
        arguments:  ['@session']
        tags:
            - { name: monolog.processor, method: processRecord, channel: main }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!-- app/config/config.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:monolog="http://symfony.com/schema/dic/monolog"
    xsi:schemaLocation="http://symfony.com/schema/dic/services
        http://symfony.com/schema/dic/services/services-1.0.xsd
        http://symfony.com/schema/dic/monolog
        http://symfony.com/schema/dic/monolog/monolog-1.0.xsd">
 
    <services>
        <service id="monolog.processor.session_request"
            class="AppBundle\SessionRequestProcessor">
 
            <argument type="service" id="session" />
            <tag name="monolog.processor" method="processRecord" channel="main" />
        </service>
    </services>
</container>
1
2
3
4
5
6
7
// app/config/config.php
 
// ...
$container
    ->register('monolog.processor.session_request', SessionRequestProcessor::class)
    ->addArgument(new Reference('session'))
    ->addTag('monolog.processor', array('method' => 'processRecord', 'channel' => 'main'));

本文,包括例程代码在内,采用的是 Creative Commons BY-SA 3.0 创作共用授权。

登录symfonychina 发表评论或留下问题(我们会尽量回复)