norikraで作るphpの例外検知システム yapc::asia tokyo 2015 lt
TRANSCRIPT
Norikraで作るPHPの例外検知システム
YAPC::Asia Tokyo 2015 LTMasahiro Nagano @kazeburo
PHPはじめました 長年Perlをやってきましたが
PHPの例外を検出し通知するシステム
Catch PHP Exception and send it to Slack
STEP 1例外をログに記録する
Log the PHP Exception
Try-Catchtry { throw new MyAppException('Boofy');} catch (\Exception $e ) { $msg = json_encode(array( 'message' => $e->getMessage(), '_exception' => array( 'class' => get_class($e), 'message' => $e->getMessage(), 'trace' => .. ), )). "\n"; error_log($msg, 3, '/path/to/app_error_log');}
set_exception_handler
set_exception_handler(function($e) { $msg = decorate_exception($e); error_log($msg, 3, '/path/to/app_error_log');});
throw new MyAppException('Boofy');
try-catch外で発生した例外を補足
Catch the PHP Exception outside Try-Catch
set_error_handler
set_error_handler( function($severity, $msg, $file, $line){ throw new ErrorException( $msg, 0, $$severity, $file, $line ); });
PHPではエラーと例外は別物エラーを例外に変換
Convert Error to Exeption
これらの機能を使っても補足できない例外がある
(例)syntax error、存在しないメソッドの呼び出し
Can’t all Exception with these functions
error_reporting & error_log
error_reporting(E_ALL | E_STRICT);ini_set('error_log', '/path/to/php_log');
致命的エラーをログに記録php.ini でも書ける
Log Fatal Errors to the log file
Apache vhost ErrorLog
<VirtualHost *:80> ServerName api.example.com ErrorLog /path/to/error_log</VirtualHost>
php.ini にerror_logの設定がなくini_set 前にエラーが発生した場合
Apache ErrorLog
ErrorLog /var/log/httpd/error_log
Segmentation fault などApacheのworkerプロセスの不正終了
ここまでまとめ
PHP(mod_php)のエラーログは全部で4つのファイルに記録される
ここまでが長かった
弊社の環境では
STEP 2例外の集約から通知
構成
App
App
App SQLを投入
エラーログをfluentdでNorikraに送りリアルタイムに集計してSlackに通知
fluentd<source> type tail format json path /path/to/app_error_log tag nohostname.error_app_log</source>
<source> type tail format /^\[(?<time>[^\]]*)\] (?<message>.*)$/ time_format %d-%b-%Y %H:%M:%S path /path/to/php_log tag nohostname.apache_error</source>
<source> type tail format /^\[[^ ]* (?<time>[^\]]*)\] \[(?<level>[^\]]*)\](?: \[pid (?<pid>[^\]]*)\])? \[client (?<client>[^\]]*)\] (?<message>.*?)(?:, referer: (?<referer>.*))?$/ path /path/to/error_log tag nohostname.apache_error</source>
<source> type tail format /^\[[^ ]* (?<time>[^\]]*)\] \[(?<level>[^\]]*)\](?: \[pid (?<pid>[^\]]*)\])? \[client (?<client>[^\]]*)\] (?<message>.*?)(?:, referer: (?<referer>.*))?$/ path /var/log/httpd/error_log tag nohostname.apache_error</source>
<match nohostname.**> type record_reformer tag ${tag_suffix[1]} hostname ${hostname}</match>
<match {error_app_log,apache_error}> type forward <server> name cep host cep </server></match>
in_tail x 4
hostname追加
集約サーバへの送信
Norikra
•Norikra とはリアルタイムイベントストリームに対して SQL ライクな言語で処理できる super cool なプロダクト
Norikra QuerySELECT "alert-channel" as channel, "[..][" || hostname || "] Detect *" || CAST(COUNT(*), string) || "* PDOException in this 1min: ```" || message || "``` action: `" || COALESCE(NULLABLE(action),"-") || "`" AS msgFROM error_app_log.win:time_batch(1 min)WHERE exception.class = "PDOException" OR ( _exception.class = "ErrorException" AND _exception.message LIKE "PDOStatement%" )GROUP BY hostname, message, actionHAVING COUNT(*) > 0
表示例
まとめ• Norikra便利
• PHPのエラーログはつらい
• 扱いづらいPHPのエラー処理を適当にいなす - uzullaがブログ
• http://uzulla.hateblo.jp/entry/2013/12/20/041619
He is an awesomePHP guy!!!
おわり