Menu

OpenTelemetry

Observability ist entscheidend für das Verständnis und die Optimierung des Verhaltens und der Leistung Ihrer Next.js-App.

Mit zunehmender Komplexität von Anwendungen wird es immer schwieriger, Probleme zu identifizieren und zu diagnostizieren. Durch den Einsatz von Observability-Tools wie Logging und Metriken können Entwickler Einblicke in das Verhalten ihrer Anwendung gewinnen und Optimierungspotenziale identifizieren. Mit Observability können Entwickler Probleme proaktiv angehen, bevor sie zu größeren Problemen werden, und so ein besseres Nutzererlebnis bieten. Daher wird dringend empfohlen, Observability in Next.js-Anwendungen zu nutzen, um die Leistung zu verbessern, Ressourcen zu optimieren und das Nutzererlebnis zu verbessern.

Wir empfehlen die Verwendung von OpenTelemetry zur Instrumentierung Ihrer Apps. Es ist eine plattformunabhängige Methode zur App-Instrumentierung, die es Ihnen ermöglicht, Ihren Observability-Anbieter zu wechseln, ohne den Code zu ändern. Lesen Sie die Offiziellen OpenTelemetry-Dokumentation für weitere Informationen über OpenTelemetry und dessen Funktionsweise.

Diese Dokumentation verwendet Begriffe wie Span, Trace oder Exporter, die alle im OpenTelemetry Observability Primer zu finden sind.

Next.js unterstützt OpenTelemetry-Instrumentierung standardmäßig, was bedeutet, dass Next.js bereits selbst instrumentiert wurde. Wenn Sie OpenTelemetry aktivieren, werden wir automatisch den gesamten Code wie getStaticProps in Spans mit hilfreichen Attributen einwickeln.

Erste Schritte

OpenTelemetry ist erweiterbar, aber die richtige Einrichtung kann sehr komplex sein. Deshalb haben wir das Paket @vercel/otel vorbereitet, das Ihnen hilft, schnell zu starten.

Verwendung von @vercel/otel

Um zu beginnen, installieren Sie die folgenden Pakete:

Terminal
npm install @vercel/otel @opentelemetry/sdk-logs @opentelemetry/api-logs @opentelemetry/instrumentation

Erstellen Sie als Nächstes eine benutzerdefinierte instrumentation.ts (oder .js)-Datei im Stammverzeichnis des Projekts (oder im src-Ordner, falls verwendet):

your-project/instrumentation.ts
import { registerOTel } from '@vercel/otel'
 
export function register() {
  registerOTel({ serviceName: 'next-app' })
}
your-project/instrumentation.js
import { registerOTel } from '@vercel/otel'
 
export function register() {
  registerOTel({ serviceName: 'next-app' })
}

Weitere Konfigurationsoptionen finden Sie in der @vercel/otel-Dokumentation.

Hinweis:

  • Die instrumentation-Datei sollte sich im Stammverzeichnis des Projekts und nicht im app- oder pages-Verzeichnis befinden. Bei Verwendung des src-Ordners platzieren Sie die Datei innerhalb von src neben pages und app.
  • Wenn Sie die Konfigurationsoption pageExtensions verwenden, um ein Suffix hinzuzufügen, müssen Sie den Dateinamen von instrumentation entsprechend aktualisieren.
  • Wir haben ein einfaches with-opentelemetry-Beispiel erstellt, das Sie verwenden können.

Manuelle OpenTelemetry-Konfiguration

Das Paket @vercel/otel bietet viele Konfigurationsoptionen und sollte die meisten Anwendungsfälle abdecken. Wenn es Ihren Anforderungen jedoch nicht entspricht, können Sie OpenTelemetry manuell konfigurieren.

Zuerst müssen Sie OpenTelemetry-Pakete installieren:

Terminal
npm install @opentelemetry/sdk-node @opentelemetry/resources @opentelemetry/semantic-conventions @opentelemetry/sdk-trace-node @opentelemetry/exporter-trace-otlp-http

Nun können Sie NodeSDK in Ihrer instrumentation.ts initialisieren. Anders als @vercel/otel ist NodeSDK nicht mit Edge Runtime kompatibel, daher müssen Sie sicherstellen, dass Sie sie nur importieren, wenn process.env.NEXT_RUNTIME === 'nodejs'. Wir empfehlen, eine neue Datei instrumentation.node.ts zu erstellen, die Sie nur bei Verwendung von Node importieren:

instrumentation.ts
export async function register() {
  if (process.env.NEXT_RUNTIME === 'nodejs') {
    await import('./instrumentation.node.ts')
  }
}
instrumentation.js
export async function register() {
  if (process.env.NEXT_RUNTIME === 'nodejs') {
    await import('./instrumentation.node.js')
  }
}
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()
instrumentation.node.js
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()

Dies entspricht der Verwendung von @vercel/otel, macht es jedoch möglich, einige Funktionen zu modifizieren und zu erweitern, die von @vercel/otel nicht bereitgestellt werden. Wenn Edge Runtime-Unterstützung erforderlich ist, müssen Sie @vercel/otel verwenden.

Testen Ihrer Instrumentierung

Sie benötigen einen OpenTelemetry-Collector mit einem kompatiblen Backend, um OpenTelemetry-Traces lokal zu testen. Wir empfehlen unsere OpenTelemetry Dev-Umgebung.

Wenn alles funktioniert, sollten Sie den Root-Server-Span mit der Bezeichnung GET /requested/pathname sehen können. Alle anderen Spans aus dieser bestimmten Trace werden darunter verschachtelt sein.

Next.js verfolgt mehr Spans, als standardmäßig ausgegeben werden. Um mehr Spans zu sehen, müssen Sie NEXT_OTEL_VERBOSE=1 setzen.

Bereitstellung

Verwendung des OpenTelemetry Collectors

Bei der Bereitstellung mit OpenTelemetry Collector können Sie @vercel/otel verwenden. Es funktioniert sowohl auf Vercel als auch bei Selbst-Hosting.

Bereitstellung auf Vercel

Wir haben sichergestellt, dass OpenTelemetry standardmäßig auf Vercel funktioniert.

Folgen Sie der Vercel-Dokumentation, um Ihr Projekt mit einem Observability-Anbieter zu verbinden.

Selbst-Hosting

Die Bereitstellung auf anderen Plattformen ist ebenfalls unkompliziert. Sie müssen Ihren eigenen OpenTelemetry Collector einrichten, um die Telemetrie-Daten von Ihrer Next.js-App zu empfangen und zu verarbeiten.

Führen Sie dies aus, indem Sie der OpenTelemetry Collector Getting Started-Anleitung folgen, die Sie durch das Einrichten des Collectors und die Konfiguration zum Empfang von Daten aus Ihrer Next.js-App führt.

Sobald Ihr Collector läuft, können Sie Ihre Next.js-App auf der von Ihnen gewählten Plattform gemäß deren jeweiligen Bereitstellungsanleitungen bereitstellen.

Benutzerdefinierte Exporters

OpenTelemetry Collector ist nicht erforderlich. Sie können einen benutzerdefinierten OpenTelemetry-Exporter mit @vercel/otel oder manueller OpenTelemetry-Konfiguration verwenden.

Benutzerdefinierte Spans

Sie können einen benutzerdefinierten Span mit OpenTelemetry-APIs hinzufügen.

Terminal
npm install @opentelemetry/api

Das folgende Beispiel zeigt eine Funktion, die GitHub-Sterne abruft und einen benutzerdefinierten fetchGithubStars-Span hinzufügt, um das Ergebnis der Abrufanfrage zu verfolgen:

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()
      }
    })
}

Die register-Funktion wird vor der Ausführung Ihres Codes in einer neuen Umgebung ausgeführt. Sie können neue Spans erstellen, und sie sollten korrekt zur exportierten Trace hinzugefügt werden.

Standard-Spans in Next.js

Next.js instrumentiert automatisch mehrere Spans, um nützliche Einblicke in die Leistung Ihrer Anwendung zu geben.

Attribute auf Spans folgen den OpenTelemetry-Semantischen Konventionen. Wir fügen auch einige benutzerdefinierte Attribute unter dem next-Namespace hinzu:

  • next.span_name - dupliziert Span-Name
  • next.span_type - jeder Span-Typ hat einen eindeutigen Bezeichner
  • next.route - Das Routenmuster der Anfrage (z.B. /[param]/user).
  • next.rsc (true/false) - Ob es sich um eine RSC-Anfrage handelt, wie z.B. Prefetch.
  • next.page
    • Dies ist ein interner Wert, der von einem App-Router verwendet wird.
    • Sie können es sich als Route zu einer speziellen Datei vorstellen (wie page.ts, layout.ts, loading.ts und andere)
    • Es kann nur als eindeutiger Bezeichner verwendet werden, wenn es mit next.route kombiniert wird, da /layout sowohl /(groupA)/layout.ts als auch /(groupB)/layout.ts identifizieren kann

[http.method] [next.route]

  • next.span_type: BaseServer.handleRequest

Dieser Span repräsentiert den Root-Span für jede eingehende Anfrage an Ihre Next.js-Anwendung. Er verfolgt die HTTP-Methode, Route, Ziel und Statuscode der Anfrage.

Attribute:

Route rendern (app) [next.route]

  • next.span_type: AppRender.getBodyResult.

Dieser Span repräsentiert den Prozess des Renderns einer Route im App-Router.

Attribute:

  • next.span_name
  • next.span_type
  • next.route

Abruf [http.method] [http.url]

  • next.span_type: AppRender.fetch

Dieser Span repräsentiert die in Ihrem Code ausgeführte Abrufanfrage.

Attribute:

Dieser Span kann durch Setzen von NEXT_OTEL_FETCH_DISABLED=1 in Ihrer Umgebung deaktiviert werden. Dies ist nützlich, wenn Sie eine benutzerdefinierte Fetch-Instrumentierungsbibliothek verwenden möchten.

API-Route ausführen (app) [next.route]

  • next.span_type: AppRouteRouteHandlers.runHandler.

Dieser Span repräsentiert die Ausführung eines API-Route-Handlers im App-Router.

Attribute:

  • next.span_name
  • next.span_type
  • next.route

getServerSideProps [next.route]

  • next.span_type: Render.getServerSideProps.

Dieser Span repräsentiert die Ausführung von getServerSideProps für eine bestimmte Route.

Attribute:

  • next.span_name
  • next.span_type
  • next.route

getStaticProps [next.route]

  • next.span_type: Render.getStaticProps.

Dieser Span repräsentiert die Ausführung von getStaticProps für eine bestimmte Route.

Attribute:

  • next.span_name
  • next.span_type
  • next.route

Route rendern (pages) [next.route]

  • next.span_type: Render.renderDocument.

Dieser Span repräsentiert den Prozess des Renderns des Dokuments für eine bestimmte Route.

Attribute:

  • next.span_name
  • next.span_type
  • next.route

generateMetadata [next.page]

  • next.span_type: ResolveMetadata.generateMetadata.

Dieser Span repräsentiert den Prozess der Metadatengenerierung für eine bestimmte Seite (eine einzelne Route kann mehrere dieser Spans haben).

Attribute:

  • next.span_name
  • next.span_type
  • next.page

Seitenkomponenten auflösen

  • next.span_type: NextNodeServer.findPageComponents.

Dieser Span repräsentiert den Prozess des Auffindens von Seitenkomponenten für eine bestimmte Seite.

Attribute:

  • next.span_name
  • next.span_type
  • next.route

Segmentmodule auflösen

  • next.span_type: NextNodeServer.getLayoutOrPageModule.

Dieser Span repräsentiert das Laden von Codemodules für ein Layout oder eine Seite.

Attribute:

  • next.span_name
  • next.span_type
  • next.segment

Antwort starten

  • next.span_type: NextNodeServer.startResponse.

Dieser Span mit Nulllänge repräsentiert den Zeitpunkt, an dem das erste Byte in der Antwort gesendet wurde.