Article by: Lewis D.
Logs は、開発チームが問題を調査するときに最初に確認することが多い場所です。しかし、Logs は後回しで追加されることが多く、開発者は「ログを出しすぎる/出さなさすぎる」のバランスに悩みがちです。
経験豊富な開発者なら、調査を頼まれて 200MB のプレーンテキストのログファイルを渡された経験を覚えているかもしれません。3 時間と 4 本の Python スクリプトを費やした末に、問題が別のコンポーネントにあると分かる、というようなことです。
これまで、ロギングを簡単にするための多くの標準やライブラリが作られてきましたし、React Native にはロギング関数も豊富にあります。私たちの React Native ロギング入門ガイドは良い出発点です。ただ、さらに一段レベルを上げたいなら、このガイドで Sentry のロギング機能を使う方法を紹介します。これにより、ログが有用になり、必要な情報をすぐに取り出せるようになります。
Sentry に Logs を取り込む
このガイドでは、シンプルな React Native(Expo)アプリを使って、Sentry のさまざまなロギング機能の例を示します。
このアプリは、フィールドに基本的なバリデーションがある問い合わせフォームです。手元で同じように試したい場合は、デモリポジトリ内にこのアプリがあります。

デモの React Native アプリのインターフェース
既存の React Native アプリケーションがある場合やこれから作る予定がある場合でも、このガイドでは、Sentry を使ったロギングを最大限に活用するために必要な手順を説明します。
セットアップ
Sentry の機能を使い始めるには、まずプロジェクトに Sentry を導入する必要があります。最初に Sentry で新しいプロジェクトを作成し、プラットフォームとして React Native を選択します。次に、インストールウィザードを実行して、ローカルのプロジェクトに必要な設定を追加します。

プロンプトが表示されたらロギングを有効にします。設定が完了すると、メインの App.js に次のようなコードが追加されているはずです。

これにより、Sentry SDK が初期化され、Sentry のロギングライブラリによる Logs が有効になります。
Sentry Logger API
Sentry を初期化して Logs を有効にしたので、Sentry.logger 名前空間を使って、ログを Sentry のダッシュボードに送信できます。
ログレベルは次のとおりです。
- trace
- debug
- info
- warn
- error
- fatal
また、Sentry.logger.fmt 関数を使うと、ログメッセージにプロパティを追加できます。
サンプルアプリでは、handleSubmit 関数に新しいログ呼び出しを追加します。


ログには追加の属性を手動で付与できます。これらはログメッセージ本体の一部にはならず、ログに付随する形で追加され、あとから検索やフィルタに使えます。
試すには、先ほど追加したログを次のように更新します。

フォームを送信すると、ログのペイロードに新しい filterID と extraMessage の両方のフィールドが表示されます。

インテグレーション
Sentry Logger API は動くようになりましたが、このアプリにはすでに、デフォルトの JavaScript の console オブジェクトを使ったロギングがあります。幸い、すべてを書き直す必要はありません。Sentry には、デフォルトの JavaScript ロギングと統合する方法も用意されています。
App.js の Sentry.init 呼び出しで、enableLogs: true の行の後に、次のコードを追加します。


ただし、このガイドの後半で示すとおり、ダッシュボード側のフィルタリングでもノイズは減らせます。そのため、多くの場合は、役に立つ情報はできるだけ Sentry に送っておくほうがよいでしょう。
ではアプリを再起動し、フォームに入力して、送信されるログを確認してみましょう。

こうした統合ログでも、Sentry は発生元の環境やブラウザ種別など、利用可能な追加情報をすべて関連付けます。これらのデータは、ログのフィルタ、検索、グルーピングに利用できます。
検索、フィルタリング、グルーピング
Logs ダッシュボードでは、すべてのログを 1 か所で確認できるだけでなく、必要なものを正確に見つけるためのツールも使えます。
ダッシュボード上部の検索バーを使えば、特定のログメッセージを探せます。ログメッセージ本文に含まれるテキストで検索することも、Sentry のクエリ構文を使って特定フィールドで検索することもできます。
たとえば、検索バーに sub と入力すると、フォーム送信に関連するログをすべて取得できます。

ログレベルでも検索できます。warning のログだけを表示したい場合は、検索バーに severity:warn と入力します。

先ほど追加した追加属性でも絞り込めます。検索バーに filterID:01 と入力してください。

ログがアプリケーション内の複数の箇所から送られてくる場合でも、カスタム属性を使えば、特定のコンポーネントやフローに関するログを素早く切り分けられます。
複数のフィルタを組み合わせることもできます。たとえば、filterID とログレベルの両方で絞り込み、アプリの特定箇所からの warning ログだけを表示するといったことが可能です。
また Sentry では、さまざまな属性でログをグルーピングできます。行うには、 >> Advanced ボタンをクリックし、Group By のドロップダウンを開いて、severity を選択します。

ログはログレベルごとに整理されたので、各 severity にどれだけログがあるかを把握しやすくなりました。環境、ブラウザ種別、またはログに追加した任意のカスタム属性でもグルーピングできます。
これは、特定のユーザーや特定の環境にだけ影響する問題をデバッグするときに特に有用です。ブラウザや OS ごとにすばやくグルーピングして、問題が特定のプラットフォームに限定されているかどうかを確認できます。
実際のアプリケーションをデバッグする
Sentry ロギングの本当の価値を見るために、もう少し完成度の高い例を見てみましょう。
私たちは、猫の写真に upvote / downvote できる「猫投票アプリ」を作りました。このアプリは、React Native のフロントエンドと、SQLite データベースを持つ Express.js のバックエンドで構成されています。フロントエンドは外部 API から猫の画像を取得し、それをデータベースに保存します。
ロギング機能を自分でも試したい場合は、このアプリのリポジトリを clone できます。
このガイドは React Native に焦点を当てているため、Sentry はフロントエンド側にだけ設定しています。ただし、バックエンドのコードについても Express.js 用の Sentry プロジェクトを作ることは可能ですし、作ることをおすすめします。
アプリ構成
このアプリは次の要素で構成されています。
- 猫画像と upvote / downvote ボタンを表示する投票画面
- 最も人気のある猫を表示する winner 画面
- データ取得と状態を管理する context provider
- バックエンドとの通信を担当する API service
フロントエンドの frontend/App.js における Sentry の設定は次のとおりです。

ユーザー操作のトラッキング
frontend/src/screens/CatListScreen.js では、ユーザーが猫に投票したタイミングをログします。logger API と breadcrumbs の両方を使って、ユーザーが何をしたかの足跡(トレイル)を残します。

バックエンドの問題をデバッグする
特定の猫に投票したとき、一部のユーザーが 500 Internal Server Error(API エラー)を受け取っている、という報告があったとします。調査のために Logs ダッシュボードを確認します。
まず、直近の error ログをダッシュボードで確認します。severity:error で絞り込むと、Vote submission failed のログがいくつか見つかります。
そのうちの 1 つをクリックして詳細を確認します。

Logs には次の情報が表示されます。
- ユーザーが投票しようとした猫(catId: “133”)
- 投票の種類(voteType: “upvote”)
- バックエンドからのエラーメッセージ(errorMessage: “API Error: 500″)
- エラーが発生したタイムスタンプ
これは error レベルのイベントなので、Sentry には Issue も記録されます。Issues ダッシュボードへ移動し、該当するエラーイベントをクリックします。

Issue のエントリでは、下へスクロールすると、エラーに至るまでの breadcrumb のトレイルを確認できます。
Logs からは、ユーザーが猫一覧を読み込み、upvote ボタンをクリックし、その後 API リクエストが 500 の HTTP ステータスコードで失敗したことが分かります。

これで、問題がバックエンド側にあることが分かりました。同じタイムスタンプ付近のバックエンドのサーバーログを確認すると、データベースの制約エラーが見つかりました。バックエンドは投票を挿入しようとしましたが、外部キー制約違反(cat ID がデータベースに存在しない)により拒否されていました。
Sentry の Logs に戻り、この猫がいつ追加されたのかを検索します。operation:fetchCats で絞り込むと、アプリが外部 API から猫を取得していたことが分かります。しかし、データベースに保存しようとした際に、リクエストのうち 1 つが失敗していました。Sentry のログには次のように表示されています。

問題は明確です。アプリが新しい猫を取得したとき、一部はデータベースへの追加に成功しましたが、別の一部は ID の重複により失敗していました。結果として、ユーザーにはデータベースに存在しない猫が表示され、その猫に投票しようとすると、バックエンドが投票を拒否していました。
この問題は、猫を取得するロジックのエラーハンドリングを改善することで修正できます。保存に失敗した猫は UI から取り除き、ユーザーがデータベースに存在しない猫に投票できないようにします。

パフォーマンス監視
エラーに加えて、Sentry の spans 機能を使えばパフォーマンスも追跡できます。frontend/src/context/CatsContext.js では、猫の読み込みにどれくらい時間がかかっているかを計測できます。

spans を使うと、パフォーマンス追跡の開発者体験が向上します。Sentry ダッシュボードの Performance タブで span データを確認でき、アプリケーション内の遅い処理やボトルネックを簡単に特定できます。
beforeSendLog 関数
beforeSendLog 関数を使うと、Sentry に送信する前にログをフィルタできます。Sentry に届くデータを細かく制御できるため、十分なログを確保しつつ、ダッシュボードをノイズで埋めないようにバランスを取るのに役立ちます。
たとえば、本番環境では debug レベルのログを除外したり、機密情報を取り除いてから Sentry に送信したりできます。

null を返すことで、そのログが Sentry に送信されないようにできます。この方法は、機密性の高いユーザー情報を保護しつつ、ログを整理して関連性の高い状態に保つのに役立ちます。
Logs を超えて
Sentry のロギングは、ログをただの生データから、問題の診断で膨大な時間を節約できる有用で直感的なツールへと変えます。
Sentry のロギング機能をセットアップする手順がまだ不明な場合は、logs の設定、または drains と forwarders の設定に関するドキュメントを参照してください。
このガイドでも触れたとおり、ロギングは tracing や profiling といった Sentry の他の機能と密接に連携します。
これらの機能をすべてセットアップすれば、Sentry のツール群を最大限に活用することができます。
FAQ
■構造化データをメッセージに詰め込むのではなくログに添付できますか?
はい。そうすることをおすすめします。catId や voteType、feature のような属性を追加すると、ログメッセージの読みやすさを保ちつつ、ログを検索・フィルタ可能にできます。ログメッセージは見出し、属性はデバッグ時に助けになる注釈だと考えてください。
■Sentry では、Logs と Issues はどういう関係ですか?
Logs と Issues はつながっていますが、役割が異なります。Logs は「何が、どの順番で起きたのか」を理解するのに役立ちます。Issues は「対処すべき失敗」を表し、通常はエラーやクラッシュに関連付きます。error レベルのログが記録されると、Sentry は Issue を作成または更新し、Logs、breadcrumbs、スタックトレース、ユーザーコンテキストを 1 か所にまとめて関連付けられます。
■フロントエンドとバックエンドにまたがる問題のデバッグでは、Logs はどう役立ちますか?
Logs は出来事の流れを語り、トレーシングは時間軸を示します。フロントエンドで意味のあるイベントをログを記録し、バックエンドのログやトレースと組み合わせることで、ユーザーのタップからデータベースエラーに至るまで、リクエストを追跡できます。特に、フロントエンドのエラーが、実は別の姿をしたバックエンド問題だった場合に有効です。
■最初から選別してログを記録すべきですか?それとも全部記録して後で絞り込むべきですか?
一般的には、意図を持って積極的にログを記録するのがよいでしょう。インシデント後に不足しているログを後追いで追加するより、Sentry 上でノイズの多いログを後からフィルタするほうが簡単です。状態の変化、ユーザー操作、システム境界(API 呼び出し、永続化、非同期処理)を中心に記録してください。量が問題になったら、ログレベルや beforeSendLog で調整します。
■Logs と breadcrumbs はどう使い分ければよいですか?
単体で検索・クエリできるものにしたいなら Logs を使います。エラーやクラッシュに付随するコンテキストとして残したいなら breadcrumbs を使います。Logs はアプリ全体で何が起きたかを伝え、breadcrumbs は何かが壊れる直前に何が起きたかを伝えます。
■ロギングを設定した次のステップは何ですか?
Logs をエラー、パフォーマンスの spans、リリースと関連付け始めてください。ロギングはより大きなフィードバックループの一部として使うと最も効果を発揮します。アプリがクラッシュしたかどうかだけでなく、コード変更が実際のユーザーにどう影響するかを理解する助けになります。
Original Page: Logging in React Native with Sentry
IchizokuはSentryと提携し、日本でSentry製品の導入支援、テクニカルサポート、ベストプラクティスの共有を行なっています。Ichizokuが提供するSentryの日本語サイトについてはこちらをご覧ください。またご導入についての相談はこちらのフォームからお気軽にお問い合わせください。


