Sentryでjsのエラーログを収集してみた

# Sentryとは
様々な言語から送信されたイベントログを表示してくれるやつです。OSSです。[サービス](https://getsentry.com/welcome/)でも提供されています。今回はサービス版でjsのエラーログ収集をやってみました。

# Sentry使用開始までの手順(簡略)
1. アカウント作成
2. チームとプロジェクトを作成
3. jsへの組み込み
4. 動作確認

## 1. アカウント作成
以下のURLへアクセスし、アカウントを作成します。
https://www.getsentry.com/signup/

## 2. チームとプロジェクトの作成
チームとプロジェクトを作成します。プロジェクトを作成する際にプラットフォームを選択する必要があるので、そこでJavaScriptを選択します。


## 3. jsへの組み込み
Sentryへエラーログを送信するコードを仕込みます。
基本的にドキュメントの通りにやればできます。
https://docs.getsentry.com/hosted/clients/javascript/

```html:index.html
// スクリプトをロード
<script src="//cdn.ravenjs.com/1.1.19/raven.min.js"></script>
```

```js:app.js
// PUBLIC_DSNを設定
// DSNフォーマット: '{PROTOCOL}://{PUBLIC_KEY}:{SECRET_KEY}@{HOST}/{PATH}{PROJECT_ID}'
// SECRET_KEYを含んだものを設定しようとすると、怒られるのでSECRET_KEYは抜く
Raven.config('{PROTOCOL}://{PUBLIC_KEY}@{HOST}/{PATH}{PROJECT_ID}').install();

try {
  // エラー発生 
  doSomething(a[0])
} catch(e) {
  // Sentryへ送信
  Raven.captureException(e)
}
```

## 4. 動作確認
サーバを立ててアクセスし、エラーをSentryへ送信し確認します。
ローカルで試した場合以下のようなエラーが出ますが、Sentryのソースを読んだ限り問題なさそうだったので無視して大丈夫です。

```
There were errors encountered while processing this event

Security violation
{"url":"http://localhost:3000/js/index.js?1440634018942","value":"http://localhost:3000/js/index.js?1440634018942 matches the URL blacklist"}
```

これでエラーイベントを収集ができました。

## Tips
```js
// 想定外のエラー捕捉
window.onerror = function(message, file, line, col, error){
  Raven.captureException(error);
}

// Promise(bluebird)でcatchからもれたエラーをまとめて捕捉
// bluebirdは予め読み込んでおく
// bluebird以外のPromiseは頑張ってcatchする
Promise.onPossiblyUnhandledRejection(function(error){
    throw error;
});
```

## Sentry使用開始までの手順(簡略)参考URL
- https://docs.getsentry.com/hosted/clients/javascript/
- https://github.com/getsentry/sentry/blob/master/src/sentry/http.py
- https://github.com/getsentry/raven-js/blob/master/docs/usage.rst


# SourceMapへの対応
最近はBrowserify + uglify等でビルド&Minifyを行ったものをデプロイすることが多くなってきていると思います。
minifyされたjsのエラーログは正直何が起こっているのかわからないです。
SentryはSourceMapに対応しているので、SourceMapを使ってエラーログを整形してくれます。便利

以下で出現するコード・app.js・app.js.map等はBrowserify + uglifyでビルド&minifyされているものとします。ビルド方法等はここでは触れません。

## SourceMapをPublicにしている場合

```
# web server
DocumentRoot/
　　├ index.html
　　└ js/
　　　├ app.js
　　　└ app.js.map
```

```js
//# sourceMappingURL=app.js.map
```

Publicサーバでこんな感じのディレクトリ構成で、jsにsourceMappingURLが設定してある場合、SentryがよしなにSourceMapを取得し、エラーを整形してくれます。
多くの場合、SourceMapは公開したく無いと思うので、その場合は別途設定が必要です。

## SourceMapをPublicにしない場合
```
# web server
DocumentRoot/
　　├ index.html
　　└ js/
　　　└ app.js
```

SourceMapを公開しない場合、Sentryへ.jsと.js.mapのアップロードが必要になります。
手順としては

1. jsへリリースの設定
2. リリースの作成
3. ファイルアップロード


となります。
以下のコマンドはバージョン```v1.0.0```のリリースを行った例となります。api_key・APIのエンドポイントは適宜自分の環境に合わせて書き換えてください。

### 1. jsへ設定
jsへリリースの設定を行います。

```js
var Raven = require('raven-js');
Raven.config('___PUBLIC_DSN___', {
  // releaseを設定
  release: 'v1.0.0'
}).install();

```

### 2. リリースの作成
Sentryにリリースを作成します。

```bash
curl https://app.getsentry.com/api/0/projects/:organization_slug/:project_slug/releases/ \
  -u [api_key]: \
  -X POST \
  -d '{"version": "v1.0.0"}' \
  -H 'Content-Type: application/json'  
```

### 3. ファイルアップロード
Sentryへ.jsファイルと.js.mapファイルをアップロードします。

```bash
curl https://app.getsentry.com/api/0/projects/:organization_slug/:project_slug/releases/v1.0.0/files/ \
  -u [api_key]: \
  -X POST \
  -F name="http://example.com/js/app.js" \
  -F file=@app.js
  
curl https://app.getsentry.com/api/0/projects/:organization_slug/:project_slug/releases/v1.0.0/files/ \
  -u [api_key]: \
  -X POST \
  -F name="http://example.com/js/app.js.map" \
  -F file=@app.js.map
```

これで設定完了です。
エラーログがSentryで整形されるようになります。

## SourceMap参考URL
- https://app.getsentry.com/docs/api/releases/
- https://docs.getsentry.com/hosted/clients/javascript/sourcemaps/