Next.jsアプリにOpenTelemetryを実装する方法
可観測性は、Next.jsアプリの動作とパフォーマンスを理解し最適化するために重要です。
アプリケーションがより複雑になるにつれて、発生する可能性のある問題を特定して診断することがますます困難になります。ロギングとメトリクスなどの可観測性ツールを活用することで、開発者はアプリケーションの動作について洞察を得ることができ、最適化の領域を特定できます。可観測性があれば、開発者は問題が大きな問題になる前に主体的に対応でき、より優れたユーザー体験を提供できます。したがって、パフォーマンスを向上させ、リソースを最適化し、ユーザー体験を向上させるために、Next.jsアプリケーションで可観測性を使用することが強く推奨されます。
アプリをインストルメントするためにOpenTelemetryを使用することをお勧めします。 これはプラットフォーム非依存の方法でアプリをインストルメントでき、コードを変更することなく可観測性プロバイダーを変更できます。 OpenTelemetryとその動作方法の詳細については、OpenTelemetryの公式ドキュメントをお読みください。
このドキュメントでは、Span、Trace、_Exporter_などの用語を使用しており、これらはすべてOpenTelemetry Observability Primerに記載されています。
Next.jsはOpenTelemetryインストルメンテーションをそのままサポートしており、Next.js自体は既にインストルメント済みです。
OpenTelemetryを有効にすると、getStaticPropsのようなすべてのコードが自動的に有用な属性を持つ_spans_でラップされます。
はじめに
OpenTelemetryは拡張可能ですが、正しく設定するには非常に冗長になる可能性があります。
そのため、迅速に始めるのに役立つ@vercel/otelパッケージを用意しました。
@vercel/otelを使用する
まず、以下のパッケージをインストールします。
npm install @vercel/otel @opentelemetry/sdk-logs @opentelemetry/api-logs @opentelemetry/instrumentation次に、プロジェクトのルートディレクトリに(またはsrcフォルダを使用している場合はそれ以下に)カスタムinstrumentation.ts(または.js)ファイルを作成します。
import { registerOTel } from '@vercel/otel'
export function register() {
registerOTel({ serviceName: 'next-app' })
}詳細な設定オプションについては、@vercel/otelドキュメントを参照してください。
補足:
instrumentationファイルはプロジェクトのルートに配置し、appまたはpagesディレクトリ内には配置しないでください。srcフォルダを使用している場合は、pagesとappの横のsrc内にファイルを配置してください。pageExtensions設定オプションを使用して接尾辞を追加する場合は、instrumentationファイル名も同様に更新する必要があります。- 使用できる基本的なwith-opentelemetryの例を作成しました。
OpenTelemetryの手動設定
@vercel/otelパッケージは多くの設定オプションを提供し、ほとんどの一般的なユースケースに対応します。しかし、ニーズに合わない場合は、OpenTelemetryを手動で設定できます。
まず、OpenTelemetryパッケージをインストールする必要があります。
npm install @opentelemetry/sdk-node @opentelemetry/resources @opentelemetry/semantic-conventions @opentelemetry/sdk-trace-node @opentelemetry/exporter-trace-otlp-httpこれで、instrumentation.tsでNodeSDKを初期化できます。
@vercel/otelとは異なり、NodeSDKはedgeランタイムと互換性がないため、process.env.NEXT_RUNTIME === 'nodejs'の場合にのみそれらをインポートしていることを確認する必要があります。新しいinstrumentation.node.tsファイルを作成し、nodeを使用する場合にのみ条件付きでインポートすることをお勧めします。
export async function register() {
if (process.env.NEXT_RUNTIME === 'nodejs') {
await import('./instrumentation.node.ts')
}
}import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'
import { resourceFromAttributes } from '@opentelemetry/resources'
import { NodeSDK } from '@opentelemetry/sdk-node'
import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-node'
import { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions'
const sdk = new NodeSDK({
resource: resourceFromAttributes({
[ATTR_SERVICE_NAME]: 'next-app',
}),
spanProcessor: new SimpleSpanProcessor(new OTLPTraceExporter()),
})
sdk.start()これは@vercel/otelを使用するのと同等ですが、@vercel/otelで公開されていない機能を変更および拡張することが可能です。edgeランタイムサポートが必要な場合は、@vercel/otelを使用する必要があります。
インストルメンテーションのテスト
OpenTelemetryトレースをローカルでテストするには、互換性のあるバックエンドを備えたOpenTelemetryコレクターが必要です。 OpenTelemetry開発環境の使用をお勧めします。
すべてが正常に機能していれば、GET /requested/pathnameというラベルが付いたルートサーバースパンを表示できるはずです。
その特定のトレース内の他のすべてのスパンはその下にネストされます。
Next.jsはデフォルトで発行されるより多くのスパンをトレースします。
さらに多くのスパンを見るには、NEXT_OTEL_VERBOSE=1を設定する必要があります。
デプロイ
OpenTelemetry Collectorを使用する
OpenTelemetry Collectorでデプロイする場合は、@vercel/otelを使用できます。
Vercelでもセルフホストでもどちらでも動作します。
Vercelへのデプロイ
OpenTelemetryがVercelで標準で動作することを確認しました。
Vercelドキュメントに従い、プロジェクトを可観測性プロバイダーに接続してください。
セルフホスティング
他のプラットフォームへのデプロイも簡単です。Next.jsアプリからテレメトリデータを受け取って処理するための独自のOpenTelemetry Collectorを起動する必要があります。
これを行うには、OpenTelemetry Collector Getting Started guideに従ってください。このガイドでは、コレクターをセットアップし、Next.jsアプリからデータを受け取るように設定する手順を説明します。
コレクターが起動して実行されたら、各プラットフォームのデプロイガイドに従い、選択したプラットフォームにNext.jsアプリをデプロイできます。
カスタムエクスポーター
OpenTelemetry Collectorは必須ではありません。@vercel/otelまたはOpenTelemetry手動設定でカスタムOpenTelemetryエクスポーターを使用できます。
カスタムスパン
OpenTelemetry APIを使用してカスタムスパンを追加できます。
npm install @opentelemetry/api次の例は、GitHubスターをフェッチし、フェッチリクエストの結果を追跡するためにカスタムfetchGithubStarsスパンを追加する関数を示しています。
import { trace } from '@opentelemetry/api'
export async function fetchGithubStars() {
return await trace
.getTracer('nextjs-example')
.startActiveSpan('fetchGithubStars', async (span) => {
try {
return await getValue()
} finally {
span.end()
}
})
}register関数は新しい環境でコードが実行される前に実行されます。
新しいスパンの作成を開始でき、エクスポートされたトレースに正しく追加される必要があります。
Next.jsのデフォルトスパン
Next.jsはアプリケーションのパフォーマンスについて有用な洞察を提供するために、複数のスパンを自動的にインストルメントします。
スパンの属性はOpenTelemetryセマンティック規約に従います。また、next名前空間の下にカスタム属性も追加します。
next.span_name- スパン名を複製しますnext.span_type- 各スパンタイプには一意の識別子がありますnext.route- リクエストのルートパターン(例:/[param]/user)。next.rsc(true/false) - リクエストがプリフェッチなどのRSCリクエストであるかどうか。next.page- これはアプリRouterで使用される内部値です。
- これは特別なファイルへのルート(
page.ts、layout.ts、loading.tsなど)と考えることができます /(groupA)/layout.tsと/(groupB)/layout.tsの両方を識別するために/layoutを使用できるため、next.routeと組み合わせた場合にのみ一意の識別子として使用できます
[http.method] [next.route]
next.span_type:BaseServer.handleRequest
このスパンはNext.jsアプリケーションへの各受信リクエストのルートスパンを表します。リクエストのHTTPメソッド、ルート、ターゲット、ステータスコードを追跡します。
属性:
- 共通HTTP属性
http.methodhttp.status_code
- サーバーHTTP属性
http.routehttp.target
next.span_namenext.span_typenext.route
render route (app) [next.route]
next.span_type:AppRender.getBodyResult
このスパンはアプリRouterでのルートのレンダリングプロセスを表します。
属性:
next.span_namenext.span_typenext.route
fetch [http.method] [http.url]
next.span_type:AppRender.fetch
このスパンはコードで実行されたフェッチリクエストを表します。
属性:
- 共通HTTP属性
http.method
- クライアントHTTP属性
http.urlnet.peer.namenet.peer.port(指定されている場合のみ)
next.span_namenext.span_type
このスパンは、環境でNEXT_OTEL_FETCH_DISABLED=1を設定することでオフにできます。カスタムフェッチインストルメンテーションライブラリを使用する場合に便利です。
executing api route (app) [next.route]
next.span_type:AppRouteRouteHandlers.runHandler
このスパンはアプリRouterでのAPIルートハンドラーの実行を表します。
属性:
next.span_namenext.span_typenext.route
getServerSideProps [next.route]
next.span_type:Render.getServerSideProps
このスパンは特定のルートのgetServerSidePropsの実行を表します。
属性:
next.span_namenext.span_typenext.route
getStaticProps [next.route]
next.span_type:Render.getStaticProps
このスパンは特定のルートのgetStaticPropsの実行を表します。
属性:
next.span_namenext.span_typenext.route
render route (pages) [next.route]
next.span_type:Render.renderDocument
このスパンは特定のルートのドキュメントのレンダリングプロセスを表します。
属性:
next.span_namenext.span_typenext.route
generateMetadata [next.page]
next.span_type:ResolveMetadata.generateMetadata
このスパンは特定のページのメタデータ生成プロセスを表します(1つのルートには複数のこれらのスパンを含めることができます)。
属性:
next.span_namenext.span_typenext.page
resolve page components
next.span_type:NextNodeServer.findPageComponents
このスパンは特定のページのページコンポーネントの解決プロセスを表します。
属性:
next.span_namenext.span_typenext.route
resolve segment modules
next.span_type:NextNodeServer.getLayoutOrPageModule
このスパンはレイアウトまたはページのコードモジュールの読み込みを表します。
属性:
next.span_namenext.span_typenext.segment
start response
next.span_type:NextNodeServer.startResponse
このゼロ長スパンは、レスポンスの最初のバイトが送信された時刻を表します。