オオカミ少年にならないフロントエンドエラー監視システムの工夫

この記事は 弁護士ドットコム [Advent Calendar 2020](https://qiita.com/advent-calendar/2020/bengo4com) 21日目の記事です。
昨日の記事は @NaokiTsuchiya さんの [タスクベースUIとREST - Qiita](https://qiita.com/NaokiTsuchiya/private/fe5622639d5f57c172d3) でした。

皆さんの監視システムはオオカミ少年 :wolf: になっていませんか？下記みたいな状況に心当たりはありませんか？

>うるさすぎるアラートにはイライラします。うるさいアラートによって、人々は監視システムを信用しなくなり、さらにはすっかり無視してしまうようになります。
>
>アラートを見て「このアラートは前にも見たな。数分したら勝手に消えるはずだから、何もする必要ないんじゃないかな」と思ったことは何度あるでしょうか。
>
> [「入門 監視」](https://www.amazon.co.jp/%E5%85%A5%E9%96%80-%E7%9B%A3%E8%A6%96-%E2%80%95%E3%83%A2%E3%83%80%E3%83%B3%E3%81%AA%E3%83%A2%E3%83%8B%E3%82%BF%E3%83%AA%E3%83%B3%E3%82%B0%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AE%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3-Mike-Julian/dp/4873118646) 第三章より

弊社でも、昨年DataDogのフロントエンド監視を導入しました。導入したものの、気を抜くとすぐにオオカミ少年になるアラート。アラートがなることになれて、本当の大事故につながるのは避けたいですよね。

今回は、フロントエンド監視の難しさと、弊社の試行錯誤をまとめました。

導入について詳しくは、[DatadogでフロントエンドのJSエラーを収集してサービス改善 - Qiita](https://qiita.com/komtaki/items/a2d3f06e2265e55b0c08)をご参照ください。


# 三文まとめ

- アラートで、サポートするブラウザの明確化
- 対応不要なエラーの除外
- 監視単位の分割と閾値の設定


# フロントエンドの監視

ここでのフロントエンドの定義は「入門 監視」と同様に下記とします。

> ブラウザあるいはネイティブなモバイルアプリケーションによってパースされて実行されるすべてを、フロントエンドと定義
>
> [「入門 監視」](https://www.amazon.co.jp/%E5%85%A5%E9%96%80-%E7%9B%A3%E8%A6%96-%E2%80%95%E3%83%A2%E3%83%80%E3%83%B3%E3%81%AA%E3%83%A2%E3%83%8B%E3%82%BF%E3%83%AA%E3%83%B3%E3%82%B0%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AE%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3-Mike-Julian/dp/4873118646) 第6章　フロントエンドより

最近SPAの普及も進んできて、「サーバーサイドのレスポンスは正常なのに、画面がホワイトアウトしてしまう。」といったケースが発生したり、ユーザーが実際に見ているブラウザ上での監視が求められています。

フロントエンド監視には、大きく二種類あると思います。

- エラーの監視
- 表示速度の監視

エラーの監視は、ブラウザ上でのアプリのクラッシュを検知するもの。表示速度の監視は、SpeedIndex等の指標を用いて、レンダリング等に異常がないか、ユーザー体験を損なっていないかを監視するものです。

今回は、エラーの監視を中心に見ていきます。

# エラー発生対応ブラウザの明確化

サーバー監視の場合、自身で作成した単一の動作環境で実行されます。一方、フロントエンドの場合、ユーザーのそれぞれのブラウザで実行されます。ブラウザごとによって、サポートされているAPIが異なり動作が再現できない事が多々あります。

下記はFetch APIの例です。サポートタイミングやサポートレベルがバラバラなことがわかります。

![Caniuse fetch Api.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/525723/c541da12-7497-6b42-661b-3e583395da02.jpeg)
https://caniuse.com/?search=fetch

そのため、監視する動作環境の絞り込み等の工夫が必要に感じます。

サイトで公開している対応ブラウザと、JSのBuild設定を元に、エラー監視するブラウザを絞り込むのが良いと思います。

対応しないブラウザを対象に入れていると、エラーの数が増えてきて紛らわしくなります。またBotの除去にも役立ちます。

弊社でも最近、脱IEに向けて動き出しました。しかし、まだまだIEユーザーは残っているので、サービスとしての強い判断が求められます。

### サイト上の動作確認機種&ブラウザ

https://www.bengo4.com/sp/static/support/

弊社の例だと、サイト上では、標準ブラウザの最新バージョンになっています。

### JSのビルド設定の対応ブラウザ

最近のモダンなフロントエンド開発では、多くの場合Webpackを使っていると思います。そして、[browserslist](https://github.com/browserslist/browserslist)を使用して、`.browserslistrc`やpackage.json に設定が記述されているでしょう。その場合、`npx browserslist`で対象のブラウザの一覧を確認できます。


下記は今の弊社のwebpackの設定です。実際はかなり多様なブラウザと古いバージョンをサポートしていることがわかります。


```/.browserslistrc
last 4 versions
Android >= 4
```

```bash
$ npx browserslist
and_chr 73
and_ff 66
and_qq 1.2
and_uc 11.8
android 67
android 4.4.3-4.4.4
android 4.4
android 4.2-4.3
android 4.1
android 4
baidu 7.12
bb 10
bb 7
chrome 73
chrome 72
chrome 71
chrome 70
edge 18
edge 17
edge 16
edge 15
firefox 66
firefox 65
firefox 64
firefox 63
ie 11
ie 10
ie 9
ie 8
ie_mob 11
ie_mob 10
ios_saf 12.2
ios_saf 12.0-12.1
ios_saf 11.3-11.4
ios_saf 11.0-11.2
kaios 2.5
op_mini all
op_mob 46
op_mob 12.1
op_mob 12
op_mob 11.5
opera 58
opera 57
opera 56
opera 55
safari 12.1
safari 12
safari 11.1
safari 11
samsung 9.2
samsung 8.2
samsung 7.2-7.4
samsung 6.2-6.4
```

これらをベースに実際のユーザー利用ユーザー数を加味して、Chrome, Firefox, Edge, Safariをアラート対象ブラウザに設定しています。エラー数の揺らぎを抑えるため、可能な限り厳しく限定します。

上記で、IEを抜いているのは、今後の廃止の準備です。IEを入れると、エラーが一気に増えるんですよね。:cry:

# 対応しないエラーを除外する

サービスを運営していると、どうしても直せないエラーが出てきます。ユーザーのネットワークに依存するものや、無害なエラーです。こういったエラーが、アラート対象に入っているとオオカミ少年の原因になります。

いくつか代表的な例を確認してみます。

## 広告タグ, 分析タグのエラー

メディアサイトだと、広告タグや分析タグが入っているはずです。Google Adsense, Google Analytics, Marketo..etc。ユーザーごとに、動的に要素を書き換えるので、多様な要因でエラーになることが多いです。

アプリケーションのエラーアラート対象からは除外するべきです。広告運用に力を入れているなら、広告JSエラー専用のアラートを作成するのも一つの手かもしれません。

```
XHR error POST https://stats.g.doubleclick.net/j/collect?t=dc....

Failed to load
```

## ネットワーク起因の可能性のあるエラー

弊社の例ですと、結構このエラーが発生します。ファイルサイズが大きいもので、ユーザのネットワーク環境が不安定な場合、ファイルが破損すると推測されます。

状況に応じてこのようなエラーは除去した方がいいですが、本当にバグが混入していることもあるので注意が必要でしょう。

```
Unexpected token '<'
```

## ResizeObserver loop limit exceeded

ResizeObserver インターフェイスの機能は、Element のコンテンツを配置できるボックス（ボーダーボックスからパディングを引いたもの）または SVGElement のバウンディングボックスへの変更を監視です。無限のコールバックループとそれ自身のコールバック関数でサイズ変更することによって生じるであろう循環的な依存関係を避けます。

ResizeObserverの機能が監視のみで、ループが最大値に達してサイトが壊れることはありません。そのため、基本的に無視して問題ないと思います。

> このエラーは、ResizeObserverが単一のアニメーションフレーム内ですべての観測を配信できなかったことを意味します。それは良性です（あなたのサイトは壊れません）。
>
>[google chrome - ResizeObserver - loop limit exceeded - Stack Overflow](https://stackoverflow.com/questions/49384120/resizeobserver-loop-limit-exceeded)

## ユーザーのchrome拡張のエラー

consoleに上がるエラーを全て収集していると、下記のようなchrome拡張等のエラーが収集されてしまうことがあります。
サービス起因のものではないので、除外しましょう。

```
TypeError: Cannot read property 'value' of undefined
  at messageCheck @ chrome-extension://ckcjbalmdhnljpnckbplelepkcfjpalb/ow.js:73:17
```

# 監視対象の分割と閾値の調整

弊社の例だと、監視対象は二つに分けられます。

一般ユーザー側のページは、一般公開されているため、かなりアクセスがあり、エラーも多く発生しています。

一方、弁護士マイページの方は、ユーザーが弁護士に限られているため、エラー数は少ないです。ですが、Reactで構築されているため、クラッシュすると大事故につながります。

- 一般ユーザーページ -> 大きい閾値
- 弁護士向けページ -> 小さい閾値

そのため、ページをURLでグルーピングして、閾値を設定し、2つのアラートを用意しています。閾値が大きく異なる場合、監視単位を分割するのは非常に効果的だと思います。

# DataDogでの設定例

![スクリーンショット 2020-12-21 16.13.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/525723/cb1509d1-a194-ae90-cb0c-d5b37c6fd405.png)

- ブラウザのログに限定
  - `source:browser`
- 本番環境
  - `@env:production`
- ブラウザの種別を指定
  - `@http.useragent_details.browser.family:(*Chrome* OR *Edge* OR *Safari* OR *Firefox*)`
- ネットワークエラーを除外
  - `-@error.origin:network -"Network request failed" -"Unsuccessful HTTP response"`
- 広告タグ等、chrome拡張など修正できないエラーを除外
  - `-"Script error" -YadsTimelineManager -FB -twttr -*doubleclick* -*chrome* -ResizeObserver`


# まとめ

まだまだ試行錯誤の領域ですが、簡単にまとめてみました。完成には程遠く、botのユーザーエージェントのなりすましには対応できず、誤報があがっています。

実際にどのようなアラートの設定が組めるかは、使用している監視Sassにもよると思います。DataDogもまだまだ発展途中ですが、なかなか使い勝手は良いと思うので、機会があれば触ってみてください。

モダンなフロントエンド開発を目指していきましょう。:rocket: