デバッグし易くしよう! 7:  デバッグ用のClass

特にStep6のログファイルの出力のことを書きましたが、
毎回error_log...で、ログファイルの出力先等を記載するのは面倒臭い。
ログファイルに出力したいことと、画面に表示したいことは同じ場合も多い。
どのプログラムでもデバッグ用にやりたい作業はだいたい同じ
ということで、実際の自分のプログラムではデバッグ処理用のClassを作成して使い回しています。本当に使っているものはもっと複雑というかラーメンかスパゲッティか的な物なのですが、少し単純化してみたものをご参考までに載せて説明させて頂きたいと思います。*1

Step7: デバッグ用Classを使う

仮に testLogと名付けたClassを作成しました。
このClassを利用してできることは以下の通りとなります。

1.任意のテキスト文字列を表示/ログファイルに出力する。
2.ログファイルへの出力に際しては、以下の内容も追加した状態で出力される。
  a.処理が行われた時間
b.プログラム名
3.ログファイルに、
  プログラムの開始、終了時刻および処理時間を出力することも可能
4.文字列の表示、非表示は切り替え可能

プログラム側でのこのClassの利用例は次のようになります。

<?php
require_once("test_log.php");  //testLog class
testLog::setLogfile('./logfile/test_log.txt'); //ログファイル名の指定
testLog::setProgname( 'testprogram_name' ); // プログラム名
testLog::setdispLogF( TRUE ); //  ログを画面表示するか? TRUE/FALSE

testLog::save_msg('処理スタート','====['.__FILE__.']==');

// メインの処理

testLog::save_msg('処理終了','=================================');
testLog::keikazikanLog();  
?>

上のようなコードを含むプログラムを実行した場合。
./logfile/test_log.txtには、以下のような形式でログを出力することができます。

"2010-01-12 01:13:48","0.8619","testprogram_name","処理スタート","====[C:\(中略)\testprogram.php]=="

"2010-01-12 01:13:48","0.72220","testprogram_name","処理終了","================================="
"2010-01-12 01:13:48","0.72433","testprogram_name","[ 2010-01-12 01:13:48.8614 ]-[ 2010-01-12 01:13:48.72419 ]","  開始からの処理時間= [0.63805]sec"

画面の表示は下記のようになります。

testLog: 処理スタート,====[C:\(中略)\testprogram.php]==

testLog: 処理終了,=================================
testLog: [ 2010-01-12 01:13:48.8614 ]-[ 2010-01-12 01:13:48.72419 ],  開始からの処理時間= [0.63805]sec

見ておわかり頂けると思いますが、最初に出力対象のログファイル名、プログラム名、画面表示の有無を設定してしまえば後は、

testLog::save_msg('text1','text2');

のように、表示、出力したい情報を文字列形式にしてセットするだけです。なお、2つ目の項目は省略も可能です。

以下、実際のtestLog Class となります。

<?php
/******************************************************************************
 * file name: test_log.php
 * Description : ログ出力処理 Class
 * Ver. :              Ver.
 * Create Date:        2010/XX/XX
 * Last Update Date    2010/XX/XX
 ******************************************************************************/
 /***********************************************************************
 * Class Name: testLog
 * Definition : class testLog{}
 * Description: ログ出力
 *
 ************************************************************************/

class testLog
{
    public $filename = '';  //ログファイル名 
    public $startTime = null;  // 処理の開始時間
    public $progname = ''; //処理プログラム名
    public $dispLogF = FALSE; // ログ対象のテキストを表示するか?

/*......................................................................
 * Function Name: getInstance()
 * Description : testLogクラスのインスタンスを返す
 * Arguments: 
 * Return Values; & object
  ......................................................................*/
    function & getInstance()
    {
        static $instance = null;
        if (null === $instance) {
            $instance = new testLog;
            $instance->startTime = $instance->getMicrotime();
        }
        return $instance;
    }

 /****************************************************************************
  * public 
  ****************************************************************************/

/*......................................................................
 * Function Name: function setLogfile ( $path )
 * Description :ログファイル名設定
 * Arguments: 
 *       $path : ログファイル名
 * Return Values; bool True/False
  ......................................................................*/
    function setLogfile ( $path )
    {
        $dir = dirname($path);
        if (is_dir($dir) && is_writable($dir)) {
            $testLog =& testLog::getInstance();
            $testLog->filename = $path;
            return true;
        } else {
            return false;
        }
    }
    
/*......................................................................
 * Function Name: function setProgname ( $namae )
 * Description :ログ出力用実行プログラム名設定
 * Arguments: 
 *       $namae : プログラム名
 * Return Values;
  ......................................................................*/

    function setProgname( $namae ){
            $testLog =& testLog::getInstance();
            $testLog->progname = $namae;
    }
 
/*......................................................................
 * Function Name: function setdispLogF ( $dispFlag =FALSE )
 * Description : ログ内容を画面表示するかどうかフラグ設定
 * Arguments: 
 *       $dispFlag: 表示するかどうかフラグ
 * Return Values;
  ......................................................................*/

    function setdispLogF( $dispFlag ){
            $testLog =& testLog::getInstance();
            $testLog->dispLogF = $dispFlag;
    }
    
/*......................................................................
 * Function Name: function keikazikanLog ( )
 * Description :処理開始からの経過時間をログ
 * Arguments: 
 * Return Values;
  ......................................................................*/

    function  keikazikanLog( ){
            $testLog =& testLog::getInstance();
            $ima= $testLog->getMicrotime();
            
            $buf1=$testLog->formatMicrotime($testLog->startTime, 'Y-m-d H:i:s');
            $buf2=$testLog->formatMicrotime($ima, 'Y-m-d H:i:s');
            $buf3=$testLog->formatMicrotime($ima - $testLog->startTime);
            
            $testLog->save_msg("[ ".$buf1." ]-[ ".$buf2." ]",
               "  開始からの処理時間= [".$buf3."]sec");

    }
    
 /****************************************************************************
  * public  ユーティリティ
  ****************************************************************************/

  /*......................................................................
 * Function Name:  save_msg ( $log_msg1, $log_msg2 )
 * Description : 任意のメッセージをログに保存する。
 * Arguments: 
 *     string $erlog_msg : 保存したいメッセージテキスト
 * Return Values;
  ......................................................................*/


    function save_msg ( $log_msg1, $log_msg2=null)
    {
        $testLog =& testLog::getInstance();
        if (!$testLog->filename) {
            return false;
        }
                // $dispLogF==TRUEなら表示
        if($testLog->dispLogF){
        	echo "testLog: ".$log_msg1.",".$log_msg2."<br>";
        }
        // 現在時刻をフォーマット。小数点で分ける
        $time = explode('.', $testLog->formatMicrotime($testLog->getMicrotime(), 'Y-m-d H:i:s'));
        // $message を整形
        $message = '"'. $time[0]. '","0.'. $time[1]. '","'.$testLog->progname.'","'. $log_msg1. '","'.  $log_msg2. '"'. "\r\n";
        // 保存
        error_log($message, 3, $testLog->filename);
    }

 /*......................................................................
 * Function Name:  getMicrotime ()
 * Description :現在時刻をマイクロ秒で返す
 * Arguments: 
 * Return Values;
  ......................................................................*/
    function getMicrotime ()
    {
        list($msec, $sec) = explode(' ', microtime());
        return ((float)$sec + (float)$msec);
    }    
 /*......................................................................
 * Function Name:  formatMicrotime ( $time, $format = null )
 * Description :マイクロ秒を書式化して返す。少数点未満は第5位まで
 * Arguments: 
 *       float  $time   : タイムスタンプ.マイクロ秒
 *       string $format : タイムスタンプのフォーマット(date関数の仕様による)
 *                       省略時は 秒数.マイクロ秒
 * Return Values;
  ......................................................................*/
    function formatMicrotime ( $time, $format = null )
    {
        if (is_string($format)) {
            $sec  = (int)$time;
            $msec = (int)(($time - $sec) * 100000);
            $formated = date($format, $sec). '.'. $msec;
        } else {
            $formated = sprintf('%0.5f', $time);
        }
        return $formated;
    }
} // End of testLog class
?>

一通りテストしておりますので、大丈夫だと思いますが、普段使っているコードと異なりますため、万が一不具合等ございました際は、ご一報いただけますと幸いです。

*1:http://www.sound-uz.jp/php/note/startDebug のdebugクラスを物凄く参考にさせていただいております。