Article by: David Y.
本ブログの内容
- サンプルアプリケーションのセットアップ
- エラーの再現
- エラーの調査
- エラーの修正
- Next.js アプリケーションでエラーを特定するための Sentry トレーシング設定
- Sentry トレーシングで可能なその他の機能
ローカル開発中は、ブレークポイントや console.log があなたの正気を保ってくれるかもしれませんが、本番環境の問題はまったく別の話です。本番環境では、エラーが複数のマイクロサービスに分散していたり、難読化されたコードに隠れていたりします。それらを追跡するのは至難の業です。
そこで活躍するのが Sentry のトレースとスパンです。フルスタックかつ分散された環境において、ネットワークリクエスト、API 呼び出し、DB 取得などすべてを簡単に可視化できます。
Sentry の分散トレーシングは、Next.js アプリを通過する各ネットワークリクエスト、API 呼び出し、データベースクエリを明確かつ実用的に可視化します。推測に頼ることなく、パフォーマンスのボトルネックや複雑な障害が発生している箇所を正確にマッピングできます。
分散トレーシングにより、例えばデータベースのレコード欠落や想定外のペイロードを返すエンドポイントなど、エラーの根本原因をすばやく特定し、エラーがユーザー体験全体にどう影響するかを正確に把握できます。さらに優れているのは、他人のコードをあさったり、リポジトリの権限を待ったりすることなく、本番トラフィックをデバッグできる点です。
Sentry が新たなエラーを検知した瞬間や、インサイトに予期しないスパイクが表示されたとき、特定のトレース ID に絞り込み、各リクエストを特定し、コールスタックが崩れ始めた正確な場所を突き止めることが可能なのです。
分散トレーシングなら、以下のような状況でも簡単にデバッグできます。
- ソースコードへの読み書き権限がない場合
- デバッグ用のコードを追加でデプロイできない場合
- エラーメッセージがあいまいで不明瞭な場合
- 複数のマイクロサービスが原因の特定を難しくしている場合
本ガイドでは、ソースコードを見ることなく本番環境の問題を効果的にデバッグするために、Sentry のトレーシング機能を活用する方法をご紹介します。
手元でセットアップして進められる、サンプルのコース管理アプリを用意しました。
サンプルアプリケーションのセットアップ
このコース管理アプリケーションは、TypeScript で記述されており、React フレームワークである Next.js を採用しています。型安全性の確保には tRPC を、データの永続化には PostgreSQL を使用しています。ソースコードは GitHub で公開されています。
このガイドを読み進めるには、以下を実施してください。
- Sentry 上で新しい Next.js プロジェクトを作成し、データソース名(DSN)をメモしてください。プロジェクト設定から確認できます。
- アプリケーションを実行するシステムに、Node.js、npm、PostgreSQL がインストールされていることを確認してください。
最後に、コース管理アプリケーションをダウンロードし、ビルドして実行します。
- GitHub リポジトリを複製
- 依存関係をインストール
- 環境変数を設定するために env.example を .env にコピー
- 以下の変数を更新
– DATABASE_URL: PostgreSQL の接続文字列(デフォルトでも問題ありません)
– NEXTAUTH_SECRET: NextAuth.js 用のランダムな文字列
– NEXTAUTH_URL: アプリケーションの URL(開発環境では http://localhost:3000)
– NEXT_PUBLIC_SENTRY_DSN: 先ほど作成した Sentry プロジェクトの DSN - データベースを作成し、スキーマを設定してサンプルデータをインポート
- アプリケーションをビルド
- ビルド済みアプリケーションを実行
http://localhost:3000/sentry-example-page にアクセスしてボタンをクリックし、エラーを発生させることで、Sentry プロジェクトが正しくセットアップされているかテストできます。正常に動作していれば、プロジェクトのホームページに新しい Issue(以下の画像のような)がすぐに表示されるはずです。表示されない場合は、数秒待ってリフレッシュしてください。
Sentry のエラー例
エラーの再現
アプリケーションが起動したら、Sentry の Issue ストリームやプロジェクトホームにエラーが表示されるように、エラーを再現しましょう。
以下の手順でエラーを再現できます。
- http://localhost:3000 にアクセスすると、サインインページにリダイレクトされます。
- サンプルユーザーのいずれかでサインインします。
– メールアドレス: alice@example.com
– パスワード: password123 - 次に、ブラウザのコンソールを開くと、以下のようなエラー通知が表示されるはずです。
アプリケーションエラー
- Sentry の Issues ページに移動すると、同様の問題や関連イベントをまとめた Issue が間もなく表示されるはずです。Issue を開くと、次のような画面になります。
Sentry 上の Issue 表示例
エラーの調査
現時点では、手がかりは多くありません。
ホームページがレンダリングに失敗している理由が、読み込もうとしているコースの1つが見つからないことにあるのはわかりますが、それ以上の情報は得られません。開発モードでアプリケーションを実行していれば、スタックトレースを確認できますが、今回は本番環境で発生したエラーであり、コードは難読化されているため、読み解くことは困難です。
幸いなことに、Sentry はトレースビューページを提供しており、エラーを引き起こしたリクエストの流れを確認することが可能です。
Issue の Events セクションにある Trace ID リンクを探すと、以下のようにハイライトされています。
Trace ID
Trace ID リンクをクリックすると、以下のような トレースビューページが表示されます。
トレースビュー
トレースビューには、エラーを引き起こした初回ページ読み込みと、その際に発生した各リクエストが表示されます。この例では、ホームページの読み込み時に以下の API エンドポイントが呼び出されたことがわかります。
- /api/courses: コース情報の取得用エンドポイント
- /api/user/enrollments: ログインユーザーの受講状況取得用エンドポイント
- /api/user/me: ログインユーザーの詳細取得用エンドポイント
- /api/courses/[id]: ID を指定して単一のコースを取得するエンドポイント
エンドポイントをクリックすると、コース ID を含むリクエスト内容が表示されます。
コース ID
そのコース ID がデータベースに存在するかどうか、PostgreSQL のコマンドラインクライアント psql を使って確認しましょう。
新しいターミナルを開き、以下のコマンドを実行します。
次のような出力が表示されるはずです。
courses_db=# のプロンプトで、次のコマンドを入力して既存のテーブル一覧を表示します。
次のような出力が表示されるはずです。
次に、Course テーブルに cm85v87v50000abo0hfctxmg という コース ID が存在するかを、以下の SQL コマンドで確認します。
次のような出力が表示されるはずです。
これにより、cm85v87v50000abo0hfctxmg という コースID がデータベースに存在しないことが確認されました。
コードを一切見ずに、Sentry のトレースビューといくつかのデータベースクエリだけで、アプリケーションが存在しないコースを取得しようとしたことがエラーの原因であると特定できました。
エラーの修正
このエラーを修正するために、src/app/page.tsx にあるホームページ表示部分のコードを確認してみましょう。
25 行目から始まる try ブロックを見つけてください。
api.getCourse から始まり、ハードコードされた ID のコースを読み込もうとする問題のコード行がここにあります。
次に、72~74 行目の if ブロック内に、エラーを引き起こしているコードがあります。
この問題をどのように修正するかは、アプリケーションの要件によって異なります。
- 特集コースの機能が不要であれば、ホームページから完全に削除することが可能です。
- この機能を残す場合は、エラー発生時に graceful に処理するよう修正することが可能です。あるいは、データベースの ID をフロントエンドコードにハードコードするのではなく、特集コースの設定・取得に対応したより堅牢なアプリ内の仕組みを構築することもできます。
Next.js アプリケーションでエラーを特定するための Sentry トレーシング設定
バグを特定するうえで、 Sentry トレーシングビューが重要な役割を果たした例をご紹介します。
Sentry のインストールウィザード(npx @sentry/wizard@latest -i nextjs)を使用してアプリに Sentry を統合し、トレーシングを有効化したため、トレースビューページにアクセスできました。また、Turbopack を無効にして、Sentry がアプリケーションのフロントエンドで動作できるようにしました。
トレーシングは個々のリクエストの処理時間を記録するため、パフォーマンスのプロファイリングやモニタリングにも強力なツールです。これを示すために、コース管理アプリケーションの API 呼び出しの一部に人工的な遅延を加えました。その遅延は トレースビューページ上で明確に確認できます。
トレースビュー
トレーシングやセッションリプレイなどの高度な機能では、Sentry により多くのデータを送信する必要があり、パフォーマンスや帯域幅の使用に影響を与える可能性があります。そのため、アプリケーションの負荷や組織の許容範囲に応じて、サンプリングレートを適切に設定する必要があります。
Sentry トレーシングで可能なその他の機能
本ガイドでは、現実的ながらも比較的コンパクトで自己完結した例を使って、曖昧な Next.js の問題を Sentry のトレーシングでデバッグする基本を紹介しました。
しかし、Sentry 分散トレーシングは、問題のある1行のコードを見つけることにとどまりません。複数の API、非同期リクエスト、複雑なデータベース処理など、エラーがアプリ全体にどのように波及しているかを深く可視化できます。異なるコンテナのログを比較したり、本番環境で難読化されたバンドルを解析したりする必要はありません。トレースビューが手順を追って明示してくれます。
より大規模な Next.js アプリケーションや、マイクロサービスを扱うチームにとっては、今回の小さな例以上に大きな価値があります。デバッグのサイクルを短縮し、プロジェクトメンバー全員がより自立して問題を解決できるようになります。
曖昧で致命的なエラーのチケットが届いた瞬間、トレースを使用することで、原因を特定し、的確に修正することができます。推測ではなく、確かな証拠に基づいた対応が可能です。トレーシングを日常業務に組み込むことで、本番環境の問題に正面から取り組みながら、開発の本来の目的である堅牢な機能の構築とユーザー満足度の向上に集中できます。
Original Page: Investigating an ‘[Object] not found’ error in Next.js with Tracing in Sentry
IchizokuはSentryと提携し、日本でSentry製品の導入支援、テクニカルサポート、ベストプラクティスの共有を行なっています。Ichizokuが提供するSentryの日本語サイトについてはこちらをご覧ください。またご導入についての相談はこちらのフォームからお気軽にお問い合わせください。