LoginSignup
5
4

More than 5 years have passed since last update.

CS-Cart: エラーをログに出したり、Slackに通知したりする

Posted at

CS-Cartはアーキテクチャがしっかりしていないというか、10年くらい前のアーキテクチャというか、とにかくフレームワークの作りがゆるいので、改修していると今時当たり前の仕組みが無かったりする。

その1つが、エラーの通知。CS-CartでFatalエラーやExceptionが発生しても、開発者は知るすべがない。致命的なエラーになると、ユーザには下のような画面が表示され、HTMLのソースコードにコメントでエラー情報が出力されるが、顧客から連絡がないと発見することができず、後手後手になってしまう。

Service_unavailable.png

CS-Cartはエラーをどうハンドリングしているか

CS-Cartがエラーをどう処理しているかだが、DEVELOPMENT環境かどうかで挙動が違う。まず、DEVELOPMENT環境ではない いわゆる本番環境では、次の処理をしている

  • register_shutdown_functionで、Fatalエラーになっても最悪画面が真っ白にならないようにエラー処理をしている
  • ログは取っていない

DEVELOPMENT環境では、これに加えて、

  • set_error_handlerで開発者用エラー画面を出すのと、error_logを実行する

くらいはやっている。

ソースコードをgrepしてみたが、exception handlerは使っていないので、Exceptionが発生してcatchされないと画面が真っ白になる。

CS-Cartでエラーをログに出す方法

CS-Cartならhookを使ってエラーハンドリングしたいところだが、エラー処理部分には残念ながらフックがない。したがって、エラーを捉える処理を実装しないとならない。

と言っても難しいことはなく、set_error_handler, set_exception_handler,
register_shutdown_functionでエラーハンドラをバインドしておけばいい。どこに、エラーログの処理を書くか悩ましいが、とりあえずlocal_conf.phpに書いておけばよいかと思う。

local_conf.php
$reportError = function (Exception $exception) {
    // ここでログをとる
};

set_error_handler(function ($severity, $message, $file, $line) use ($reportError) {
    if (error_reporting() & $severity) {
        $reportError(new ErrorException($message, 0, $severity, $file, $line));
    }
});

set_exception_handler(function (Exception $exception) use ($reportError) {
    $reportError($exception);
});

register_shutdown_function(function () use ($reportError) {
    $error = error_get_last();
    if (isset($error['type']) and in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING])) {
        $reportError(new ErrorException($error['message'], 0, $error['type'], $error['file'], $error['line']));
    }
});

set_error_handlerは1プロセスに1個しか登録できないのがPHPの仕様だが、CS-CartはDEVELOPMENT環境でないと、set_exception_handlerを使わないので気にせず登録してしまってOK。

register_shutdown_functionはPHPの仕様上、複数登録できるので問題ない。set_exception_handlerはそもそも使われていないので、登録してしまって構わない。

Slackにエラーを通知する方法

PHP: Slackにメッセージを投稿するクラス - Qiitaを使って、Slackにエラーを投げるようにする。

エラーをログにとるなら、エラーの文脈もあるとデバッグしやすいので、つけておく。

require_once __DIR__ . '/app/SlackNotifier.php';
$webhookUrl = 'https://hooks.slack.com/services/...';
$slackNotifier = new SlackNotifier($webhookUrl);
$reportError = function (Exception $exception) use ($slackNotifier) {
    $user = \Tygh\Registry::get('user_info');
    $slackNotifier->exception($exception, [
        'HTTP_HOST'      => @$_SERVER['HTTP_HOST'],
        'REMOTE_ADDR'    => @$_SERVER['REMOTE_ADDR'],
        'REQUEST_METHOD' => @$_SERVER['REQUEST_METHOD'],
        'url'            => @"http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]",
        'user_id'        => @$user['user_id'],
        'HTTP_REFERER'   => @$_SERVER['HTTP_REFERER'],
        'ajax?'          => defined('AJAX_REQUEST') ? 'yes' : 'no',
    ]);
};

Slack.png

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4