エラー監視の仕組みを強化した話

ハイリンク開発エンジニアの梶山(@h__kajiyama)です。今回は大切なエラートラッキングの改善についてのおはなしです

はじめに

サービス運営において、本番環境でのエラーは避けられません。入念に自動テストや動作確認を行なったとしても、予期せぬ障害は発生します。起きてしまったとき、エラートラッキングを適切に行うことで、問題の早期発見や迅速な原因特定を行えます。障害の被害を最小限に抑えるうえで適切で迅速な対処が最も大切です。

エラートラッキングはツールを導入するケースが多いと思いますが、導入しても適切な利用をしないと問題の早期発見や迅速な原因特定に寄与しません

この記事では私たちのチームが実際に直面していた課題とそれをどう改善してきたかを具体例を交えて紹介します。

抱えていた課題

弊サービスではツールとしてSentryを導入していました。しかしそれを効果的に活用できておらず、特に以下2つの課題がありました。

  1. エラー通知の氾濫による危機感の麻痺

    対応の必要性に関わらずエラー通知が常に流れている状態にあり、チームメンバーがそれをいつもの光景として無視するようになっていました。重要なエラーと些細なエラーの区別がつかず、重要なエラーが通知されているのにもかかわらず気付けないことが何度かありました。

  2. エラー原因箇所特定の困難さ

    エラーメッセージが分かりやすいものであれば良いのですが、全てがそうではありません。どこで起きたのか特定をするために労力が必要で、調査を後回しにした結果積み上がり手を付けるのが億劫になってしまっていました。

これらの課題は単にツールを導入するだけでは解決できません。エラートラッキングを効果的に行うにはツールの導入だけではなく、適切な設定やチーム文化の変革が必要でした。

課題解決に向けたアプローチ

週次で行っている振り返りでエラーの見逃しが発生したことについて議論し、そこでエラー監視の課題と目標を検討し改善に着手しました。ここでは実際に行ったアプローチを紹介していきます。

  1. エラー通知の信頼性確保

    本当に必要なエラー通知のみが行われ、通知が来た際には対応が必須である状態を作るために通知の最適化を行っていきました。

    1. 不必要な通知の削除

      まず、一番の問題であった通知すべきでないエラーも通知されてしまっている状態を解消しました。エラーハンドリングが適切に行われているが”一応”Sentryに通知を送っている箇所や、ブラウザ拡張機能等のユーザー依存で発生するエラーが存在します。これらはエラーとして通知を行うべきではないです。Sentryに個別で送信している箇所の精査を行い、削除やログ出力へ移行などの対応をしました。また、Sentry公式ドキュメントを参考にフロントエンドの不要な通知を無視する設定も行いました。これらを行ったことで、不要な通知が激減し見通しが大変良くなりました。

      • [Sentryの設定の一部 sentry.client.config.js]

          Sentry.init({
            ...
            // https://docs.sentry.io/platforms/javascript/guides/react/configuration/filtering/#decluttering-sentry
            ignoreErrors: [
              // Random plugins/extensions
              'top.GLOBALS',
              // See: http://blog.errorception.com/2012/03/tale-of-unfindable-js-error.html
              'originalCreateNotification',
              'canvas.contentDocument',
              'MyApp_RemoveAllHighlights',
              'http://tt.epicplay.com',
              "Can't find variable: ZiteReader",
              'jigsaw is not defined',
              'ComboSearch is not defined',
              'http://loading.retry.widdit.com/',
              'atomicFindClose',
              // Facebook borked
              'fb_xd_fragment',
                  ...
            ],
            denyUrls: [
              // Facebook flakiness
              /graph\.facebook\.com/i,
              // Facebook blocked
              /connect\.facebook\.net\/en_US\/all\.js/i,
              // Woopra flakiness
              /eatdifferent\.com\.woopra-ns\.com/i,
              /static\.woopra\.com\/js\/woopra\.js/i,
              // Chrome extensions
              /extensions\//i,
              /^chrome:\/\//i,
              /^chrome-extension:\/\//i,
              // Other plugins
              /127\.0\.0\.1:4001\/isrunning/i, // Cacaoweb
              /webappstoolbarba\.texthelp\.com\//i,
              /metrics\.itunes\.apple\.com\.edgesuite\.net\//i,
              ...
            ],
          });
        
    2. 放置されているエラーの解消

      放置されているエラーに対して一つずつ担当と対応期限の目安を決めることを行いました。これを継続することでエラーの数を着実に減らし、最終的には通知が未知のエラーを示す状態を実現させました。

    3. 未知のエラーに対する対応

      エラー通知を受けた際にはエンジニアが即座に調査し対応方針を決定することをチームで決めました。エラー内容はすぐに把握しなければならないことは当然ながら、発生時に明確に方針を決めることでその後放置されることがないようにするためです。これによりエラー通知が必要なものだけ届く状態を維持できます。

  2. コード連携による原因箇所特定の高速化

    原因特定を迅速にするためにFrontend, Backendともにコードとの連携を行いました。これによりエラーが発生したときにソースコードのどこの場所で発生したかがSentryのエラー詳細画面を見るだけで分かるようになりました。また、release tagも送信することで、どのリリースで初めて発生したエラーかどうかも分かるようになります。これらの設定を行ったことで、エラー発生時の原因特定が早くなりました。エラーが発生したコードの箇所はわかっているので、後は処理を追うだけでどのような経緯でエラーが発生したか分かります。

    [参考: Sentry公式docs https://docs.sentry.io/platforms/javascript/sourcemaps/]

取り組みの結果

現在はエラーをすぐに検知し対応する環境が作れています。例えば、一部ユーザーのみが対象のコンポーネント描画に関する障害があるリリースで発生しました。一部ユーザーのみに影響する場合だと、件数が少なく再現に手間がかかるため以前は把握や対応が遅れがちでした。しかし、改善後のチームでは一回目のエラー発生の通知にいち早く気づき、すぐに巻き戻し対応と該当部分の修正を行えました。結果的に数人のユーザーさんが違和感を感じる程度に抑えられ、理想的な対応が行えたと言えます。

まとめ

ツールの活用とチームの仕組み改善により、エラー検知から対応までの時間を大幅に短縮し、サービスの安定性が向上しました。また、未知だが起こっている可能性がある障害に怯えることなく心理的安全性が高い状態でのサービス監視や開発が進行できています。

ツールは強力な手段ですが、適切に活用しないと結局サービスの改善はされません。今後も課題に対して目先の解決を求めず本質的な改善を続けていきます。

herp.careers