OpenTelemetry
Bon à savoir : Cette fonctionnalité est expérimentale, vous devez l'activer explicitement en ajoutant
experimental.instrumentationHook = true;
dans votrenext.config.js
.
L'observabilité est cruciale pour comprendre et optimiser le comportement et les performances de votre application Next.js.
À mesure que les applications deviennent plus complexes, il devient de plus en plus difficile d'identifier et de diagnostiquer les problèmes qui peuvent survenir. En utilisant des outils d'observabilité, tels que la journalisation et les métriques, les développeurs peuvent obtenir des insights sur le comportement de leur application et identifier des zones d'optimisation. Avec l'observabilité, les développeurs peuvent résoudre les problèmes de manière proactive avant qu'ils ne deviennent majeurs et offrir une meilleure expérience utilisateur. Par conséquent, il est fortement recommandé d'utiliser l'observabilité dans vos applications Next.js pour améliorer les performances, optimiser les ressources et enrichir l'expérience utilisateur.
Nous recommandons d'utiliser OpenTelemetry pour instrumenter vos applications. C'est une manière agnostique de la plateforme d'instrumenter les applications qui vous permet de changer votre fournisseur d'observabilité sans modifier votre code. Consultez la documentation officielle d'OpenTelemetry pour plus d'informations sur OpenTelemetry et son fonctionnement.
Cette documentation utilise des termes comme Span, Trace ou Exporter tout au long de ce document, tous peuvent être trouvés dans le guide d'observabilité OpenTelemetry.
Next.js prend en charge l'instrumentation OpenTelemetry nativement, ce qui signifie que nous avons déjà instrumenté Next.js lui-même.
Lorsque vous activez OpenTelemetry, nous encapsulons automatiquement tout votre code comme getStaticProps
dans des spans avec des attributs utiles.
Bon à savoir : Nous ne prenons actuellement en charge les bindings OpenTelemetry que dans les fonctions serverless. Nous n'en fournissons aucun pour le code
edge
ou côté client.
Premiers pas
OpenTelemetry est extensible, mais sa configuration peut être assez verbeuse.
C'est pourquoi nous avons préparé un package @vercel/otel
qui vous aide à démarrer rapidement.
Il n'est pas extensible et vous devriez configurer OpenTelemetry manuellement si vous avez besoin de personnaliser votre configuration.
Utilisation de @vercel/otel
Pour commencer, vous devez installer @vercel/otel
:
npm install @vercel/otel
Ensuite, créez un fichier personnalisé instrumentation.ts
(ou .js
) dans le répertoire racine du projet (ou dans le dossier src
si vous en utilisez un) :
import { registerOTel } from '@vercel/otel'
export function register() {
registerOTel('next-app')
}
import { registerOTel } from '@vercel/otel'
export function register() {
registerOTel('next-app')
}
Bon à savoir
- Le fichier
instrumentation
doit être à la racine de votre projet et non dans les répertoiresapp
oupages
. Si vous utilisez le dossiersrc
, placez le fichier danssrc
à côté depages
etapp
.- Si vous utilisez l'option de configuration
pageExtensions
pour ajouter un suffixe, vous devrez également mettre à jour le nom du fichierinstrumentation
pour correspondre.- Nous avons créé un exemple basique with-opentelemetry que vous pouvez utiliser.
Configuration manuelle d'OpenTelemetry
Si notre wrapper @vercel/otel
ne répond pas à vos besoins, vous pouvez configurer OpenTelemetry manuellement.
Premièrement, vous devez installer les packages OpenTelemetry :
npm install @opentelemetry/sdk-node @opentelemetry/resources @opentelemetry/semantic-conventions @opentelemetry/sdk-trace-node @opentelemetry/exporter-trace-otlp-http
Maintenant, vous pouvez initialiser NodeSDK
dans votre instrumentation.ts
.
Les API OpenTelemetry ne sont pas compatibles avec le runtime edge, vous devez donc vous assurer de les importer uniquement lorsque process.env.NEXT_RUNTIME === 'nodejs'
. Nous recommandons de créer un nouveau fichier instrumentation.node.ts
que vous importez conditionnellement uniquement lors de l'utilisation de node :
export async function register() {
if (process.env.NEXT_RUNTIME === 'nodejs') {
await import('./instrumentation.node.ts')
}
}
export async function register() {
if (process.env.NEXT_RUNTIME === 'nodejs') {
await import('./instrumentation.node.js')
}
}
import { NodeSDK } from '@opentelemetry/sdk-node'
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'
import { Resource } from '@opentelemetry/resources'
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'
import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-node'
const sdk = new NodeSDK({
resource: new Resource({
[SemanticResourceAttributes.SERVICE_NAME]: 'next-app',
}),
spanProcessor: new SimpleSpanProcessor(new OTLPTraceExporter()),
})
sdk.start()
import { NodeSDK } from '@opentelemetry/sdk-node'
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'
import { Resource } from '@opentelemetry/resources'
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'
import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-node'
const sdk = new NodeSDK({
resource: new Resource({
[SemanticResourceAttributes.SERVICE_NAME]: 'next-app',
}),
spanProcessor: new SimpleSpanProcessor(new OTLPTraceExporter()),
})
sdk.start()
Faire cela est équivalent à utiliser @vercel/otel
, mais il est possible de le modifier et de l'étendre.
Par exemple, vous pourriez utiliser @opentelemetry/exporter-trace-otlp-grpc
au lieu de @opentelemetry/exporter-trace-otlp-http
ou vous pouvez spécifier plus d'attributs de ressource.
Tester votre instrumentation
Vous avez besoin d'un collecteur OpenTelemetry avec un backend compatible pour tester les traces OpenTelemetry localement. Nous recommandons d'utiliser notre environnement de développement OpenTelemetry.
Si tout fonctionne correctement, vous devriez pouvoir voir le span racine du serveur étiqueté comme GET /requested/pathname
.
Tous les autres spans de cette trace particulière seront imbriqués en dessous.
Next.js trace plus de spans que ceux émis par défaut.
Pour voir plus de spans, vous devez définir NEXT_OTEL_VERBOSE=1
.
Déploiement
Utilisation d'OpenTelemetry Collector
Lorsque vous déployez avec OpenTelemetry Collector, vous pouvez utiliser @vercel/otel
.
Il fonctionnera à la fois sur Vercel et en auto-hébergement.
Déploiement sur Vercel
Nous nous sommes assurés qu'OpenTelemetry fonctionne nativement sur Vercel.
Suivez la documentation Vercel pour connecter votre projet à un fournisseur d'observabilité.
Auto-hébergement
Le déploiement sur d'autres plateformes est également simple. Vous devrez déployer votre propre OpenTelemetry Collector pour recevoir et traiter les données de télémétrie de votre application Next.js.
Pour ce faire, suivez le guide de démarrage d'OpenTelemetry Collector, qui vous guidera dans la configuration du collecteur et son paramétrage pour recevoir les données de votre application Next.js.
Une fois que votre collecteur est opérationnel, vous pouvez déployer votre application Next.js sur la plateforme de votre choix en suivant leurs guides de déploiement respectifs.
Exporteurs personnalisés
Nous recommandons d'utiliser OpenTelemetry Collector. Si ce n'est pas possible sur votre plateforme, vous pouvez utiliser un exporteur OpenTelemetry personnalisé avec une configuration manuelle d'OpenTelemetry
Spans personnalisés
Vous pouvez ajouter un span personnalisé avec les API OpenTelemetry.
npm install @opentelemetry/api
L'exemple suivant montre une fonction qui récupère les stars GitHub et ajoute un span personnalisé fetchGithubStars
pour suivre le résultat de la requête fetch :
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()
}
})
}
La fonction register
s'exécutera avant votre code dans un nouvel environnement.
Vous pouvez commencer à créer de nouveaux spans, et ils devraient être correctement ajoutés à la trace exportée.
Spans par défaut dans Next.js
Next.js instrumente automatiquement plusieurs spans pour vous fournir des insights utiles sur les performances de votre application.
Les attributs des spans suivent les conventions sémantiques OpenTelemetry. Nous ajoutons également certains attributs personnalisés sous l'espace de noms next
:
next.span_name
- duplique le nom du spannext.span_type
- chaque type de span a un identifiant uniquenext.route
- Le motif de route de la requête (par exemple,/[param]/user
).next.page
- Il s'agit d'une valeur interne utilisée par le routeur app.
- Vous pouvez le considérer comme une route vers un fichier spécial (comme
page.ts
,layout.ts
,loading.ts
et autres) - Il peut être utilisé comme identifiant unique uniquement lorsqu'il est associé à
next.route
car/layout
peut être utilisé pour identifier à la fois/(groupA)/layout.ts
et/(groupB)/layout.ts
[http.method] [next.route]
next.span_type
:BaseServer.handleRequest
Ce span représente le span racine pour chaque requête entrante dans votre application Next.js. Il suit la méthode HTTP, la route, la cible et le code de statut de la requête.
Attributs :
- Attributs HTTP communs
http.method
http.status_code
- Attributs HTTP serveur
http.route
http.target
next.span_name
next.span_type
next.route
render route (app) [next.route]
next.span_type
:AppRender.getBodyResult
.
Ce span représente le processus de rendu d'une route dans le routeur app.
Attributs :
next.span_name
next.span_type
next.route
fetch [http.method] [http.url]
next.span_type
:AppRender.fetch
Ce span représente la requête fetch exécutée dans votre code.
Attributs :
- Attributs HTTP communs
http.method
- Attributs HTTP client
http.url
net.peer.name
net.peer.port
(uniquement si spécifié)
next.span_name
next.span_type
executing api route (app) [next.route]
next.span_type
:AppRouteRouteHandlers.runHandler
.
Ce span représente l'exécution d'un gestionnaire de route API dans le routeur app.
Attributs :
next.span_name
next.span_type
next.route
getServerSideProps [next.route]
next.span_type
:Render.getServerSideProps
.
Ce span représente l'exécution de getServerSideProps
pour une route spécifique.
Attributs :
next.span_name
next.span_type
next.route
getStaticProps [next.route]
next.span_type
:Render.getStaticProps
.
Ce span représente l'exécution de getStaticProps
pour une route spécifique.
Attributs :
next.span_name
next.span_type
next.route
render route (pages) [next.route]
next.span_type
:Render.renderDocument
.
Ce span représente le processus de rendu du document pour une route spécifique.
Attributs :
next.span_name
next.span_type
next.route
generateMetadata [next.page]
next.span_type
:ResolveMetadata.generateMetadata
.
Ce span représente le processus de génération de métadonnées pour une page spécifique (une seule route peut avoir plusieurs de ces spans).
Attributs :
next.span_name
next.span_type
next.page