勉強会で話したZend_Logを拡張してログのローテーションをできるようにしたものです。 log4jやlog4phpを参考にしながら、基本的な機能の部分をZend_Logに合わせて作りました。 前回の記事でも書きましたが、logrotateなどを使用してサーバー側でローテーションできないような場合(junichiroさんがコメントで仰っているようにレンタルサーバーなど)に、使用するといいかもしれません。 ソースはこちら

特徴

  • 特定の期間やログのサイズをもとにローテーションを行うことができる
  • ローテーションの方法を自由に拡張できる
  • Zend_Logを使っていれば、writerを変更するだけで設定ができる

構成

Wads/
  Log/
    Writer/
      RotationFile.php
    RotationFile/
      Writer/
        Interface.php
      Policy/
        Abstract.php
        Datetime.php
        Size.php
    RotationFile.php

Wads_Log_Writer_RotationFile クラスが、既存のZend_Log_Writer を拡張してローテーションに対応させたものです。これに、Wads_Log_RotationFile というローテーションを行うクラスを設定して使用します。 また、Wads/Log/RotationFile/Policy 以下にあるクラスでどのようにローテーションを行うか決めています。 現在は、ログファイルのサイズでローテーションを行うWads_Log_RotationFile_Policy_Sizeと、日付や時間、曜日でローテーションを行うWads_Log_RotationFile_Policy_Datetime の2つを用意しています。

使用方法

  1. Wads_Log_RotationFileクラスのオブジェクトを生成する
  2. 1で生成したオブジェクト指定してWads_Log_Writer_RotationFileのオブジェクトを生成する
  3. Wads_Log_Writer_RotationFileのオブジェクトをZend_Logに追加する
  4. Zend_Logのlog()関数などを使ってログを書き出す

3以降は通常のZend_Logの使い方と同じです。 使用例です。

// ログファイル名
$logfile = "/var/log/foo/test.log";

// ローテーション方法指定
$opt = array(
    'policy' => 'size', // Wads\_Log\_RotationFile\_Policy\_Size使用する
    'backupindex' => 3,
    'size' => 40
);

// 1(上の■ 使用方法 の番号)
$lotation = new Wads\_Log\_Rotation($logfile, $opt);

// 2 ('a' は fopen の mode)
$writer = new Wads\_Log\_Writer\_RotationFile($logfile, 'a', $lotation);

// 3
$log = new Zend\_Log();
$log->addWriter($writer);

/\* ...その他フィルターなどZend\_Logの設定 \*/

// 4
$log->log("test");

Wads_Log_RotationFileのコンストラクタ内で Wads/Log/RotationFile/Policy 以下のクラスを生成しています。 どのクラスを使用するかはオプション($opt)のpolicyで指定します。

Wads\_Log\_RotationFile\_Policy\_Size なら 'policy' => 'size'
Wads\_Log\_RotationFile\_Policy\_Datetime なら 'policy' => 'datetime'

その他のオプションは主に Wads/Log/RotationFile/Policy 以下のクラスで使用しています。

Wads_Log_RotationFile_Policy_Size を使用する場合

ログファイルが指定したサイズに達した場合にローテーションを行います。以下のオプションが指定できます。

file

ログファイル名を指定します。 指定しない場合は、Wads_Log_Rotationの第1引数で指定したログファイル名が使用されます。

size

ログファイルの最大サイズを指定します。このサイズを超えるとローテーションが行われます(デフォルトは10M)。 また、サイズはKB、MB、GBの指定ができます。

backupindex

ファイルのバックアップを行う世代数を決定します(デフォルトは1)。 世代ごとにファイル名の後ろに、.1、.2のように番号が付与されます。 たとえば、

file        : /var/log/foo/test.log
backupindex : 3

の場合、以下のようになります

/var/log/foo/test.log     … 現在書き込みが行われているファイル
/var/log/foo/test.log.1   … 一つ前に書きこみが行われていたファイル
/var/log/foo/test.log.2   … 一番古いファイル。次のローテーション時に削除される

Wads_Log_RotationFile_Policy_Datetime を使用する場合

日付や時間に応じてローテーションを行います。以下のオプションが指定できます。

file

ログファイル名を指定します。 指定しない場合は、Wads_Log_Rotationの第1引数で指定したログファイル名が使用されます。 パスを除いたファイル名の部分が、nameformatの%file%の部分に置き換えられます。

ateformat

date()関数の第一引数に指定するフォーマットを指定できます(デフォルトはYmd)。 これでローテーションを行うタイミングや、ファイル名が決定されます。 もし、Y-m-d指定した場合、日毎のローテーションを行い、nameformatの%date%の部分が「2009-04-20」のように置き換えられます。 また、YmdHとすれば、時間毎でのローテーションを行います。

nameformat

%file% と %date% を使ってパス名を除いたログファイルの名前の部分を決定します(デフォルトは%file%_%date%)。 %file%がfileで指定した値に、%date%がdateformatで指定した値に置き換えられます。

file       : /var/log/foo/test.log
deteformat : Ymd
nameformat : %file.%date

の場合

/var/log/foo/test.log.20090420

となります。

Wads_Log_RotationFileを指定しない場合

もし、Wads_Log_RotationFileをWads_Log_Writer_File設定しなければ(コンストラクタの第三引数を指定しない)、Zend_Log_Writer_Streamで、ファイルをオープンした場合と同等の機能で使用できます。 そのほかの関数については、あまり複雑ではないので直接ソースを見ていただくといいです。

設計的なところ

Wads/Log/RotationFile 以下に Policyディレクトリを作らずに、直接クラスを配置したほうがすっきりするかもしれません。 こんな感じです

Wads/
  Log/
    RotationFile/
      Abstract.php
      Datetime.php
      Size.php

もともとWads/Log/RotationFile 以下は

RotationFile/
 Trigger/
 Policy/

となっていました。 これはlog4jに倣って、ローテーションのきっかけとなる条件を定義するトリガークラスなるものと、ローテーションの方法を定義するポリシークラスに分けていたためです。 ただし、途中で設計を変更して、今回はシンプルにするために2つをあわせてポリシーとしました。 今回は使い方について書きましたが、次回は拡張する場合の方法や、関連する部分の仕組みを書いてみようと思います。