LoginSignup
7
7

More than 5 years have passed since last update.

Zend\LogでFingersCrossedモード(問題発生時に過去ログを一気に出力)

Posted at

アプリケーションログは、何か障害が発生した時は調査の起点になりますので大事ですよね。

ロガーは通常、ログレベルを設定できて、debug用の情報などは開発環境だけ出力し、本番環境では抑制しておきます。無駄な大量のログ出力は、それなりにパフォーマンスに悪影響を与えますからね。

しかし、何かエラーが起きたときは、ログ出力が抑制されていることにより、原因がわかりにくくなってしまいます。

Monolog特有の機能であるFingersCrossedは、このジレンマを解消します。
ある特定のレベル(CRITICALなど)のログ出力を指示した瞬間、ログレベルを切り替え、過去にさかのぼってINFOなどのすべてのログを出力します。

これにより、問題が起きた時だけ詳細にログを吐くことができ、障害対応に効果を発揮します。

で、本題なのですが。

Zend Framework2の公式ロガーであるZend\Logには似たような機能がないか調べていたら、Monologからポーティングされているようでした。しかしマニュアルには使い方が書かれていませんでしたので、メモしておきます。

Zend\Logのインストール

まあ、composerでインストールするのが楽ですかね。zf2全体のパッケージ(zendframework/zendframework)をインストール済みなら、Zend\Logも含まれています。

$ mkdir some-project
$ cd some-project
$ composer require 'zendframework/zend-log:*'

Zend\Logはロギング自体を提供するコア部分、出力先へ実際の出力を行うWriter部分、ログ出力の抑制を行うFilter部分、すべてバラバラに作られており、使う場合は組み立て作業が必要です。

Zend\Log\Writer\FingersCrossed の例

<?php
require 'vendor/autoload.php';

use Zend\Log;
use Zend\Log\Writer;

$logger = new Log\Logger;

//実際は適当なファイルなどを指定する。ここではお試しなので標準出力を指定
$writer = new Writer\Stream('php://output');

//FingersCrossed でラッピングする
$fingersCrossed = new Writer\FingersCrossed($writer, Log\Logger::CRIT);

$logger->addWriter($fingersCrossed);

// ここまででloggerの使用準備完了

$logger->debug('debug!!');
$logger->info('info!!');
$logger->notice('notice!!');
$logger->warn('warn!!');
$logger->err('error!!');
sleep(2);
$logger->crit('crit!!');
$logger->alert('alert!!');
$logger->emerg('emerg!!');

Zend\LogのログレベルはsyslogのRFCに準拠して決められていて、debugが一番緩やかなレベル、emergが一番ヤバいレベルとなっています。

ただのロガーであれば、上記コードはdebugからerrまで出力した後、2秒待って、crit以降を出力するはずです。

FingersCrossedでは、critが最初に呼ばれるまでdebugからerrまでのログ出力は抑制されているので、2秒待ってから、一気にdebugからemergeまで出力される挙動になります。

Filter\Priorityとの組み合わせ

なお、FingersCrossedモードで出力する場合でもdebugレベルは出力しなくてよい、というのであれば、予めwriterにpriorityによるfilterを設定しておきましょう。

<?php
require 'vendor/autoload.php';

use Zend\Log;
use Zend\Log\Writer;

$logger = new Log\Logger;

//実際は適当なファイルなどを指定する。ここではお試しなので標準出力を指定
$writer = new Writer\Stream('php://output');
$writer->addFilter(new Log\Filter\Priority(Log\Logger::INFO)); //info以降のみ出力するよう抑制

//FingersCrossed でラッピングする
$fingersCrossed = new Writer\FingersCrossed($writer, Log\Logger::CRIT);

$logger->addWriter($fingersCrossed);

// ここまでで使用準備完了

$logger->debug('debug!!'); //これが出力されることはない
$logger->info('info!!');
$logger->notice('notice!!');
$logger->warn('warn!!');
$logger->err('error!!');
sleep(2);
$logger->crit('crit!!');
$logger->alert('alert!!');
$logger->emerg('emerg!!');

FingersCrossedが使いたいがために、ロガーだけはMonologを使う、なんてことはしなくても大丈夫そうです。ZF使いならZend\Logを使ってしまう方が楽でしょう。

全部バラバラに作ってあるのはお作法として正しいのですが、使うまでの設定処理はこのままだと面倒ですので、実際はフレームワーク付属のDIコンテナなりサービスロケータなりの中で組み立てるとよいでしょう。

7
7
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
7