モンモンブログ

Ruby, Python, PHP, JavaScript/jQuery などなど気分に応じて

Symfony2 + Monolog でのロギングについて(その1)

Symfony2 のロギングでデフォルトで使われてる Monolog について調べたので忘れないうちにまとめておく。 何回かに分けて書きます。今回は Monolog イットセルフについて。

Monolog のバージョンは 1.7.0。

Monolog の構造

Monolog は4つのコンポーネントからなります。

  • ロガー
    コントローラで $logger = $this->get('logger') って取得するおなじみのあいつ。Logger クラス。 プロセッサとハンドラをいずれも複数登録できます。

  • ハンドラ
    メイン処理担当。ロガーからログ情報を受け取って、プロセッサで前処理して、フォーマッタで成形して、出力する。 プロセッサを複数とフォーマッタを1つ、登録できます。 また、以降のハンドラに処理を続行させるかどうかのフラグ (bubble フラグ) も持ちます。 代表的な StreamHandler はファイルにログを書き込むハンドラです。

  • プロセッサ
    ログ情報の前処理を担当。 例えば IntrospectionProcessor は、ログメソッドの呼ばれた箇所のファイル名、行番号、クラス名、メソッド名を、ログ情報の extra フィールドに付加します。

  • フォーマッタ
    ログ情報の成形を担当。 デフォルトの LineFormatter は、ログ情報を文字通り1行のログに成形します。

プロセッサはロガーとハンドラどっちにも登録出来て、
ロガーに登録すれば、共通の前処理をハンドラに渡す前にさせることができるし、
ハンドラに登録すれば、そのハンドラ専用の前処理をさせられます。

コンポーネント同士の登録関係を図にすると例えばこんな感じ?

ロガー
 └ プロセッサ1
 │
 └ ハンドラ1
 │ └ プロセッサ1
 │ └ プロセッサ2
 │ └ フォーマッタ
 │
 └ ハンドラ2(プロセッサなし)
   └ フォーマッタ

ログ情報 = record

ログ情報は "record" という名前の連想配列でやり取りされます。 record 1つがログ1行に相当します。

こんな形式です。

$record = array(
  'message' => "xxxx",            // ログメッセージ本文
  'level' => 400,                 // ログレベルを表す数値。DEBUG なら 100, ERROR なら 400 など
  'level_name' => "ERROR",        // ログレベルを表す文字列
  'channel' => "main",            // Logger 自身の名前を表す文字列
  'datetime' => new \DateTime(),  // タイムスタンプ
  'context' => array(),           // 追加情報その1。ロガーを呼ぶ側から利用出来る。
  'extra' => array(),             // 追加情報その2。プロセッサなどが使用。
  'formatted' => "xxxx",          // フォーマッタによる整形済みの文字列
);

「追加情報」が contextextra の2つありますけど

  • context は、 $logger->debug("ログメッセージ", array(1, 2, 3)) のようにログメソッドの第2引数として外から渡すことのできる情報
  • extra は、プロセッサなどが内部的に追加する情報

です。ちなみに LineFormatter の場合、どちらも単純に json_encode で文字列化して出力してくれます。

おおざっぱな動作

ログメソッドを呼んだ際、各コンポーネントがどんな風に連携して動作するのか、ざくっと解説します。 ハンドラによって動作は微妙に異なるので、ここでは代表的な組み合わせとして StreamHandler + LineFormatter を想定します。

スタート地点は $logger->debug("ログメッセージ") ですね。

  1. (Logger) ログメッセージを元に record 連想配列を作る
  2. (Logger) record をロガーのプロセッサで前処理
  3. (Logger) ハンドラを順に実行して record を処理していく
    1. (Handler) record のログレベルを確認、処理対象でなければ何もせず終了
    2. (Handler) record をハンドラのプロセッサで前処理
    3. (Handler) record をフォーマッタで文字列に変換
    4. (Handler) 文字列をファイルに出力
    5. (Handler) ハンドラの bubble フラグが false なら、これ以降のハンドラでの処理を停止する

今回はここまで。次回は Monolog を Symfony2 で使う際の設定方法について書く予定。