コンテンツにスキップ
App RouterGuidesOpenTelemetry

OpenTelemetry を使用したインストルメンテーションの設定方法

オブザーバビリティは、Next.js アプリケーションの動作とパフォーマンスを理解し、最適化するために不可欠です。

アプリケーションが複雑になるにつれて、発生する可能性のある問題を特定し、診断することがますます困難になります。ロギングやメトリクスなどのオブザーバビリティツールを活用することで、開発者はアプリケーションの動作に関する洞察を得て、最適化の領域を特定できます。オブザーバビリティにより、開発者は問題を重大な問題になる前にプロアクティブに対処し、より良いユーザーエクスペリエンスを提供できます。したがって、パフォーマンスを向上させ、リソースを最適化し、ユーザーエクスペリエンスを向上させるために、Next.js アプリケーションでオブザーバビリティを使用することを強くお勧めします。

アプリのインストルメンテーションには OpenTelemetry の使用をお勧めします。これは、コードを変更せずにオブザーバビリティプロバイダーを変更できる、プラットフォームに依存しないアプリのインストルメンテーション方法です。OpenTelemetry とその仕組みの詳細については、公式 OpenTelemetry ドキュメント を参照してください。

このドキュメントでは、SpanTraceExporter などの用語がドキュメント全体で使用されています。これらの用語はすべて、OpenTelemetry Observability Primer で確認できます。

Next.js は OpenTelemetry のインストルメンテーションを標準でサポートしており、Next.js 自体にインストルメンテーションが施されています。

はじめに

OpenTelemetry は拡張可能ですが、適切に設定するにはかなりの手間がかかります。そのため、@vercel/otel というパッケージを用意し、迅速な開始を支援します。

@vercel/otel の使用

開始するには、次のパッケージをインストールしてください

ターミナル
npm install @vercel/otel @opentelemetry/sdk-logs @opentelemetry/api-logs @opentelemetry/instrumentation

次に、プロジェクトのルートディレクトリ(または、使用している場合は src フォルダ内)にカスタム instrumentation.ts(または .js)ファイルを作成します。

your-project/instrumentation.ts
import { registerOTel } from '@vercel/otel'
 
export function register() {
  registerOTel({ serviceName: 'next-app' })
}

@vercel/otel の追加設定オプションについては、@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.tsNodeSDK を初期化します。@vercel/otel とは異なり、NodeSDK はエッジランタイムと互換性がありません。そのため、process.env.NEXT_RUNTIME === 'nodejs' の場合にのみインポートしていることを確認する必要があります。Node を使用する場合にのみ条件付きでインポートする新しいファイル instrumentation.node.ts を作成することをお勧めします。

instrumentation.ts
export async function register() {
  if (process.env.NEXT_RUNTIME === 'nodejs') {
    await import('./instrumentation.node.ts')
  }
}
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 で公開されていない一部の機能を変更および拡張できます。エッジランタイムのサポートが必要な場合は、@vercel/otel を使用する必要があります。

インストルメンテーションのテスト

ローカルで OpenTelemetry トレースをテストするには、互換性のあるバックエンドを持つ OpenTelemetry Collector が必要です。当社の OpenTelemetry 開発環境 の使用をお勧めします。

すべてうまく機能すれば、GET /requested/pathname というラベルのルートサーバー Span が表示されるはずです。その特定のトレースからの他のすべての Span は、その下にネストされます。

Next.js は、デフォルトで発行される Span よりも多くの Span を自動的にインストルメントします。より多くの Span を表示するには、NEXT_OTEL_VERBOSE=1 を設定する必要があります。

デプロイ

OpenTelemetry Collector の使用

OpenTelemetry Collector を使用してデプロイする場合、@vercel/otel を使用できます。これは、Vercel 上でもセルフホストでも機能します。

Vercel へのデプロイ

Vercel では、OpenTelemetry がすぐに使用できるようにしました。

Vercel のドキュメントに従って、プロジェクトをお客様のオブザーバビリティプロバイダーに接続 してください。

セルフホスティング

他のプラットフォームへのデプロイも簡単です。Next.js アプリケーションからテレメトリデータを受信して処理するために、独自の OpenTelemetry Collector を起動する必要があります。

これを行うには、OpenTelemetry Collector の開始ガイド に従ってください。これにより、コレクターの設定と Next.js アプリケーションからのデータ受信の設定方法がわかります。

コレクターを起動したら、各プラットフォームのデプロイガイドに従って、Next.js アプリケーションを選択したプラットフォームにデプロイできます。

カスタム Exporter

OpenTelemetry Collector は必須ではありません。@vercel/otel または OpenTelemetry の手動設定 でカスタム OpenTelemetry Exporter を使用できます。

カスタム Span

OpenTelemetry API を使用してカスタム Span を追加できます。OpenTelemetry API

ターミナル
npm install @opentelemetry/api

次の例は、GitHub のスターを取得し、フェッチリクエストの結果を追跡するためにカスタム fetchGithubStars Span を追加する関数を示しています。

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 関数は、新しい環境でコードが実行される前に実行されます。新しい Span を作成すると、エクスポートされたトレースに正しく追加されます。

Next.js のデフォルト Span

Next.js は、アプリケーションのパフォーマンスに関する有用な洞察を提供するために、いくつかの Span を自動的にインストルメントします。

Span の属性は OpenTelemetry セマンティック規約 に従います。また、next 名前空間の下にいくつかのカスタム属性を追加します。

  • next.span_name - Span 名の重複
  • next.span_type - 各 Span タイプには一意の識別子があります。
  • next.route - リクエストのルートパターン(例: /[param]/user)。
  • next.rsc (true/false) - リクエストが RSC リクエスト(プリフェッチなど)であるかどうか。
  • next.page
    • これは App Router が使用する内部値です。
    • 特殊なファイル(page.tslayout.tsloading.ts など)へのルートとして考えることができます。
    • next.route と組み合わせてのみ一意の識別子として使用できます。なぜなら、/layout/(groupA)/layout.ts/(groupB)/layout.ts の両方を識別するために使用できるためです。

[http.method] [next.route]

  • next.span_type: BaseServer.handleRequest

この Span は、Next.js アプリケーションへの各受信リクエストのルート Span を表します。リクエストの HTTP メソッド、ルート、ターゲット、およびステータスコードを追跡します。

属性

render route (app) [next.route]

  • next.span_type: AppRender.getBodyResult.

この Span は、App Router でのルートのレンダリングプロセスを表します。

属性

  • next.span_name
  • next.span_type
  • next.route

fetch [http.method] [http.url]

  • next.span_type: AppRender.fetch

この Span は、コードで実行された fetch リクエストを表します。

属性

この Span は、環境で NEXT_OTEL_FETCH_DISABLED=1 を設定することで無効にできます。これは、カスタム fetch インストルメンテーションライブラリを使用したい場合に便利です。

executing api route (app) [next.route]

  • next.span_type: AppRouteRouteHandlers.runHandler

この Span は、App Router での API Route Handler の実行を表します。

属性

  • next.span_name
  • next.span_type
  • next.route

getServerSideProps [next.route]

  • next.span_type: Render.getServerSideProps

この Span は、特定のルートの getServerSideProps の実行を表します。

属性

  • next.span_name
  • next.span_type
  • next.route

getStaticProps [next.route]

  • next.span_type: Render.getStaticProps

この Span は、特定のルートの getStaticProps の実行を表します。

属性

  • next.span_name
  • next.span_type
  • next.route

render route (pages) [next.route]

  • next.span_type: Render.renderDocument

この Span は、特定のルートのドキュメントのレンダリングプロセスを表します。

属性

  • next.span_name
  • next.span_type
  • next.route

generateMetadata [next.page]

  • next.span_type: ResolveMetadata.generateMetadata

この Span は、特定のページのメタデータ生成プロセスを表します(1 つのルートに複数のこのような Span がある場合があります)。

属性

  • next.span_name
  • next.span_type
  • next.page

resolve page components

  • next.span_type: NextNodeServer.findPageComponents

この Span は、特定のページのページコンポーネントの解決プロセスを表します。

属性

  • next.span_name
  • next.span_type
  • next.route

resolve segment modules

  • next.span_type: NextNodeServer.getLayoutOrPageModule

この Span は、レイアウトまたはページのコードモジュールの読み込みを表します。

属性

  • next.span_name
  • next.span_type
  • next.segment

start response

  • next.span_type: NextNodeServer.startResponse

このゼロ長 Span は、レスポンスの最初のバイトが送信された時点を表します。