コンテンツへスキップ

OpenTelemetry

可観測性は、Next.jsアプリの動作とパフォーマンスを理解し、最適化するために不可欠です。

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

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

このドキュメントでは、スパントレースエクスポーターといった用語を使用していますが、これらはすべてOpenTelemetry 可観測性プライマーで確認できます。

Next.jsはOpenTelemetryの計測を標準でサポートしており、これはNext.js自体がすでに計測されていることを意味します。OpenTelemetryを有効にすると、getStaticPropsのようなすべてのコードが役立つ属性を持つスパンに自動的にラップされます。

はじめに

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のドキュメントを参照してください。

知っておくと良いこと:

  • 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はEdge Runtimeと互換性がないため、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 { Resource } 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: new Resource({
    [ATTR_SERVICE_NAME]: 'next-app',
  }),
  spanProcessor: new SimpleSpanProcessor(new OTLPTraceExporter()),
})
sdk.start()

これを行うことは@vercel/otelを使用することと同等ですが、@vercel/otelによって公開されていない一部の機能を変更および拡張することが可能です。Edge Runtimeのサポートが必要な場合は、@vercel/otelを使用する必要があります。

計測のテスト

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

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

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

デプロイ

OpenTelemetry Collectorの使用

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

Vercelへのデプロイ

VercelではOpenTelemetryが標準で動作することを確認しました。

プロジェクトを可観測性プロバイダーに接続するには、Vercelドキュメントに従ってください。

セルフホスティング

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

これを行うには、コレクターのセットアップと、Next.jsアプリからデータを受信するための設定を順を追って説明しているOpenTelemetry Collector入門ガイドに従ってください。

コレクターが稼働したら、それぞれのデプロイガイドに従って、選択したプラットフォームに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
    • これは、App Routerで使用される内部値です。
    • これは、特殊なファイル(page.tslayout.tsloading.tsなど)へのルートと考えることができます。
    • next.routeと組み合わせた場合にのみ一意の識別子として使用できます。なぜなら、/layout/(groupA)/layout.ts/(groupB)/layout.tsの両方を識別するために使用できるためです。

[http.method] [next.route]

  • next.span_type: BaseServer.handleRequest

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

属性

ルートのレンダリング (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

このスパンは、コードで実行されるフェッチリクエストを表します。

属性

このスパンは、環境でNEXT_OTEL_FETCH_DISABLED=1を設定することでオフにできます。これは、カスタムのフェッチ計測ライブラリを使用したい場合に便利です。

APIルートの実行 (app) [next.route]

  • next.span_type: AppRouteRouteHandlers.runHandler

このスパンは、App RouterでのAPIルートハンドラの実行を表します。

属性

  • 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

ルートのレンダリング (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.

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