メインコンテンツまでスキップ

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

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

your-project/instrumentation.ts
import { registerOTel } from '@vercel/otel'

export function register() {
registerOTel({ serviceName: 'next-app' })
}

追加の設定オプションについては、@vercel/otelドキュメントを参照してください。

Good to know:

  • instrumentationファイルは、プロジェクトのルートに配置し、apppagesディレクトリの中に配置しないでください。srcフォルダを使っている場合は、src内にpagesappと一緒に配置します
  • pageExtensionsの設定オプションを使用してサフィックスを追加した場合、instrumentationのファイル名も一致させる必要があります
  • 使用できる基本的な例としてwith-opentelemetryを作成しました

OpenTelemetry の手動設定

@vercel/otelパッケージは多くの設定オプションを提供しており、一般的なユースケースのほとんどに対応しています。ただし、それでは不足する場合、OpenTelemetry を手動で設定できます。

まず、OpenTelemetryパッケージをインストールする必要があります:

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はedge runtimeと互換性がないため、process.env.NEXT_RUNTIME === 'nodejs'のときにのみインポートするように注意してください。instrumentation.node.tsという新しいファイルを作成し、nodeを使用するときにのみ条件付きでインポートすることをお勧めします:

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としてラベル付けされたrootサーバーのspanが表示されるはずです。その特定のトレースからの他のすべてのspanは、その下にネストされます。

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

デプロイ

OpenTelemetry Collectorの使用

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

Vercelでのデプロイ

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

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

セルフホスティング

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

これを行うには、OpenTelemetry Collector開始ガイドに従って、コレクタの設定とNext.jsアプリからデータを受信するように設定します。

コレクタが稼働したら、それぞれのデプロイメントガイドに従ってNext.jsアプリを任意のプラットフォームにデプロイします。

カスタムエクスポーター

OpenTelemetry Collectorは不要です。@vercel/otelまたは手動のOpenTelemetry設定を使用してカスタムOpenTelemetryエクスポーターを使用できます。

カスタムSpans

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

Terminal
npm install @opentelemetry/api

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

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のデフォルトのSpans

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

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など)
    • /layout/(groupA)/layout.ts/(groupB)/layout.tsの両方を識別するために使用できるため、next.routeとペアにしなければ一意の識別子として使用することはできません

[http.method] [next.route]

  • next.span_type: BaseServer.handleRequest

このspanは、Next.jsアプリケーションへの各リクエストのroot 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は、コード内で実行されたフェッチリクエストを表します。

属性:

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

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は、レスポンスで最初のバイトが送信された時間を表します。