ロギングで Monolog を使用する方法

Monolog は、 Symfony2 で採用している ロギングを行うライブラリです。 Monolog は、 Python の LogBook ライブラリにインスパイアされて作成されました。

使用方法

Monolog では、ロガーはそれぞれのロギングチャネルを定義します。そのチャネルは、多くのログを書くハンドラを持っています(ハンドラは、共有されます)。

Tip

サービスでロガーを注入する際に、 use a custom channel を参照して、ログを書かれたアプリケーションの部分を簡単に調べることができます。

ベースとなるハンドラは、 StreamHandler で、ストリーム内でログを書きます。デフォルトでは、本番環境では、 app/logs/prod.log へ、開発環境では、 app/logs/dev.log になります。

Monolog は、 FingersCrossedHandler と呼ばれる本番環境でのロギングのための、強力なビルトインされたハンドラも付属しています。このハンドラを使用すれば、他のハンドラへのメッセージを転送することによって、メッセージがアクションレベルに到達したときのみ、バッファにメッセージを格納してそのメッセージをログに書くことができます。アクションレベルとは、 Standard edtion で提供されているコンフィギュレーション内の ERROR のことです。

メッセージをログに書くには、コントローラ内でコンテナからロガーサービスを取得(get)するだけです。:

$logger = $this->get('logger');
$logger->info('We just got the logger');
$logger->err('An error occurred');

Tip

Symfony\Component\HttpKernel\Log\LoggerInterface インタフェースで定義されているメソッドのみを使用すれば、あなたのコードを一切変更しなくても、ロガーの実装を変更することができます。

いろんなハンドラの使用

ロガーは、連続して呼ばれるたくさんのハンドラを使います。つまり、開発者が簡単にいくつもの方法でメッセージをログに書き込めるようになっています。

  • YAML
    monolog:
        handlers:
            syslog:
                type: stream
                path: /var/log/symfony.log
                level: error
            main:
                type: fingers_crossed
                action_level: warning
                handler: file
            file:
                type: stream
                level: debug
    
  • XML
    <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="syslog"
                type="stream"
                path="/var/log/symfony.log"
                level="error"
            />
            <monolog:handler
                name="main"
                type="fingers_crossed"
                action-level="warning"
                handler="file"
            />
            <monolog:handler
                name="file"
                type="stream"
                level="debug"
            />
        </monolog:config>
    </container>
    

上記のコンフィギュレーションでは、多くのハンドラを定義しています。また、このハンドラは、定義した順番で呼ばれます。

Tip

“file” と名付けられたハンドラは、 finger_crossed ハンドラの入れ子のハンドラとして使用されているので、スタックには入れられません。

Note

他の設定ファイルで MonologBundle の設定を変更したければ、全てのスタックを再定義しなければなりません。定義では、順番が重要であり、マージでは順番を制御することができません。

Formatter の変更

ハンドラは、 Formatter を使用して、実際のロギングの前にフォーマットを指定します。全ての Monologo のハンドラは、デフォルトでは Monolog\Formatter\LineFormatter のインスタンスを使用します。しかし、これの置き換えは簡単です。置き換える Formatter には Monolog\Formatter\FormatterInterface を実装する必要があります。

  • YAML
    services:
        my_formatter:
            class: Monolog\Formatter\JsonFormatter
    monolog:
        handlers:
            file:
                type: stream
                level: debug
                formatter: my_formatter
    
  • XML
    <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="my_formatter" class="Monolog\Formatter\JsonFormatter" />
        </services>
        <monolog:config>
            <monolog:handler
                name="file"
                type="stream"
                level="debug"
                formatter="my_formatter"
            />
        </monolog:config>
    </container>
    

ログメッセージにデータを追加する

Monolog では、ロギングをする前にデータを追加して書き込み処理をすることができます。この Processor は、全てのハンドラスタックにも、特定のハンドラにも適用が可能です。

Processor は、第一引数として書き込むレコードを受け取るだけです(A processor is simply a callable receiving the record as it’s first argument.)

このProcessor は、 monolog.processor DIC タグを使用して設定します。 reference about it を参照してください。

Session/Request のトークンの追加

ログのエントリが、 Session か、 Request またはその両方に属しているのかを区別することが難しいときがあります。以下の例では、Processor を使用して、ユニークなトークンを個々のリクエストに追加しています。

namespace Acme\MyBundle;

use Symfony\Component\HttpFoundation\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;
    }
}
  • YAML
    services:
        monolog.formatter.session_request:
            class: Monolog\Formatter\LineFormatter
            arguments:
                - "[%%datetime%%] [%%extra.token%%] %%channel%%.%%level_name%%: %%message%%\n"
    
        monolog.processor.session_request:
            class: Acme\MyBundle\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

Note

ハンドラを複数使用する際に、 Processor をグローバルに追加するのではなく、ぞれのハンドラに登録することもできます。