PHPでのログのとり方を考える

テーマ:

PHPでは記述ミスがあればエラー内容が画面表示されますし、警告も設定によりますが画面表示されるようになっています。なので特にデバッグツール類が必要になることはないでしょう。。
なので簡易的なログとり関数などを作っておけば充分です。


PHPにはログとり専用のerror_log()関数が用意されています。


書式 error_log("ログ書き込み内容をここに", 3, "/path/to/filename");


という書き方で実現できます。
恐らく実質fopen("/path/to/filename", "a")というアペンドモード(追加)書き込みが行われていると思います。


error_logという関数名ですが、エラーだけでなく開発時のデバッグ用にも大いに利用できると思います。


ということで早速使ってみましょう。



■ログとり(1)
<?php


$s= "foo";
error_log($s, 3, "error.log");


$s= "bar";
error_log($s, 3, "error.log");


?>



[error.log書き込み内容]

foobar


あれれ、1度目と2度目のログデータがつながってしまって切れ目がわかりません。
末尾改行が必要ですね。




■ログとり(2)
<?php

$s= "foo";
log2($s);


$s= "bar";
log2($s);



function log2($s)
{
    error_log(rtrim($s) . "\n", 3, "error.log");
}
?>



[error.log書き込み内容]

foo
bar


うまくいきました。
書き込み内容末尾に改行があるかどうかわからないので、改行があればrtrim()で削って"\n"を付加しています。これでログ末尾に必ず改行が付くことになります。


ところでログといえば必ず書き込んだ日付が付きものです。
日付を追加してみましょう。




■ログとり(3)
<?php

$s= "foo";
log3($s);


$s= "bar";
log3($s);



function log3($s)
{
    error_log(date("[Y/m/d H:i:s] ") . rtrim($s) . "\n", 3, "error.log");
}
?>



[error.log書き込み内容]

[2009/11/11 22:45:47] foo
[2009/11/11 22:45:47] bar


っぽいですね。ログって感じがプンプンしてきましたね。

では次はもっと欲を出してスカラー変数以外の配列などにも対応できるようにしてみます。




■ログとり(4)
<?php

$array= array("foo", "bar");
log4($array);



function log4($s)
{
    error_log(date("[Y/m/d H:i:s] ") . rtrim(print_r($s,true)) . "\n", 3, "error.log");
}
?>



[error.log書き込み内容]

[2009/11/11 23:23:32] Array
(
    [0] => foo
    [1] => bar
)


print_r()関数を使いました。この関数の第2引数を「true」にすると標準出力しないで文字列として返すようになります。


それでは更に欲を出して値の型も知ることができるようにprint_r()関数をvar_dump()関数に代えてみます。




■ログとり(5)
<?php

$array= array("foo", "bar", 5);
log5($array);



function log5($s)
{
    ob_start();
    var_dump($s);
    $log= ob_get_contents();
    ob_end_clean();
    error_log(date("[Y/m/d H:i:s] ") . rtrim($log) . "\n", 3, "error.log");
}
?>



[error.log書き込み内容]

[2009/11/11 23:28:35] array(3) {
    [0]=>
    string(3) "foo"
    [1]=>
    string(3) "bar"
    [2]=>
    int(5)
}


var_dump()関数にはprint_r()関数のような文字列を返すオプションは用意されていませんので、標準出力をバッファリングさせて捕まえないといけません。
そのためにob系関数を使っています。
これで値のデータ型まで知ることができるようになりました。


これくらいで終わりにしたいところですが、もし一度に複数の変数をログ書き込みしたい場合にも対応できたほうがいいので可変引数対応に書き替えます。




■ログとり(6)
<?php

$array= array("foo", "5", 5);
$s= "hoge";
log6($array, $s);



function log6()
{
    ob_start();
    foreach (func_get_args() as $argv){
        echo "\t";
        var_dump($argv);
    }
    $log= ob_get_contents();
    ob_end_clean();
    error_log(date("[Y/m/d H:i:s] ") . rtrim($log) . "\n", 3, "error.log");
}
?>



[error.log書き込み内容]

[2009/11/11 23:31:54] array(3) {
    [0]=>
    string(3) "foo"
    [1]=>
    string(1) "5"
    [2]=>
    int(5)
}
    string(4) "hoge"



その他、作成したこの関数を複数スクリプトで使う場合には書き込むログファイル名を分けるとか、一つのログファイルに書き込む場合には$_SERVER['SCRIPT_NAME']の値も併せて保存するといい感じになると思います。


できれば log6(__FILE__ . "(" . __LINE__ . ")". $message);のように記述したほうがよりわかり易いですが、面倒なんですよね。define()使っても置換できませんでした。



AD