OpenTelemetryを使用した計装の設定方法
オブザーバビリティ(可観測性)は、Next.jsアプリケーションの動作とパフォーマンスを理解し最適化するために重要です。
アプリケーションが複雑になるにつれ、発生する問題を特定・診断することが難しくなります。ロギングやメトリクスなどのオブザーバビリティツールを活用することで、開発者はアプリケーションの動作を把握し、最適化すべき領域を特定できます。オブザーバビリティにより、開発者は問題が重大化する前に先手を打って対処し、より良いユーザー体験を提供できます。そのため、Next.jsアプリケーションでオブザーバビリティを使用してパフォーマンスを向上させ、リソースを最適化し、ユーザー体験を向上させることを強く推奨します。
アプリの計装にはOpenTelemetryを使用することをお勧めします。 これはプラットフォームに依存しない計装方法で、コードを変更せずにオブザーバビリティプロバイダーを変更できます。 OpenTelemetryの詳細と動作原理については公式OpenTelemetryドキュメントを参照してください。
このドキュメントでは_Span_、Trace、_Exporter_などの用語を使用します。これらはすべてOpenTelemetry Observability Primerで説明されています。
Next.jsはOpenTelemetry計装をデフォルトでサポートしており、Next.js自体が既に計装されています。
はじめに
OpenTelemetryは拡張可能ですが、適切に設定するにはかなりの記述が必要です。
そのため、迅速に開始できるように@vercel/otel
パッケージを用意しました。
@vercel/otel
の使用
まず、以下のパッケージをインストールします:
次に、プロジェクトのルートディレクトリ(またはsrc
フォルダを使用している場合はその中)にカスタムinstrumentation.ts
(または.js
)ファイルを作成します:
追加の設定オプションについては@vercel/otel
ドキュメントを参照してください。
知っておくと良いこと:
instrumentation
ファイルはプロジェクトのルートに配置し、app
やpages
ディレクトリ内には配置しないでください。src
フォルダを使用している場合は、pages
やapp
と同階層のsrc
内に配置します。pageExtensions
設定オプションを使用してサフィックスを追加する場合、instrumentation
ファイル名もそれに合わせて更新する必要があります。- 基本的なwith-opentelemetryの例を用意していますので、参考にしてください。
手動でのOpenTelemetry設定
@vercel/otel
パッケージは多くの設定オプションを提供し、一般的なユースケースのほとんどに対応しています。しかし、ニーズに合わない場合は手動でOpenTelemetryを設定できます。
まず、OpenTelemetryパッケージをインストールします:
次に、instrumentation.ts
でNodeSDK
を初期化します。
@vercel/otel
とは異なり、NodeSDK
はエッジランタイムと互換性がないため、process.env.NEXT_RUNTIME === 'nodejs'
の場合のみインポートする必要があります。nodeを使用時にのみ条件付きでインポートする新しいファイルinstrumentation.node.ts
を作成することをお勧めします:
これは@vercel/otel
を使用するのと同等ですが、@vercel/otel
で公開されていない機能を変更・拡張することが可能です。エッジランタイムのサポートが必要な場合は、@vercel/otel
を使用する必要があります。
計装のテスト
OpenTelemetryトレースをローカルでテストするには、OpenTelemetryコレクターと互換性のあるバックエンドが必要です。 OpenTelemetry開発環境の使用をお勧めします。
すべてが正しく動作していれば、GET /requested/pathname
とラベル付けされたルートサーバースパンが表示されるはずです。
そのトレースの他のすべてのスパンは、その下にネストされます。
Next.jsはデフォルトで出力されるよりも多くのスパンをトレースします。
より多くのスパンを表示するには、NEXT_OTEL_VERBOSE=1
を設定する必要があります。
デプロイ
OpenTelemetryコレクターの使用
OpenTelemetryコレクターでデプロイする場合、@vercel/otel
を使用できます。
これはVercelでもセルフホスティングでも動作します。
Vercelへのデプロイ
Vercel上でOpenTelemetryがすぐに動作するようにしました。
プロジェクトをオブザーバビリティプロバイダーに接続するにはVercelドキュメントに従ってください。
セルフホスティング
他のプラットフォームへのデプロイも簡単です。Next.jsアプリからテレメトリーデータを受信して処理するために、独自のOpenTelemetryコレクターを起動する必要があります。
これを行うには、OpenTelemetryコレクター入門ガイドに従って、コレクターをセットアップし、Next.jsアプリからデータを受信するように設定してください。
コレクターが起動して実行されたら、選択したプラットフォームにNext.jsアプリをデプロイできます。それぞれのデプロイガイドに従ってください。
カスタムエクスポーター
OpenTelemetryコレクターは必須ではありません。@vercel/otel
または手動OpenTelemetry設定でカスタムOpenTelemetryエクスポーターを使用できます。
カスタムスパン
OpenTelemetry APIを使用してカスタムスパンを追加できます。
次の例は、GitHubのスター数を取得し、fetchリクエストの結果を追跡するためのfetchGithubStars
カスタムスパンを追加する関数を示しています:
register
関数は、新しい環境でコードが実行される前に実行されます。
新しいスパンを作成し始めると、それらは正しくエクスポートされたトレースに追加されるはずです。
Next.jsのデフォルトスパン
Next.jsは、アプリケーションのパフォーマンスに関する有用な洞察を提供するために、いくつかのスパンを自動的に計装します。
スパンの属性はOpenTelemetryセマンティック規約に従います。また、next
名前空間の下にいくつかのカスタム属性を追加しています:
next.span_name
- スパン名の複製next.span_type
- 各スパンタイプの一意の識別子next.route
- リクエストのルートパターン(例:/[param]/user
)next.rsc
(true/false) - リクエストがプレフェッチなどのRSCリクエストかどうかnext.page
- これはApp Routerで使用される内部値です
page.ts
、layout.ts
、loading.ts
などの特別なファイルへのルートと考えることができますnext.route
と組み合わせた場合にのみ一意の識別子として使用できます。なぜなら/layout
は/(groupA)/layout.ts
と/(groupB)/layout.ts
の両方を識別するために使用できるからです
[http.method] [next.route]
next.span_type
:BaseServer.handleRequest
このスパンは、Next.jsアプリケーションへの各着信リクエストのルートスパンを表します。リクエストのHTTPメソッド、ルート、ターゲット、およびステータスコードを追跡します。
属性:
- 共通HTTP属性
http.method
http.status_code
- サーバーHTTP属性
http.route
http.target
next.span_name
next.span_type
next.route
render route (app) [next.route]
next.span_type
:AppRender.getBodyResult
.
このスパンは、App Routerでのルートのレンダリングプロセスを表します。
属性:
next.span_name
next.span_type
next.route
fetch [http.method] [http.url]
next.span_type
:AppRender.fetch
.
このスパンは、コード内で実行されるfetchリクエストを表します。
属性:
- 共通HTTP属性
http.method
- クライアントHTTP属性
http.url
net.peer.name
net.peer.port
(指定されている場合のみ)
next.span_name
next.span_type
このスパンは、環境変数NEXT_OTEL_FETCH_DISABLED=1
を設定することで無効にできます。これはカスタムfetch計装ライブラリを使用したい場合に便利です。
executing api route (app) [next.route]
next.span_type
:AppRouteRouteHandlers.runHandler
.
このスパンは、App RouterでのAPI Route Handlerの実行を表します。
属性:
next.span_name
next.span_type
next.route
getServerSideProps [next.route]
next.span_type
:Render.getServerSideProps
.
このスパンは、特定のルートに対するgetServerSideProps
の実行を表します。
属性:
next.span_name
next.span_type
next.route
getStaticProps [next.route]
next.span_type
:Render.getStaticProps
.
このスパンは、特定のルートに対するgetStaticProps
の実行を表します。
属性:
next.span_name
next.span_type
next.route
render route (pages) [next.route]
next.span_type
:Render.renderDocument
.
このスパンは、特定のルートに対するドキュメントのレンダリングプロセスを表します。
属性:
next.span_name
next.span_type
next.route
generateMetadata [next.page]
next.span_type
:ResolveMetadata.generateMetadata
.
このスパンは、特定のページ(1つのルートに複数存在する可能性あり)のメタデータ生成プロセスを表します。
属性:
next.span_name
next.span_type
next.page
resolve page components
next.span_type
:NextNodeServer.findPageComponents
.
このスパンは、特定のページに対するページコンポーネントの解決プロセスを表します。
属性:
next.span_name
next.span_type
next.route
resolve segment modules
next.span_type
:NextNodeServer.getLayoutOrPageModule
.
このスパンは、レイアウトまたはページのコードモジュールの読み込みを表します。
属性:
next.span_name
next.span_type
next.segment
start response
next.span_type
:NextNodeServer.startResponse
.
このゼロ長スパンは、レスポンスで最初のバイトが送信された時間を表します。