Sentry を導入したので導入手順をまとめました。
PHP (Laravel) と Vue.js の場合について記載しています。
Sentry?
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
に設定を追加する必要があるようです。
'providers' => array(
// ...
Sentry\SentryLaravel\SentryLaravelServiceProvider::class,
)
'aliases' => array(
// ...
'Sentry' => Sentry\SentryLaravel\SentryFacade::class,
)
Sentry へのロギングを実施させる仕組みとして、 app/Exceptions/Handler.php
の report()
に手を加えます。
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
に書き込むなりしましょう。
return array(
'dsn' => env('SENTRY_LARAVEL_DSN', 'https://foobar@sentry.io/1234567890'),
...
仕上げに Laravel の 500 エラーページを用意します。
サーバエラーが起きた際に、ロギングだけでなくユーザーに詳細な報告を入力してもらうためのフォームを表示できます。
<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 に送信できます。
<?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
に登録します。
...
'sentry.context' => \App\Http\Middleware\SentryContext::class
];
ロギング時にユーザー情報を含めたいルートに対してこの Middleware を適用します。
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()
を実行します。
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
だけなのかなと思います。
- https://github.com/getsentry/sentry-javascript/blob/5.0.0/packages/browser/src/backend.ts#L16
- https://github.com/getsentry/sentry-javascript/blob/5.0.0/packages/types/src/options.ts#L8
integrations
に渡している Dedupe
, ExtraErrorData
はオプショナルになります。これらは @sentry/browser@4.x
ではデフォルトで適用されていた物でしたが、 5.x
からは明示的に登録してあげないと適用されません。
使い方や役割は こちらの公式ドキュメント を参照してください。
基本的には以上で完了ですが、利用している JS フレームワークによってはそれぞれ異なる integrations
が必要になります。
下記は Vue.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)
})
これはいい感じのラッパーを作って操作するのが良さそうですね。