LoginSignup
3
0

More than 3 years have passed since last update.

[Laravel 5.8] report()にコンテキストを渡せるようにする

Last updated at Posted at 2019-07-30

report()? コンテキスト?

Laravelが用意しているreportヘルパは、例外をロギングしてくれます。

report(new \Exception('sample exception'));
ログファイル
[2019-07-30 16:15:55] local.ERROR: sample exception {"exception":"[object] (Exception(code: 0): sample exception at /var/www/routes/web.php:29)
[stacktrace]
...

ログファイルにある{"exception":"[object] ...がコンテキストで、ロギングする情報のことです。デフォルトでは例外情報とログインしていればそのユーザーIDになります。以下はデフォルトLaravelの実装です。

vendor/laravel/framework/src/Illuminate/Foundation/Exceptions/Handler.php
    /**
     * Report or log an exception.
     *
     * @param  \Exception  $e
     * @return mixed
     *
     * @throws \Exception
     */
    public function report(Exception $e)
    {
        //略

        $logger->error(
            $e->getMessage(),
            array_merge($this->context(), ['exception' => $e] // ここでコンテキストをロギング
        ));
    }

    /**
     * Get the default context variables for logging.
     *
     * @return array
     */
    protected function context()
    {
        try {
            return array_filter([
                'userId' => Auth::id(),
                // 'email' => optional(Auth::user())->email,
            ]);
        } catch (Throwable $e) {
            return [];
        }
    }

上記のcontextメソッドをオーバーライドすればコンテキストを自由に編集できますが、全てのreportヘルパに影響するので、reportするときにコンテキストを渡せるようにしました。

ただ、本当は以下のようにしたかったのですが

こうしたい
report($e); // デフォルトのコンテキストでロギング
report($e, ['hoge' => 'fuga']); // コンテキストに追加してロギング

後述の理由で難しそうだったので以下で妥協しました。

こうなった
use Illuminate\Contracts\Debug\ExceptionHandler;

report($e); // デフォルトのコンテキストでロギング
app(ExceptionHandler::class)->report($e, ['hoge' => 'fuga']); // コンテキストに追加してロギング

実装

app/Exceptions/Handler.phpでreportメソッドをオーバーライドします。

app/Exceptions/Handler.php
    /**
     * Report or log an exception.
     *
     * @param  \Exception  $e
     * @return mixed
     *
     * @throws \Exception
     */
    public function report(Exception $e, array $context = []) // $contextを引数に追加
    {
        if ($this->shouldntReport($e)) {
            return;
        }

        if (is_callable($reportCallable = [$e, 'report'])) {
            return $this->container->call($reportCallable);
        }

        try {
            $logger = $this->container->make(LoggerInterface::class);
        } catch (Exception $ex) {
            throw $e;
        }

        $logger->error(
            $e->getMessage(),
            array_merge($this->context(), $context, ['exception' => $e] // $contextをマージするようにする
        ));
    }

使用するときは、サービスコンテナからExceptionHandlerを受け取りreportしてください。

use Illuminate\Contracts\Debug\ExceptionHandler;

app(ExceptionHandler::class)->report(new \Exception('sample exception'), ['hoge' => 'fuga']);
ログファイル
[2019-07-30 16:34:17] local.ERROR: sample exception {"hoge":"fuga","exception":"[object] (Exception(code: 0): sample exception at /var/www/routes/web.php:25)
[stacktrace]
...

reportヘルパにコンテキストを渡せるようにできないか?

上記はreportヘルパを通さず、直接ExceptionHandlerのreportメソッドを呼んでいます。reportヘルパを使ってreport($e, $context)とするには、reportヘルパをオーバーライドする必要があります。
reportヘルパの実装は以下になっています。

vendor/laravel/framework/src/Illuminate/Foundation/helpers.php
if (! function_exists('report')) {
    /**
     * Report an exception.
     *
     * @param  \Throwable  $exception
     * @return void
     */
    function report($exception)
    {
        if ($exception instanceof Throwable &&
            ! $exception instanceof Exception) {
            $exception = new FatalThrowableError($exception);
        }

        app(ExceptionHandler::class)->report($exception);
    }
}

ヘルパのオーバーライドは、
https://qiita.com/kd9951/items/46ef3559009ee575ea7d
の記事が詳しいです。ただヘルパの引数を追加したいので、この記事のベストな方法(サービスコンテナで入れ替える)は使えません。

以下のようなapp/helpers.phpを作り、vendor/laravel/framework/src/Illuminate/Foundation/helpers.phpよりも早くapp/helpers.phpを読み込むようにすればオーバーライドできるようですが、良さそうな方法がないので辞めました。

app/helpers.php
<?php

if (! function_exists('report')) {
    /**
     * Report an exception.
     *
     * @param  \Throwable  $exception
     * @param  array  $context
     * @return void
     */
    function report($exception, $context = []) // 引数に$context追加
    {
        if ($exception instanceof Throwable &&
            ! $exception instanceof Exception) {
            $exception = new FatalThrowableError($exception);
        }

        app(ExceptionHandler::class)->report($exception, $context); // $contextを渡す
    }
}
3
0
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
3
0