La méthode recommandée pour monitorer une application Next.js est de s'appuyer sur les spans OpenTelemetry natifs émis par Next.js ainsi que sur la fonctionnalité d'agent hybride de l'agent Node.js, plutôt que sur l'instrumentation Next.js intégrée de l'agent. Cette page explique comment activer l'agent hybride, indique des exemples d'applications et aborde les questions courantes sur l'injection de l'agent de browser et sur la façon de déployer vers des fournisseurs cloud.
Important
La prise en charge native de Next.js OpenTelemetry nécessite la version 14.1.0 de l’agent Node.js ou plus tard. L’agent hybride instrumente uniquement le runtime Node.js ; le runtime edge Next.js n’est pas pris en charge, c’est pourquoi l’exemple register() ci-dessous se termine prématurément à moins que NEXT_RUNTIME ne soit nodejs.
L’agent Node.js dispose de l’instrumentation Next.js depuis 2022 via @newrelic/next, et cette instrumentation a été intégrée à l’agent dans la version 12.0.0. Cependant, elle était limitée et ne fonctionnait pas au moment de déployer sur des fournisseurs de cloud comme Vercel, AWS Amplify, Netlify ou Azure Static Web Apps. Avec l’introduction de l’ agent hybride, l’agent Node.js peut intercepter les spans OpenTelemetry et synthétiser la télémétrie qui alimente l’expérience New Relic. L’instrumentation native de Next.js OpenTelemetry a été ajoutée dans la version 14.1.0.
Activer l’agent hybride
Pour activer l'agent hybride et désactiver les instrumentations d'agent qui sont en conflit avec Next.js, définissez la configuration suivante dans 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 } }}Conseil
Si vous effectuez des appels fetch natifs, vous devez désactiver l'instrumentation undici comme indiqué ci-dessus. Next.js enveloppe fetch et crée ses propres spans clients, donc laisser undici activé produit des spans clients en double dans vos traces.
Si vous préférez utiliser des variables d’environnement :
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=falseVous devez également ajouter un fichier instrumentation.js (ou instrumentation.ts pour TypeScript) pour charger l'agent avant le reste de votre application :
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()}Consultez l'application d'exemple Next.js App Router pour un exemple plus complet de cette configuration.
Next.js instrumentation dans Vercel
Déployer vers Vercel sépare les pages statiques et dynamiques dans des environnements différents. Au lieu de vous appuyer sur .env et newrelic.js pour charger la configuration de l'agent, définissez les variables d'environnement suivantes dans la console Vercel sous 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=falseVous avez toujours besoin du fichier instrumentation.js décrit ci-dessus ; seule la source de la configuration change sur Vercel.
Consultez l'application d'exemple Next.js App Router pour un exemple plus complet de cette configuration.
Injecter l’agent de browser
Puisque Next.js est un framework full-stack, la plupart des clients souhaitent une observabilité à la fois sur le client et sur le serveur. L'exemple suivant montre comment injecter l'agent New Relic Browser dans chaque page.
Modifiez le fichier de mise en page racine dans app/ et ajoutez ce qui suit :
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> );}Consultez l'application d'exemple Next.js App Router pour un exemple plus complet de cette configuration.