この時点以降、ハードシグナルであれ、キャッチされなかった Swift のエラーであれ、NSException であれ、アプリ内で発生したあらゆるクラッシュが捉えられます。それぞれには、シンボリケート済みのスタックトレース、そこに至るまでの breadcrumbs、そしてそれが発生した正確なリリースの情報が付随します。

これによって実際に得られるのは、時間の経過に伴う安定性の明確な全体像です。本記事で紹介する他のすべての土台となるものです。
Error Monitoring
クラッシュの話が済んだところで、より捉えにくいエラーについて話しましょう。クラッシュは少なくとも自ら存在を知らせてくれます。私たちがより心配しているのは、そうではない失敗です。アプリは動き続けているのに、どこかで値の読み取りがひそかに間違っているというケースです。これはたいてい誤った計測値につながり、誤った計測値はユーザーの不満につながります。
Usage にとって、こうしたエラーを早期に検出し、素早く対応することは極めて重要です。先ほど触れたように、このアプリの多くの部分は、ドキュメント化されていないソースやAPIを通じてシステムデータを読み取っています。特定のデバイス・OSバージョン・ハードウェア世代ごとに、ある読み取り値がどのような形になるかを事前に必ず把握できるわけではありません。
その不確実性と付き合っていけるのは、網羅的なエラーロギングのおかげです。アプリが認識できない値を読み取るたびに、私たちはそれを Sentry で non-fatal error として記録します。これには、欠落しているフィールド、まだ対応していない型の構造、想定範囲を超えた数値などが含まれ、Sentry がプライバシー面でも役立つ場面です。
イベントには添付することを選んだコンテキストしか含まれません。送信するのは、予期しない読み取り値の形、たとえばグラフィックスカードのレスポンスの型やフィールドといった情報だけです。値そのものを送ることは決してありませんし、ユーザーに関する情報を送ることも決してありません。それでも何かがすり抜けてしまった場合にはbeforeSend が、各イベントがデバイスを離れる前にそれを洗い流す最後のチェックポイントになります。
私たちが最も頻繁に遭遇する具体的な例が、グラフィックスカードの読み取りです。Apple が GPU 統計として返すデータ構造は、macOS のバージョン間、そしてハードウェア世代間で微妙に変化してきました。少しだけ形の異なる新しい Mac が登場したとき、本来なら私たちは手探り状態に陥るはずです。ところが実際には、その予期しない構造が記録された Sentry イベントを当日のうちに受け取れるのです。
この早期警告のおかげで、新しい形への対応はたいてい次のリリースで出荷されます。ほとんどのユーザーがそのハードウェアを手にする頃には、修正はすでにリリース済みなのです。
「Error」だけでは足りないとき
パースやデコードのエラーで何が問題だったのかを突き止めるには、スタックトレースだけではまず足りません。私たちはほぼ必ず、エラーそのものと並べて失敗した対象を見たいと考えます。
Swift の Error プロトコルは、デフォルトでは任意のペイロードを持たないため、追加します。小さなラッパー構造体と、たった1つの拡張メソッドがあれば十分です。

with(data:) メソッドは、呼び出し側のためのシンタックスシュガーです。エラーの型を書き換えることなく、任意のエラーにコンテキストを付け足すことができ、付与するものが何もないときには何もしないよう穏当に振る舞います。典型的な使い方は次のとおりです。
throw GraphicsHelperFetcherError.displayMissingProperty(“sppci_model”).with(data: rawResponse)
そのうえで、キャプチャ地点でデータを取り出し、Sentry の scope に extra として乗せます。
Sentry 上では、このデータはイベントの中でラベル付きのフィールドとして、スタックトレースのすぐ隣に表示されます。私たちが扱うような、認識できないシステムの読み取り値や予期しないフィールドの形といったエラーでは、そのたった1つのフィールドが決め手になることがよくあります。
このパターンが実際に動いている様子をお見せしましょう。以下のスクリーンショットは、macOS アプリから得られた実際の Sentry イベントです。グラフィックスの読み取りで発生したパースエラーで、display オブジェクトの1つが、私たちが想定していたプロパティを持たないまま返ってきたケースです。スタックトレースはどこで失敗したかを教えてくれますが、data フィールドはなぜ失敗したのかを教えてくれます。生の構造がそこにそのまま示されていて、これまで見たことのない GPU と macOS の組み合わせで、そのフィールドが欠けているのです。これは、グラフィックスデータ内の display オブジェクトの扱いを更新すべきだというシグナルであり、たいていは次のリリースで修正を届けられます。


Size Analysis
クラッシュモニタリングとエラーモニタリングは、アプリが動いている間を見張ります。しかし、誰かが起動する前の段階で壊れていたビルドを検出することはできません。私たちはそれを痛い経験から学びました。
少し前のことですが、あるリファクタリングで、アプリのローカライズの1つが誤って削除されてしまいました。どういうわけかその差分は通常のレビュープロセスを通っておらず、壊れたリファクタリングを含むビルドがアップロードされ、リリース対象として選ばれてしまいました。本番環境に反映されると、その影響は即座に、しかもはっきりと現れました。原因が分かる前に、影響を受けたロケールのアクティブユーザーが崖から落ちるように減少したのです。
めったにないこととはいえ、こうしたことはどんなチームでも起こり得ます。私たちには、差分レビューにとどまらない第二の防衛線が必要でした。
Sentry の Size Analysis が、まさにその役割を果たしてくれました。これはリリースビルドごとに実行され、Sentry の他の機能がすでに使っているのと同じ version+build のリリースタグにサイズレポートを添付し、新しいビルドを1つ前のビルドと比較します。ローカライズファイルやアセット、あるいはバンドルリソース全体が消えてしまった場合、その差分によって見逃すことは不可能になります。逆の場合も同様です。なぜか肥大化したリリースは、その原因が内訳のすぐそこに表示されます。

Size Analysis は(おそらく)アプリのサイズを抑えることだけを目的としたものですが(私たちもその目的で使っています!)、私たちが心を動かされたのは、これをリグレッションのゲートとして使うという点でした。人手や自動化されたプロセスがレビューでこうした問題を捉える保証はなく、Size Analysis は追加のサニティチェックとしてうまく機能します。
さらにサイズレポートに加えて、リリース間の差分を監視し、ビルドが1つ前と比べて目に見えて重くなったり軽くなったりするたびに通知してくれる Sentry のモニターも設定しました。「軽くなる」方向は、先ほどのローカライズの一件を分かりやすく浮かび上がらせます。「重くなる」方向は、忍び寄る肥大化を捉えます。いずれにしても、これで私たちはこうした問題が深刻になる前に気づけると安心していられます。

Metrics
ここまでの内容はすべて、うまくいかないことを検出する話でした。最後のピースは、うまくいっていることを証明することです。
Metrics は比較的新しい Sentry の機能で、私たちはちょうど導入している最中です。Usage のようなアプリにとって、パフォーマンスとリソース使用量は、あれば嬉しいという程度のものではなく、それ自体が製品そのものです。そのため、コードベースのどこからでも独自の Counter や Gauge を送出でき、それらをクラッシュやエラーの隣に並べて見られることには、大きな意味があります。
私たちはサンプリングのレイテンシ、バックグラウンド処理の所要時間、同期間隔といった、もともと気にかけている項目をインストルメントしています。そうすることで、最適化の取り組みが実際にそれらの数値を動かしていることを Metrics で確認できます。
今のところ、手応えは上々です。もう少し使い込んだところで、あらためて詳しくご紹介したいと思います。
User Feedback
ユーザーの行動のすべてが、クラッシュやエラーとして現れるわけではありません。アプリは技術的には健全なのに、誰かが何かおかしいチャートをじっと見つめている、ということもあります。そうした場合には、直接教えてもらえたほうがありがたいのです。

私たちは Sentry の User Feedback をまず別の製品である WinWinKit で試しました。価値を実感し、すぐに Usage にも追加しなければならないと確信しました。
これは、より速い反復と、より強いユーザーエンゲージメントを生む大きな原動力の1つになりました。私たちが自信を持っておすすめできるものです。数行のコードだけで、ユーザーがアプリを離れることなくフィードバックを送れる、小さなアプリ内フォームが手に入ります。寄せられたフィードバックはクラッシュやエラーと同じワークスペースに、同じリリースのタグ付きで届きます。
導入を迷っているなら、私たちは自信を持っておすすめします。1件1件の報告が、次のビルドを、それがなかった場合よりも少しだけ良いものにしてくれます。
まとめ
私たちは今も綱渡りを続けていますが、最近ではその眺めを心から楽しめています。Apple はまた新しいアップデートを出すでしょうし、どこかの構造体は新しい形になり、これまで触れたことのない Mac が見たこともないバイト列を送ってくるでしょう。望むところです!
もし自分ではコントロールできないプラットフォームに依存する何かを作っているなら(そして正直なところ、そうでない人などいるでしょうか?)、アドバイスはシンプルです。できるだけ多くのセーフティネットを用意しておくこと。ユーザーはきっと、そのことに感謝してくれるはずです。