Next.jsアプリケーションをモニターする推奨される方法は、エージェントの組み込みのNext.js計装ではなく、Node.jsエージェントのハイブリッドエージェント機能とともにNext.jsによって発行されるネイティブのOpenTelemetryスパンに依存することです。このページでは、ハイブリッドエージェントを有効にする方法を説明し、サンプルアプリケーションを紹介し、Browserエージェントの挿入やcloudプロバイダーへのデプロイに関するよくある質問について説明します。
重要
ネイティブのNext.js OpenTelemetryサポートには、Node.jsエージェントバージョン14.1.0以降が必要です。ハイブリッドエージェントはNode.jsランタイムのみをインストゥルメントします。Next.jsエッジランタイムはサポートされていないため、NEXT_RUNTIMEがnodejsでない限り、以下のregister()の例は早期に終了します。
Node.jsエージェントは、2022年以降@newrelic/nextを通じてNext.js計装を備えており、その計装は12.0.0でエージェントにバンドルされました。しかし、それは限定的であり、Vercel、AWS Amplify、Netlify、またはAzure Static Web Appsのようなcloudプロバイダーにデプロイする場合には機能しませんでした。ハイブリッドエージェントの導入により、Node.jsエージェントはOpenTelemetryスパンをインターセプトし、New Relicエクスペリエンスを推進するテレメトリーを合成できるようになりました。ネイティブのNext.js OpenTelemetry計装は14.1.0で追加されました。
ハイブリッドエージェントを有効にする
ハイブリッドエージェントを有効にし、Next.jsと競合するエージェントインストゥルメンテーションを無効にするには、newrelic.jsで以下の設定を行います:
'use strict'
exports.config = { app_name: ['Your application name'], license_key: 'your-license-key', opentelemetry: { enabled: true }, instrumentation: { http: { enabled: false }, next: { enabled: false }, undici: { enabled: false } }}ヒント
ネイティブのfetch呼び出しを行う場合は、上記のようにundiciの計装を無効にする必要があります。Next.jsはfetchをラップして独自のクライアントスパンを作成するため、undiciを有効にしたままにすると、トレース内に重複したクライアントスパンが生成されます。
環境変数を使用する場合:
NEW_RELIC_LICENSE_KEY=<your-license-key>NEW_RELIC_APP_NAME=<your-application-name>NEW_RELIC_OPENTELEMETRY_ENABLED=trueNEW_RELIC_INSTRUMENTATION_NEXT_ENABLED=falseNEW_RELIC_INSTRUMENTATION_HTTP_ENABLED=falseNEW_RELIC_INSTRUMENTATION_UNDICI_ENABLED=falseまた、アプリケーションの他の部分よりも前にエージェントをロードするために、instrumentation.jsファイル(またはTypeScriptの場合はinstrumentation.ts)を追加する必要があります:
async function loadNewRelicAgent() { const { default: newrelic } = await import('newrelic') const agent = newrelic?.agent if (!agent || agent.collector?.isConnected?.()) { return }
await new Promise((resolve) => { const done = () => { clearTimeout(timer) agent.removeListener('started', done) agent.removeListener('errored', done) resolve() } const timer = setTimeout(done, 8000) agent.once('started', done) agent.once('errored', done) })}
export async function register() { // The agent only instruments the Node.js runtime, not the edge runtime. if (process.env.NEXT_RUNTIME !== 'nodejs') { return }
await loadNewRelicAgent()}この設定のより完全な例については、Next.js App Routerのサンプルアプリケーションを確認してください。
Next.js における計装 Vercel
Vercelへのデプロイにより、静的ページと動的ページが異なる環境に分割されます。.envおよびnewrelic.jsに依存してエージェント設定をロードする代わりに、VercelコンソールのEnvironment Variablesで以下の環境変数を定義します:
NEW_RELIC_LICENSE_KEY=<your-license-key>NEW_RELIC_APP_NAME=<your-application-name>NEW_RELIC_OPENTELEMETRY_ENABLED=trueNEW_RELIC_INSTRUMENTATION_NEXT_ENABLED=falseNEW_RELIC_INSTRUMENTATION_HTTP_ENABLED=falseNEW_RELIC_INSTRUMENTATION_UNDICI_ENABLED=false上記で説明したinstrumentation.jsファイルは引き続き必要です;Vercelでは設定のソースのみが変更されます。
この設定のより完全な例については、Next.js App Routerのサンプルアプリケーションを確認してください。
Browserエージェントを挿入する
Next.jsはフルスタックフレームワークであるため、ほとんどの顧客はクライアントとサーバーの両方でオブザーバビリティを求めています。以下の例は、New Relic Browserエージェントをすべてのページに挿入する方法を示しています。
app/内のルートレイアウトファイルを編集し、次を追加します:
import Script from 'next/script';
async function loadNewRelicAgent() { const { default: newrelic } = await import('newrelic') const agent = newrelic?.agent if (!agent || agent.collector?.isConnected?.()) { return newrelic }
await new Promise((resolve) => { const done = () => { clearTimeout(timer) agent.removeListener('started', done) agent.removeListener('errored', done) resolve() } const timer = setTimeout(done, 8000) agent.once('started', done) agent.once('errored', done) })
return newrelic}
export default async function RootLayout({ children,}){ // Wait for the agent to connect before requesting the browser timing header. const newrelic = await loadNewRelicAgent() const browserTimingHeader = newrelic.getBrowserTimingHeader({ hasToRemoveScriptWrapper: true, allowTransactionlessInjection: true, })
return ( <html lang="en"> <body className="min-h-full flex flex-col">{children}</body> <Script // Inline scripts require an id. // See https://nextjs.org/docs/app/building-your-application/optimizing/scripts#inline-scripts id='nr-browser-agent' // "beforeInteractive" loads the script before the page becomes interactive. strategy='beforeInteractive' // The script body is the browser timing header generated above. Because // `hasToRemoveScriptWrapper` is true, the header is raw JavaScript with no // surrounding <script> tag, so we inject it with `dangerouslySetInnerHTML`. dangerouslySetInnerHTML={{ __html: browserTimingHeader }} /> </html> );}この設定のより完全な例については、Next.js App Routerのサンプルアプリケーションを確認してください。