Help us understand the problem. What is going on with this article?

Sentry を Laravel と Vue.js に導入してみた

More than 1 year has passed since last update.

Sentry を導入したので導入手順をまとめました。
PHP (Laravel) と Vue.js の場合について記載しています。

Sentry?

https://sentry.io/

Web アプリケーションで起きたエラー等をロギングできるサービスです。
Slack やメールで通知を送れます。

導入

Laravel 5.x (PHP)

Laravel 用のパッケージがあるのでこれを利用します。記事作成時点での最新バージョンは 0.10.0 です。

getsentry/sentry-laravel: Laravel integration for Sentry

導入方法: Docs - Laravel

基本

パッケージをインストールします。

composer require sentry/sentry-laravel

Laravel 5.4 以下 の場合は config/app.php に設定を追加する必要があるようです。

config/app.php
'providers' => array(
    // ...
    Sentry\SentryLaravel\SentryLaravelServiceProvider::class,
)

'aliases' => array(
    // ...
    'Sentry' => Sentry\SentryLaravel\SentryFacade::class,
)

Sentry へのロギングを実施させる仕組みとして、 app/Exceptions/Handler.phpreport() に手を加えます。

app/Exceptions/Handler.php
public function report(Exception $exception)
{
    // ここから
    if (app()->bound('sentry') && $this->shouldReport($exception)) {
        app('sentry')->captureException($exception);
    }
    // ここまで

    parent::report($exception);
}

config/sentry.php を生成するため以下のコマンドを実行します。

php artisan vendor:publish --provider="Sentry\SentryLaravel\SentryLaravelServiceProvider"

Sentry の DSN を設定します。
config/sentry.php にべた書きするなり .env に書き込むなりしましょう。

config/sentry.php
return array(
    'dsn' => env('SENTRY_LARAVEL_DSN', 'https://foobar@sentry.io/1234567890'),
    ...

仕上げに Laravel の 500 エラーページを用意します。
サーバエラーが起きた際に、ロギングだけでなくユーザーに詳細な報告を入力してもらうためのフォームを表示できます。

resources/views/errors/500.blade.php
<div class="content">
    <div class="title">予期しないエラーが発生しました</div>

    @if( app()->bound('sentry') && !empty(Sentry::getLastEventID()) )
    <div class="subtitle">Error ID: {{ Sentry::getLastEventID() }}</div>
    <script src="https://cdn.ravenjs.com/3.3.0/raven.min.js"></script>
    <script>
        Raven.showReportDialog({
            eventId: '{{ Sentry::getLastEventID() }}',
            dsn: '{{ config("sentry.dsn") }}',
            user: {
                'name': '{{ Auth::User() ? Auth::User()->name : "" }}',
                'email': '{{ Auth::User() ? Auth::User()->email : "" }}'
            }
        })
    </script>
    @endif
</div>

エラー発生時の認証ユーザー情報をログに含める

Middleware を作成します。
ユーザーの操作中にエラーが発生した時に、どのユーザーでエラーが発生したのかをログと一緒に Sentry に送信できます。

app/Http/Middleware/SentryContext.php
<?php

namespace App\Http\Middleware;

use Closure;

class SentryContext
{
    public function handle($request, Closure $next)
    {
        // ここから
        if (app()->bound('sentry')) {
            $sentry = app('sentry');

            if (auth()->check()) {
                $sentry->user_context([
                    'id' => auth()->user()->id,
                    'email' => auth()->user()->email
                ]);
            } else {
                $sentry->user_context([
                    'id' => null,
                    'email' => null
                ]);
            }
        }
        // ここまで
        return $next($request);
    }
}

ファイルを作成したら app/Kernel.php$routeMiddleware に登録します。

app/Kernel.php
        ...
        'sentry.context' => \App\Http\Middleware\SentryContext::class
    ];

ロギング時にユーザー情報を含めたいルートに対してこの Middleware を適用します。

routes/web.php
Route::middleware(['auth', 'sentry.context'])->group(function() {
  ...
}

JavaScript (+Vue.js)

4.0.0 からパッケージが新しくなり、以前の raven-js ではなくなってるっぽい。
同時に導入方法も変わっていたのでこちらもまとめ。

getsentry/sentry-javascript: Official Sentry SDKs for Javascript

いくつかのパッケージがありますが、ブラウザ上で動作する React や Vue 製の Web アプリケーション であれば @sentry/browser@sentry/integrations をインストールすれば良いようです。
型定義 (@sentry/types) も提供されているので TypeScript でも利用できます。

基本

パッケージをインストールします。ここでインストールされるバージョンは 5.x の想定です。

npm i @sentry/browser @sentry/integrations

アプリケーションの出来るだけ早いタイミングで読み込み、 init() を実行します。

path/to/my/app.js
import { init } from '@sentry/browser'
import { Dedupe, ExtraErrorData } from '@sentry/integrations'

init({
  dsn: 'https://foobar@sentry.io/1234567890',
  integrations: [
    new Dedupe(),
    new ExtraErrorData({ depth: 3 })
  ]
})

init() が受け付ける引数は以下で定義されていますが、最低限必要なのは dsn だけなのかなと思います。

integrations に渡している Dedupe, ExtraErrorData はオプショナルになります。これらは @sentry/browser@4.x ではデフォルトで適用されていた物でしたが、 5.x からは明示的に登録してあげないと適用されません。
使い方や役割は こちらの公式ドキュメント を参照してください。

基本的には以上で完了ですが、利用している JS フレームワークによってはそれぞれ異なる integrations が必要になります。
下記は Vue.js の場合です。

path/to/my/app.js
import Vue from 'vue'
import * as Sentry from '@sentry/browser'
import * as Integrations from '@sentry/integrations'

Sentry.init({
  dsn: 'https://foobar@sentry.io/1234567890',
  integrations: [
    new Dedupe(),
    new ExtraErrorData({ depth: 3 }),
    new Integrations.Vue({ Vue })
  ]
})

他のフレームワークの場合については公式ドキュメントから参照してください。
Docs - JavaScript

エラー発生時の認証ユーザー情報をログに含める

init() の実行よりも後に、 configureScope() のコールバック内で scope.setUser() を実行します。
(scope の定義はこちら: https://github.com/getsentry/sentry-javascript/blob/4.0.6/packages/hub/src/scope.ts)

import * as Sentry from '@sentry/browser'

const user = {
  id: '1',
  email: 'foo@bar.baz',
  username: 'FooBar'
}

Sentry.init(...)

Sentry.configureScope(scope => {
  scope.setUser( user )
})

この scope を使ってユーザー情報や Sentry のタグなどを設定できます。
例えば environment の値を設定する場合は次のようになります。

Sentry.configureScope(scope => {
  scope.setTag('environment', 'production')
})

削除もできます。それまで configureScope() で設定された値が丸ごと消されるようです。

Sentry.configureScope(scope => {
  // SPA でログアウト処理したら実行…とか?
  scope.clear()

  // 続けて次のスコープを設定したりも可能
  scope.setUser(user2)
})

これはいい感じのラッパーを作って操作するのが良さそうですね。

shohei_ot
フリーのWebエンジニアです。フロントエンド、バックエンドをメインにやってます。動的に表示が切り替わるフロントエンドが好きです。 つまづいた事の共有とか情報整理に記事を書きます。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away