前説
PHPの世界において、ログ出力機能のサポートは弱くて(少なくとも、Javaより)、フレームワークを使っても、実際の要件に満たさない場合は多いと思います。
例えば、実際のプロジェクトでは、誰かがいつ、どの画面、何を入力し、何を操作したかを記録するという要件が普通にお客様から求められます。
それは、運用保守段階で、システムエラーが発生した際に、一体どうやってエラーを起こすのか、調査&再現&分析するために、真っ先に確認するのは、ログからです。
本文は、WEBアプリケーションにおいて、一般的なログ出力機能の設計から実装までを記載します。操作ログ、SQLログ、エラーログそれぞれのログ出力機能を3篇を分けて、説明します。
詳細設計
操作ログ出力機能の詳細設計です。
■ログファイル名
「access-yyyy-mm-dd.log」
※日単位でログ出力内容を記録すること
■ログフォーマット
下記の表に操作ログに必要な項目を定義します。プロジェクトによって、若干違いますが、基本的な項目は揃っているかと思います。
※各項目の間に、半角スペースで区切りします。
出力項目 | 内容 | 出力内容(例) | 備考 |
日付 | Y/m/d | 2013/01/02 | JST |
時間 | H:i:s,ミリ秒 | 11:51:29,121049 | JST |
リモートIPアドレス | リモートIPアドレス | 11.12.13.14 | |
リモートHOST名 | リモートHOST名 | 11.12.13.14 | |
セッションID | セッションID | q3o4yiqwfjkae8923y9rhkasdsadfsd | |
UID | セッション内唯一識別ID | nwefeholsdf238 | |
ユーザーID | ログインユーザーID | 12345 | |
URI | リクエストURI | /dumm/login | |
ユーザーエージェント | ユーザーエージェント | Mozilla/5.0 (Windows NT 6.1; rv:50.0) Gecko/20100101 Firefox/50.0 | |
パラメータ | POST情報 |
実装
■タイムゾーンの設定
date_default_timezone_set(‘Asia/Tokyo’)により、東京のタイムゾーンを設定します。
■ミリ秒取得
$datatime = explode(‘.’ , microtime(true))により、ミリ秒を取得します。
注意点がありまして、詳しくは、こちらをご参照
■リモートIP取得
$_SERVER[‘REMOTE_ADDR’]により、リモートIP(エンドユーザー側のIP)を取得します。
ロードバランサーが存在した場合、これは効かないため、下記のように実装すれば、無難かと思います。
1 2 3 4 5 6 7 8 9 |
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; $ip_array = explode(",", $ip); $ip = $ip_array[0]; } else { $ip = $_SERVER['REMOTE_ADDR']; } |
引用文献:こちら
■リモートHOST取得
gethostbyaddr($_SERVER[‘REMOTE_ADDR’])により、リモートHOST(エンドユーザー側のHOST)を取得します。
リモートIPと同じですが、ロードバランサーが存在した場合、これあ効かないため、上記の$ipから取得したほうが良いかと思います。
■POST内容取得
下記より、POST内容を取得します。GET内容はURIに含まれているので、わざわざ再取得する必要がないかと思います。
1 2 3 4 5 6 |
$post_info = ''; foreach( $_POST as $key=>$val){ $post_info .= $key . ':' . print_r($val,TRUE) . ','; } |
■セッション内唯一識別ID(UID)について
セキュリティ上で、セッションIDが数分単位で変わることが一般的な常識で、長時間にわたる操作を調査する際に、セッションIDが唯一性をもっていないため、別途で、セッション内唯一識別ID(勝手にながら、ここでUIDと記述します)を設定しなければならないと思います。
あれ、ユーザーIDやIPなどを使えば、いいじゃん!という反論があるかと思いますが、固定IPならいいですが、動的IPの場合、唯一ではないですよね。(HOST名も同じです)また、ユーザーIDについては、ユーザーIDを持っているシステムでは、UIDが必要はなくて、持っていない場合、UIDを作りましょう。
このUIDは、操作ログだけではなく、SQLログやエラーログなどにも出力したら、調査する際にとても助かるかと思います。
■サンプル
上記のサンプルです。実際に合わせて、自分なりに実装しましょう。より良い方法があると思います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
function log_info($post_info) { date_default_timezone_set('Asia/Tokyo'); $userid = ''; if ( isset($_SESSION['userid']) ){ $userid = $_SESSION['userid']; } $uid = ''; if ( isset($_SESSION['uid']) ){ $uid = $_SESSION['uid']; } $datatime = explode('.' , microtime(true)); if( !isset($datatime[1]) ){ $datatime[1] = "000000"; } $loginfo = date('Y/m/d H:i:s,') . $datatime[1] . ' ' . $_SERVER['REMOTE_ADDR'] . ' ' . gethostbyaddr($_SERVER['REMOTE_ADDR']) . ' ' . session_id() . ' ' . $uid . ' ' . $userid . ' ' . $_SERVER['REQUEST_URI'] . ' ' . $_SERVER['HTTP_USER_AGENT'] . ' ' . $post_info; $loginfo = mb_convert_encoding($loginfo,'UTF-8','UTF-8'); $filename = 'access-' . date('Y-m-d') . '.log'; error_log( $loginfo . "\n", 3, $filename); } |
いかがでしょうか。意外と簡単ですね。次回はエラーログ出力機能を紹介します。お楽しみください。