OpenTelemetry
可観測性は、Next.js アプリケーションの動作とパフォーマンスを理解し、最適化するために不可欠です。
アプリケーションが複雑になるにつれて、発生する可能性のある問題を特定して診断することがますます困難になります。ロギングやメトリクスなどの可観測性ツールを活用することで、開発者はアプリケーションの動作に関する洞察を得て、最適化すべき領域を特定できます。可観測性により、開発者は大きな問題になる前に問題を事前に解決し、より良いユーザーエクスペリエンスを提供できます。したがって、パフォーマンスを向上させ、リソースを最適化し、ユーザーエクスペリエンスを強化するために、Next.js アプリケーションで可観測性を使用することを強くお勧めします。
アプリケーションのインストルメンテーションには、OpenTelemetry を使用することをお勧めします。これは、コードを変更することなく、可観測性プロバイダーを変更できる、プラットフォームに依存しないアプリケーションのインストルメンテーション方法です。OpenTelemetry とその仕組みの詳細については、OpenTelemetry の公式ドキュメントを参照してください。
このドキュメントでは、 Span、Trace、Exporter などの用語を使用していますが、これらはすべてOpenTelemetry Observability Primerに記載されています。
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
) ファイルを作成します。
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
はエッジランタイムと互換性がないため、process.env.NEXT_RUNTIME === 'nodejs'
の場合にのみインポートするようにする必要があります。ノードを使用する場合にのみ条件付きでインポートする新しいファイル instrumentation.node.ts
を作成することをお勧めします。
export async function register() {
if (process.env.NEXT_RUNTIME === 'nodejs') {
await import('./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
で公開されていない一部の機能を変更および拡張できます。エッジランタイムのサポートが必要な場合は、@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を立ち上げる必要があります。
これを行うには、OpenTelemetry Collectorの入門ガイドに従って、コレクターのセットアップと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
- これは、アプリルーターで使用される内部値です。
- これを、特別なファイル(
page.ts
、layout.ts
、loading.ts
など)へのルートとして考えることができます。 /layout
は、/(groupA)/layout.ts
と/(groupB)/layout.ts
の両方を識別するために使用できるため、next.route
と組み合わせた場合にのみ一意の識別子として使用できます。
[http.method] [next.route]
next.span_type
:BaseServer.handleRequest
このスパンは、Next.jsアプリケーションへの各着信リクエストのルートスパンを表します。リクエストのHTTPメソッド、ルート、ターゲット、およびステータスコードを追跡します。
属性
- 一般的なHTTP属性
http.method
http.status_code
- サーバー HTTP 属性
http.route
http.target
next.span_name
next.span_type
next.route
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リクエストを表します。
属性
- 一般的なHTTP属性
http.method
- クライアント HTTP 属性
http.url
net.peer.name
net.peer.port
(指定されている場合のみ)
next.span_name
next.span_type
このスパンは、環境変数で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
。
このスパンは、特定のページ(単一のルートでこれらのスパンが複数存在する可能性があります)のメタデータを生成する処理を表します。
属性
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
。
このゼロ長のスパは、レスポンスで最初のバイトが送信された時間を表します。
この情報は役に立ちましたか?