CodeIgniter エラーログの出力
仕事上で、Codeigniterを使って、システム開発を行う機会がありました。しっかりするシステムなので、エラーログ、SQLログとアクセスログは必須要件として、お客様から求められました。
Codeigniterを初めて使うため、アーキテクチャーを担当する私にとって、ハードルが高かった。ネットの世界でいろいろ調べて、フックを使って、実現した英語サイトも見つかったが、結局ニーズに合わずに不採用でした。また日本のサイトも調べましたが、こちらもニーズに合わず、諦めて、自力で調査し実現しました。
前提
・CodeIgniterバージョン:3.1.3
※バージョン:3.1.6でも使えますので、3.X系はいけそうではないかと思います。す。
要件
お客様からの要件は下記の通りです。
・システム運用時に、発生したエラーをログに記録し、日単位で管理すること。→ログローテーションのこと
・エラーが発生した時間(ミリ秒まで)、場所、エラーメッセージをログに記録すること。→当たり前のことかと思います
考え方
実は、Codeigniterフレームワークログにもエラーログを出力していますが、管理しづらいやカスタマイズしづらいため、却下しました。
それをきっかけに、エラー時のハンドリングはフレームワークのどこかに存在するはず、場所を見つけて、そこで、今回の要件を合わせて、カスタマイズすれば上手くいけるかもしれないと考えました。
早速、資料を調べたり、ソースを読んだりした結果、場所は分かりました!【system\core\Common.php】の中です。_error_handlerメソッドと_exception_handlerメソッドです。
実装(_error_handlerメソッド)
場所が分かれば、残すのは、実装だけです。
ログ出力する必要なエラーメッセージ、ファイルと行数は_error_handlerメソッドのパラメータとして、既に存在していますので、そのまま使えばと思います。
実装方法は簡単です。詳しくは、PHP ログ出力機能 実装方法 で紹介しましたので、ご参考まで
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 41 42 43 44 45 46 |
function _error_handler($severity, $message, $filepath, $line) { //フレームワークの既存ソースのため、省略 $_error =& load_class('Exceptions', 'core'); $_error->log_exception($severity, $message, $filepath, $line); //------------------------- ここから開始 -------------------------// date_default_timezone_set('Asia/Tokyo'); $userid = ''; if ( isset($_SESSION['userid']) ){ $userid = $_SESSION['userid']; } $datatime = explode('.' , microtime(true)); if( !isset($datatime[1]) ){ $datatime[1] = "0000"; } $loginfo = 'ERROR' . ' ' . date('Y/m/d H:i:s,') . $datatime[1] // ミリ秒まで . ' ' . session_id() // セッションID . ' ' . $userid // エラーを起こすユーザーID . ' ' . $filepath // エラーしたPHPファイル名、パラメータからそのまま使う . ' ' . $line // エラー具体的な場所、パラメータからそのまま使う . ' ' . $message // エラーメッセージ、パラメータからそのまま使う ; $loginfo = mb_convert_encoding($loginfo,'UTF-8','UTF-8'); $filename = APPPATH . 'logs' . DIRECTORY_SEPARATOR . 'error-' . date('Y-m-d') . '.log'; // エラーログを日単位で管理すること error_log( $loginfo . "\n", 3, $filename); //------------------------- ここまで終了 -------------------------// //フレームワークの既存ソースのため、省略 } |
実装(_exception_handlerメソッド)
続いて、_exception_handlerメソッドのカスタマイズです。
Exceptionが発生した際に、エラーをログに出力する必要がありますので、_error_handlerメソッドと同じように実装します。(ただし、エラーPHPファイル名などは直接に利用できないため、少し手間を取る)
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 41 42 43 |
function _exception_handler($exception) { $_error =& load_class('Exceptions', 'core'); $_error->log_exception('error', 'Exception: '.$exception->getMessage(), $exception->getFile(), $exception->getFile()); //------------------------- ここから開始 -------------------------// date_default_timezone_set('Asia/Tokyo'); $userid = ''; if ( isset($_SESSION['userid']) ){ $userid = $_SESSION['userid']; } $datatime = explode('.' , microtime(true)); if( !isset($datatime[1]) ){ $datatime[1] = "0000"; } $loginfo = 'ERROR' . ' ' . date('Y/m/d H:i:s,') . $datatime[1] // ミリ秒まで . ' ' . session_id() // セッションID . ' ' . $userid // エラーを起こすユーザーID . ' ' . $exception->getFile() // エラーしたPHPファイル名、パラメータ:$exceptionから取得 . ' ' . $exception->getLine() // エラー具体的な場所、パラメータ:$exceptionから取得 . ' ' . $exception->getMessage() // エラーメッセージ、パラメータ:$exceptionから取得 ; $loginfo = mb_convert_encoding($loginfo,'UTF-8','UTF-8'); $filename = APPPATH . 'logs' . DIRECTORY_SEPARATOR . 'error-' . date('Y-m-d') . '.log'; error_log( $loginfo . "\n", 3, $filename); //------------------------- ここまで終了 -------------------------// //フレームワークの既存ソースのため、省略 } |
サンプル
上記の実装で、実際に出力したエラーログのサンプルです。
1 2 3 4 5 |
ERROR 2019/07/09 14:50:35,976032 op9mafsbut1vtfb6dcf6q89g270h64uo testuser /var/www/vhosts/xiyuan.jp/sample/application/controllers/sample/Sample_controller.php 62 Call to undefined function force_download() |
まとめ
これ、ムチャ!フレームワークを改造するじゃん!と叫ぶかたもいるかもしれませんが、これ以外の実装方法は恐らくないと思いますので、改造するかしないか、読者の次第と思います。ちなみに、CodeIgniterはMITライセンス、完全フリーなので、著作権などを顧慮してく良いかと思います。または、より良い方法があれば、是非コメントでご連絡ください。
CodeIgniter SQLログの出力方法も紹介しましたので、是非一度読んでください。
ディスカッション
コメント一覧
まだ、コメントがありません