A maneira recomendada de monitorar um aplicativo Next.js é contar com os spans nativos do OpenTelemetry emitidos pelo Next.js em conjunto com o recurso de agente híbrido do agente Node.js, em vez da instrumentação Next.js integrada do agente. Esta página explica como habilitar o agente híbrido, aponta para aplicativos de exemplo e aborda perguntas comuns sobre como injetar o agente do browser e implantar em provedores de cloud.
Importante
O suporte nativo ao Next.js OpenTelemetry requer a versão 14.1.0 do agente Node.js ou posterior. Apenas o runtime Node.js é instrumentado pelo agente híbrido; o runtime de borda Next.js não é suportado, motivo pelo qual o exemplo register() abaixo é encerrado precocemente a menos que NEXT_RUNTIME seja nodejs.
O agente Node.js possui instrumentação do Next.js desde 2022 por meio do @newrelic/next, e essa instrumentação foi incluída no agente na versão 12.0.0. No entanto, era limitado e não funcionava ao implantar em provedores de cloud como Vercel, AWS Amplify, Netlify ou Azure Static Web Apps. Com a introdução do agente híbrido, o agente Node.js pode interceptar spans OpenTelemetry e sintetizar a telemetria que impulsiona a experiência do New Relic. A instrumentação nativa Next.js OpenTelemetry foi adicionada em 14.1.0.
Habilite o agente híbrido
Para habilitar o agente híbrido e desabilitar a instrumentação de agente que entra em conflito com Next.js, defina a seguinte configuração em 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 } }}Dica
Se você fizer chamadas nativas do fetch, deverá desabilitar a instrumentação do undici, conforme mostrado acima. O Next.js envolve o fetch e cria seus próprios spans de cliente, portanto, deixar o undici habilitado produz spans de cliente duplicados em seus traces.
Se você preferir usar variáveis de ambiente:
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=falseVocê também deve adicionar um arquivo instrumentation.js (ou instrumentation.ts para TypeScript) para carregar o agente antes do restante do seu aplicativo:
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()}Confira o aplicativo de exemplo Next.js App Router para ver um exemplo mais completo dessa configuração.
Next.js instrumentação em Vercel
Implantar no Vercel divide as páginas estáticas e dinâmicas em ambientes diferentes. Em vez de depender de .env e newrelic.js para carregar a configuração do agente, defina as seguintes variáveis de ambiente no console do Vercel em 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=falseVocê ainda precisa do arquivo instrumentation.js descrito acima; apenas a origem da configuração muda no Vercel.
Confira o aplicativo de exemplo Next.js App Router para ver um exemplo mais completo dessa configuração.
Injete o agente do browser
Como o Next.js é um framework full-stack, a maioria dos clientes deseja observabilidade tanto no cliente quanto no servidor. O exemplo a seguir mostra como injetar o agente do browser do New Relic em todas as páginas.
Edite o arquivo de layout raiz dentro de app/ e adicione o seguinte:
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> );}Confira o aplicativo de exemplo Next.js App Router para ver um exemplo mais completo dessa configuração.