ライター

ライターは、Zend_Log_Writer_Abstract を継承したオブジェクトです。ライターの役割は、 ログのデータをバックエンドのストレージに記録することです。

ストリームへの書き出し

Zend_Log_Writer_Stream は、ログデータを PHP のストリーム に書き出します。

ログのデータを PHP の出力バッファに書き出すには、URL php://output を使用します。一方、ログのデータを直接 STDERR のようなストリームに送ることもできます (php://stderr)。

$writer = new Zend_Log_Writer_Stream('php://output');
$logger = new Zend_Log($writer);

$logger->info('Informational message');

データをファイルに書き出すには、 ファイルシステム URL のいずれかを使用します。

$writer = new Zend_Log_Writer_Stream('/path/to/logfile');
$logger = new Zend_Log($writer);

$logger->info('Informational message');

デフォルトでは、ストリームを追記モード ("a") でオープンします。 別のモードでオープンするには、Zend_Log_Writer_Stream のコンストラクタで二番目のオプション引数にモードを指定します。

Zend_Log_Writer_Stream のコンストラクタには、 既存のストリームリソースを指定することもできます。

$stream = @fopen('/path/to/logfile', 'a', false);
if (! $stream) {
    throw new Exception('ストリームのオープンに失敗しました');
}

$writer = new Zend_Log_Writer_Stream($stream);
$logger = new Zend_Log($writer);

$logger->info('通知メッセージ');

既存のストリームリソースに対してモードを指定することはできません。 指定しようとすると Zend_Log_Exception をスローします。

データベースへの書き出し

Zend_Log_Writer_Db は、 Zend_Db を使用してログ情報をデータベースに書き出します。 Zend_Log_Writer_Db のコンストラクタには Zend_Db_Adapter のインスタンス、テーブル名 およびデータベースのカラムとイベントデータ項目との対応を指定します。

$params = array ('host'     => '127.0.0.1',
                 'username' => 'malory',
                 'password' => '******',
                 'dbname'   => 'camelot');
$db = Zend_Db::factory('PDO_MYSQL', $params);

$columnMapping = array('lvl' => 'priority', 'msg' => 'message');
$writer = new Zend_Log_Writer_Db($db, 'log_table_name', $columnMapping);

$logger = new Zend_Log($writer);

$logger->info('通知メッセージ');

上の例は、一行ぶんのログデータを 'log_table_name' という名前のテーブルに書き出します。データベースのカラム 'lvl' には優先度の番号が格納され、'msg' というカラムにログのメッセージが格納されます。

Firebug への書き込み

Zend_Log_Writer_Firebug は、ログデータを Firebug コンソール に送信します。

すべてのデータの送信には Zend_Wildfire_Channel_HttpHeaders コンポーネントを使用します。これは HTTP ヘッダを使用するので、 ページのコンテンツには何も影響を及ぼしません。 この方式なら、AJAX リクエストのようにクリーンな JSON および XML レスポンスを要求するリクエストのデバッグも行えます。

要件:

例569 Zend_Controller_Front を使ったログ記録

// 起動ファイルで、フロントコントローラのディスパッチの前に記述します
$writer = new Zend_Log_Writer_Firebug();
$logger = new Zend_Log($writer);

// モデル、ビューおよびコントローラのファイル内でこれを使用します
$logger->log('This is a log message!', Zend_Log::INFO);

例570 Zend_Controller_Front を使わないログ記録

$writer = new Zend_Log_Writer_Firebug();
$logger = new Zend_Log($writer);

$request = new Zend_Controller_Request_Http();
$response = new Zend_Controller_Response_Http();
$channel = Zend_Wildfire_Channel_HttpHeaders::getInstance();
$channel->setRequest($request);
$channel->setResponse($response);

// 出力バッファリングを開始します
ob_start();

// ロガーをコールします

$logger->log('This is a log message!', Zend_Log::INFO);

// ログデータをブラウザに送ります
$channel->flush();
$response->sendHeaders();

優先度のスタイルの設定

組み込みの優先度やユーザ定義の優先度を使うには setPriorityStyle() メソッドを使用します。

$logger->addPriority('FOO', 8);
$writer->setPriorityStyle(8, 'TRACE');
$logger->foo('Foo Message');

ユーザ定義の優先度用のデフォルトのスタイルを設定するには setDefaultPriorityStyle() メソッドを使用します。

$writer->setDefaultPriorityStyle('TRACE');

サポートしているスタイルは次のとおりです。

表112 Firebug Logging Styles

スタイル 説明
LOG 通常のログメッセージを表示します
INFO 情報ログメッセージを表示します
WARN 警告ログメッセージを表示します
ERROR エラーログメッセージを表示し、Firebug のエラーカウントをひとつ増やします
TRACE 拡張スタックトレースつきのログメッセージを表示します
EXCEPTION 拡張スタックトレースつきのエラーログメッセージを表示します
TABLE 拡張テーブルつきのログメッセージを表示します


ログ記録用のデータの準備

任意の PHP の変数を組み込みの優先度でログに記録できますが、 特殊なログ形式を使う場合は、何らかの書式変換が必要となります。

LOGINFOWARNERROR そして TRACE については特別な書式変換は不要です。

例外のログ記録

Zend_Exception のログを記録するには、 単にその例外オブジェクトをロガーに渡すだけです。 設定している優先度やスタイルにかかわらず、 例外は自動的に例外と判断されます。

$exception = new Zend_Exception('Test exception');
$logger->err($exception);

表形式のログ

ログを表形式で記録できます。カラムは自動検出され、 データの最初の行がヘッダと見なされます。

$writer->setPriorityStyle(8, 'TABLE');
$logger->addPriority('TABLE', 8);

$table = array('Summary line for the table',
             array(
                 array('Column 1', 'Column 2'),
                 array('Row 1 c 1',' Row 1 c 2'),
                 array('Row 2 c 1',' Row 2 c 2')
             )
            );
$logger->table($table);

Email への書き込み

Zend_Log_Writer_Mail は、 Zend_Mail を使ってログエントリをメールのメッセージに書き出します。 Zend_Log_Writer_Mail のコンストラクタは Zend_Mail オブジェクトを受け取り、 またオプションで Zend_Layout オブジェクトを受け取ります。

Zend_Log_Writer_Mail の主な使い道は、 開発者やシステム管理者など関係者に対して PHP スクリプトで発生したエラーを通知することです。 「何か問題がおこったら、すぐに人間に通知しないとね。 そうすればすぐに適切な対応ができるわけだから」そんなアイデアを元に Zend_Log_Writer_Mail が誕生しました。

基本的な使い方は以下のとおりです。

$mail = new Zend_Mail();
$mail->setFrom('errors@example.org')
     ->addTo('project_developers@example.org');

$writer = new Zend_Log_Writer_Mail($mail);

// 件名に使用するテキストを設定します。実際にメッセージを送信する前に、
// 発生したエラー数がこの件名に付け加えられます
$writer->setSubjectPrependText('Errors with script foo.php');

// 警告レベル以上の場合にのみメールを送信します
$writer->addFilter(Zend_Log::WARN);

$log = new Zend_Log();
$log->addWriter($writer);

// なにかが起こりました!
$log->error('unable to connect to database');

// ライターの処理が終了すると Zend_Mail::send() が立ち上がり、
// 上の Zend_Log フィルタレベル以上のすべてのログメッセージが送信されます

Zend_Log_Writer_Mail は、デフォルトで メールの本文をプレーンテキスト形式でレンダリングします。

指定したフィルタレベル以上のすべてのログエントリが、 ひとつのメールにまとめて送られます。たとえば、 警告レベル以上を送信するよう設定しているときに 2 つの警告と 5 つのエラーが発生したら、 メールには 7 つのログエントリが含まれることになります。

Zend_Layout の使用法

Zend_Layout のインスタンスを使用して、 マルチパートメールの HTML 部を作成できます。 Zend_Layout のインスタンスが用いられた場合、 Zend_Log_Writer_MailHTML をレンダリングするものとみなし、 Zend_Layout がレンダリングした値をメッセージの本文 HTML として設定します。

Zend_Log_Writer_MailZend_Layout のインスタンスを使う場合には、 setLayoutFormatter() メソッドで独自のフォーマッタを指定できます。 Zend_Layout 用のエントリフォーマッタを指定しなかった場合は、 現在使用中のものをそのまま使います。 Zend_Layout で独自のフォーマッタを使用する方法を以下に示します。

$mail = new Zend_Mail();
$mail->setFrom('errors@example.org')
     ->addTo('project_developers@example.org');
// 件名は Zend_Mail のインスタンスには設定していないことに注意しましょう!

// シンプルに、デフォルトの Zend_Layout のインスタンスを使用します
$layout = new Zend_Layout();

// エントリを li タグで囲むフォーマッタを作成します
$layoutFormatter = new Zend_Log_Formatter_Simple(
    '<li>' . Zend_Log_Formatter_Simple::DEFAULT_FORMAT . '</li>'
);

$writer = new Zend_Log_Writer_Mail($mail, $layout);

// Zend_Layout でレンダリングするための、エントリのフォーマッタを適用します
$writer->setLayoutFormatter($layoutFormatter);
$writer->setSubjectPrependText('Errors with script foo.php');
$writer->addFilter(Zend_Log::WARN);

$log = new Zend_Log();
$log->addWriter($writer);

// なにかが起こりました!
$log->error('unable to connect to database');

// ライターの処理が終了すると Zend_Mail::send() が立ち上がり、
// 上の Zend_Log フィルタレベル以上のすべてのログメッセージが送信されます
// メールは、プレーンテキストと HTML パートの両方を含む形式になります

件名でのエラーの概要

setSubjectPrependText() メソッドを Zend_Mail::setSubject() のかわりに使用すると、 メールを送信する直前に件名を動的に書き込むことができます。たとえば、 件名のテキストが "Errors from script" だとすると、 2 つの警告と 5 つのエラーが発生した場合に Zend_Log_Writer_Mail が作成するメールの件名は "Errors from script (warn = 2; error = 5)" となります。Zend_Log_Writer_Mail で件名のテキストを設定しなかった場合、もし Zend_Mail で設定されていればそれを使用します。

警告

ログエントリをメールでおくるのは危険なこともあります。 スクリプト内でのエラー条件の処理が不適切だったり エラーレベルの使用法を間違えたりすると、 エラーの発生頻度によっては何百通何千通ものメールを送信してしまう可能性があります。

現時点では、Zend_Log_Writer_Mail にはメッセージを抑制したりひとつにまとめたりする機能はありません。 そのような機能が必要な場合は自前で実装する必要があります。

もう一度言いますが、Zend_Log_Writer_Mail の第一の目標は、人間に向けてエラーの情報を積極的に伝えることです。 これらのエラーがタイミングよく処理され、 このような状況が避けられるような機能が実装されたときには、 メールによるエラー通知は便利な道具となることでしょう。

システムログへの書き込み

Zend_Log_Writer_Syslogは、 システムログ (syslog) にログ項目を書きます。 内部的には、それはPHPopenlog()closelog()、 そしてsyslog()関数の代わりです。

Zend_Log_Writer_Syslogが役立つ例の1つは、 クラスター形成されたマシンからシステムログ機能を通して集計されるログです。 多くのシステムでは、システム・イベントをリモートでログ収集できます。 それにより、システム管理者が単一のログファイルでマシンのクラスタをモニターできるようになります。

デフォルトで、生成されるsyslogメッセージはすべて、 文字列「Zend_Log」という接頭辞が付きます。 コンストラクタ、またはアプリケーション・アクセッサにアプリケーション名を渡すことで、 そのようなログメッセージを特定する異なる「アプリケーション」名を指定するかもしれません。

//インスタンス生成時に任意で "application" キーを渡します。
$writer = new Zend_Log_Writer_Syslog(array('application' => 'FooBar'));

//そのほかいつでも
$writer->setApplicationName('BarBaz');

システムログでは "facility" やアプリケーション・タイプ、 またはログ収集メッセージを指定できます。 多くのシステム・ロガーは、実は機能毎に異なるログファイルを生成します。 それは、前と同じように、サーバ活動をモニターする管理者を助けます。

コンストラクタ、またはアクセッサでログ機能を指定するかもしれません。 それは、openlog() マニュアルで定義される openlog()定数のうちの1つでなければなりません。

//インスタンス生成時に任意で "facility" キーを渡します。
$writer = new Zend_Log_Writer_Syslog(array('facility' => LOG_AUTH));

//そのほかいつでも
$writer->setFacility(LOG_USER);

ログ収集時に、デフォルトのZend_Log 優先度定数を使い続けるかもしれません。 内部的には、それらは適切なsyslog() 優先度定数にマップされます。

Zend Server モニターへの書き込み

Zend_Log_Writer_ZendMonitor では、Zend Server のモニター API を介してイベントを記録できます。 これにより、アプリケーション環境全体のログ・メッセージを一箇所に集約できます。 内部的には、それは単に Zend モニター API 由来の monitor_custom_event() 関数を使用します。

モニター API で特に役立つ機能は、 ログ・メッセージと一緒に任意のカスタム情報を指定できることです。 たとえば、例外を記録したい場合、まさにその例外メッセージを記録できません。 しかし、関数に例外オブジェクトを全て渡せます。 そして、Zend Server イベント・モニターの内部でオブジェクトを調査できます。

Zend モニターがインストールされ、使用可能にされなければいけません

このログ・ライタを使用するには、Zend モニターがインストールされ、使用可能にされなければなりません。 しかしながら、Zend モニターが検出されない場合、NULL ロガーとして単純に動作するように設計されています。

ZendMonitorログ・ライタのインスタンス生成は特記するまでもありません。

$writer = new Zend_Log_Writer_ZendMonitor();
$log    = new Zend_Log($writer);

それから、通常通り単純にメッセージを記録します。

$log->info('This is a message');

イベントと共に記録する追加の情報を指定したい場合は、 2番目の引数でその情報を渡します。

$log->info('Exception occurred', $e);

2番目の引数は、スカラー、オブジェクトまたは配列です。 情報の複数の部分を渡す必要があるならば、そうする最高の方法は連想配列を渡すことです。

$log->info('Exception occurred', array(
    'request'   => $request,
    'exception' => $e,
));

Zend Server 内では、イベントは「カスタム・イベント」として記録されます。 「モニター」タブから「イベント」項目を選び、カスタム・イベントを見るために、「カスタム」上で絞り込みます。

Zend Server のモニター・ダッシュボードのイベント

このスクリーン・ショットで、一覧表示される最初の2つのイベントは、 ZendMonitorログ・ライタを通して記録されるカスタム・イベントです。 関連した情報を全て見るには、イベントをクリックします。

Zend Server のモニターのイベント詳細

「カスタム」タブをクリックすると、ログ収集メソッドに2番目の引数を渡して記録した 追加の情報を全て詳しく表示します。 この情報は、info キーとして記録されます。 この例では、リクエスト・オブジェクトが記録されることを確認できます。

Zend_Application との統合

zf.shzf.bat コマンドは、デフォルトで Zend_Application ログ・リソース用の構成を追加します。 そして、それは ZendMonitor ログ・ライタ用の構成を含みます。 さらに、ErrorController は、アプリケーション例外を記録するために 構成されたロガーを使います。それは、デフォルトでZend モニター・イベント統合とともに提供します。

前述のように、モニター APIPHP インストールで検出されない場合、 ロガーは単純に NULL ロガーとして動作します。

ライターのスタブ

Zend_Log_Writer_Null はスタブで、ログデータをどこにも書き出しません。 これは、ログ出力を無効にしたりテスト時などに便利です。

$writer = new Zend_Log_Writer_Null;
$logger = new Zend_Log($writer);

// どこにも出力されません
$logger->info('通知メッセージ');

モックによるテスト

Zend_Log_Writer_Mock は非常にシンプルなライターです。 受け取った生のデータを配列に格納し、それを public プロパティとして公開します。

$mock = new Zend_Log_Writer_Mock;
$logger = new Zend_Log($mock);

$logger->info('通知メッセージ');

var_dump($mock->events[0]);

// Array
// (
//    [timestamp] => 2007-04-06T07:16:37-07:00
//    [message] => 通知メッセージ
//    [priority] => 6
//    [priorityName] => INFO
// )

モックが記録したイベントを消去するには、単純に $mock->events = array() とします。

ライターを組み合わせる

合成ライターオブジェクトはありません。 しかし、ログのインスタンスは任意の数のライターに書き出すことができます。そのためには addWriter() メソッドを使用します。

$writer1 = new Zend_Log_Writer_Stream('/path/to/first/logfile');
$writer2 = new Zend_Log_Writer_Stream('/path/to/second/logfile');

$logger = new Zend_Log();
$logger->addWriter($writer1);
$logger->addWriter($writer2);

// 両方のライターに書き出されます
$logger->info('通知メッセージ');