Symfony 4 was released on November 30th.
Update now to the best Symfony ever!

You are browsing the Symfony 4 documentation, which changes significantly from Symfony 3.x. If your app doesn't use Symfony 4 yet, browse the Symfony 3.4 documentation.

How to Add extra Data to Log Messages via a Processor

How to Add extra Data to Log Messages via a Processor

Monolog allows you to process the record before logging it to add some extra data. A processor can be applied for the whole handler stack or only for a specific handler.

A processor is simply a callable receiving the record as its first argument. Processors are configured using the monolog.processor DIC tag. See the reference about it.

Adding a Session/Request Token

Sometimes it is hard to tell which entries in the log belong to which session and/or request. The following example will add a unique token for each request using a processor.

 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
namespace App\Logger;

use Symfony\Component\HttpFoundation\Session\SessionInterface;

class SessionRequestProcessor
{
    private $session;
    private $sessionId;

    public function __construct(SessionInterface $session)
    {
        $this->session = $session;
    }

    public function processRecord(array $record)
    {
        if (!$this->session->isStarted()) {
            return $record;
        }

        if (!$this->sessionId) {
            $this->sessionId = substr($this->session->getId(), 0, 8) ?: '????????';
        }

        $record['extra']['token'] = $this->sessionId.'-'.substr(uniqid('', true), -8);

        return $record;
    }
}

Next, register your class as a service, as well as a formatter that uses the extra information:

  • YAML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    # config/services.yaml
    services:
        monolog.formatter.session_request:
            class: Monolog\Formatter\LineFormatter
            arguments:
                - "[%%datetime%%] [%%extra.token%%] %%channel%%.%%level_name%%: %%message%% %%context%% %%extra%%\n"
    
        App\Logger\SessionRequestProcessor:
            tags:
                - { name: monolog.processor, method: processRecord }
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    <!-- config/services.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="App\Logger\SessionRequestProcessor">
                <tag name="monolog.processor" method="processRecord" />
            </service>
        </services>
    </container>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    // config/services.php
    use App\Logger\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(SessionRequestProcessor::class)
        ->addTag('monolog.processor', array('method' => 'processRecord'));
    

Finally, set the formatter to be used on whatever handler you want:

  • YAML
    1
    2
    3
    4
    5
    6
    7
    8
    # config/packages/monolog.yaml
    monolog:
        handlers:
            main:
                type: stream
                path: '%kernel.logs_dir%/%kernel.environment%.log'
                level: debug
                formatter: monolog.formatter.session_request
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <!-- config/packages/monolog.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">
    
        <monolog:config>
            <monolog:handler
                name="main"
                type="stream"
                path="%kernel.logs_dir%/%kernel.environment%.log"
                level="debug"
                formatter="app.logger.session_request_processor"
            />
        </monolog:config>
    </container>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    // config/packages/monolog.php
    $container->loadFromExtension('monolog', array(
        'handlers' => array(
            'main' => array(
                'type'      => 'stream',
                'path'      => '%kernel.logs_dir%/%kernel.environment%.log',
                'level'     => 'debug',
                'formatter' => 'app.logger.session_request_processor',
            ),
        ),
    ));
    

If you use several handlers, you can also register a processor at the handler level or at the channel level instead of registering it globally (see the following sections).

Registering Processors per Handler

You can register a processor per handler using the handler option of the monolog.processor tag:

  • YAML
    1
    2
    3
    4
    5
    # config/services.yaml
    services:
        App\Logger\SessionRequestProcessor:
            tags:
                - { name: monolog.processor, method: processRecord, handler: main }
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    <!-- config/services.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="App\Logger\SessionRequestProcessor">
                <tag name="monolog.processor" method="processRecord" handler="main" />
            </service>
        </services>
    </container>
    
  • PHP
    1
    2
    3
    4
    5
    6
    // config/services.php
    
    // ...
    $container
        ->register(SessionRequestProcessor::class)
        ->addTag('monolog.processor', array('method' => 'processRecord', 'handler' => 'main'));
    

Registering Processors per Channel

You can register a processor per channel using the channel option of the monolog.processor tag:

  • YAML
    1
    2
    3
    4
    5
    # config/services.yaml
    services:
        App\Logger\SessionRequestProcessor:
            tags:
                - { name: monolog.processor, method: processRecord, channel: main }
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    <!-- config/services.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="App\Logger\SessionRequestProcessor">
                <tag name="monolog.processor" method="processRecord" channel="main" />
            </service>
        </services>
    </container>
    
  • PHP
    1
    2
    3
    4
    5
    6
    // config/services.php
    
    // ...
    $container
        ->register(SessionRequestProcessor::class)
        ->addTag('monolog.processor', array('method' => 'processRecord', 'channel' => 'main'));
    

This work, including the code samples, is licensed under a Creative Commons BY-SA 3.0 license.