Menu

OpenTelemetry

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

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

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

このドキュメントでは、SpanTraceExporter などの用語を使用しており、これらはすべて OpenTelemetry 可観測性プライマー で見つけることができます。

Next.js は OpenTelemetry 計装を最初から サポートしており、Next.js 自体をすでに計装しています。 OpenTelemetry を有効にすると、getStaticProps のようなすべてのコードを自動的に有用な属性を持つ spans でラップします。

はじめに

OpenTelemetry は拡張可能ですが、適切にセットアップするのはかなり冗長になる可能性があります。 そのため、迅速に始められるよう @vercel/otel パッケージを用意しました。

@vercel/otel の使用

開始するには、以下のパッケージをインストールします:

Terminal
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' })
}
your-project/instrumentation.js
import { registerOTel } from '@vercel/otel'
 
export function register() {
  registerOTel({ serviceName: 'next-app' })
}
```>
 
追加の設定オプションについては、[`@vercel/otel` ドキュメント](https://www.npmjs.com/package/@vercel/otel)を参照してください。
 
<AppOnly>
 
> **補足**:
>
> - `instrumentation` ファイルは、`app` または `pages` ディレクトリの外のプロジェクトのルートに配置する必要があります。`src` フォルダを使用している場合は、`pages` および `app` と同じ場所に配置します。
> - [`pageExtensions` 設定オプション](/docs/app/api-reference/next-config-js/pageExtensions)を使用してサフィックスを追加する場合、`instrumentation` ファイル名も一致するように更新する必要があります。
> - 使用できる基本的な [with-opentelemetry](https://github.com/vercel/next.js/tree/canary/examples/with-opentelemetry) の例を作成しました。
 
</AppOnly>
 
<PagesOnly>
 
> **補足**:
>
> - `instrumentation` ファイルは、`app` または `pages` ディレクトリの外のプロジェクトのルートに配置する必要があります。`src` フォルダを使用している場合は、`pages` および `app` と同じ場所に配置します。
> - [`pageExtensions` 設定オプション](/docs/pages/api-reference/next-config-js/pageExtensions)を使用してサフィックスを追加する場合、`instrumentation` ファイル名も一致するように更新する必要があります。
> - 使用できる基本的な [with-opentelemetry](https://github.com/vercel/next.js/tree/canary/examples/with-opentelemetry) の例を作成しました。
 
</PagesOnly>
 
### 手動 OpenTelemetry 設定
 
`@vercel/otel` パッケージは多くの設定オプションを提供し、ほとんどの一般的な使用例に対応しています。しかし、ニーズに合わない場合は、OpenTelemetry を手動で設定できます。
 
まず、OpenTelemetry パッケージをインストールする必要があります:
 
```bash filename="Terminal"
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.js
export async function register() {
  if (process.env.NEXT_RUNTIME === 'nodejs') {
    await import('./instrumentation.node.js')
  }
}
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()
instrumentation.node.js
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 では公開されていない一部の機能を変更および拡張することが可能です。エッジランタイムのサポートが必要な場合は、@vercel/otel を使用する必要があります。

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

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

正常に動作する場合、GET /requested/pathname というラベルの付いたルートサーバースパンが表示されるはずです。 その特定のトレースからの他のすべてのスパンは、その下にネストされます。

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

デプロイメント

OpenTelemetry コレクターの使用

OpenTelemetry コレクターを使用してデプロイする場合、@vercel/otel を使用できます。 Vercel と自己ホストの両方で動作します。

Vercel へのデプロイ

OpenTelemetry が Vercel ですぐに使えるように設定しました。

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

自己ホスティング

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

OpenTelemetry Collector の出発ガイドに従って、コレクターをセットアップし、Next.jsアプリからデータを受信するように設定します。

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

カスタムエクスポーター

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

カスタムスパン

OpenTelemetry APIsを使用してカスタムスパンを追加できます。

Terminal
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
    • これはアプリルーターで使用される内部値
    • 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メソッド、ルート、ターゲット、およびリクエストのステータスコードを追跡します。

属性:

render route (app) [next.route]

  • next.span_type: AppRender.getBodyResult

このスパンは、アプリルーターでのルートのレンダリングプロセスを表します。

属性:

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

fetch [http.method] [http.url]

  • next.span_type: AppRender.fetch

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

属性:

環境変数NEXT_OTEL_FETCH_DISABLED=1を設定することで、このスパンをオフにできます。カスタムfetch計測ライブラリを使用する場合に便利です。

executing api route (app) [next.route]

  • next.span_type: AppRouteRouteHandlers.runHandler

このスパンは、アプリルーターの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

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

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