Skip to main content

OpenTelemetry

很高兴知道:此功能是实验性的,你需要通过在 next.config.js 中提供 experimental.instrumentationHook = true; 来明确选择加入。

¥Good to know: This feature is experimental, you need to explicitly opt-in by providing experimental.instrumentationHook = true; in your next.config.js.

可观察性对于理解和优化 Next.js 应用的行为和性能至关重要。

¥Observability is crucial for understanding and optimizing the behavior and performance of your Next.js app.

随着应用变得越来越复杂,识别和诊断可能出现的问题变得越来越困难。通过利用日志记录和指标等可观察性工具,开发者可以深入了解应用的行为并确定需要优化的字段。借助可观察性,开发者可以在问题成为重大问题之前主动解决问题,并提供更好的用户体验。因此,强烈建议在 Next.js 应用中使用可观察性来提高性能、优化资源并增强用户体验。

¥As applications become more complex, it becomes increasingly difficult to identify and diagnose issues that may arise. By leveraging observability tools, such as logging and metrics, developers can gain insights into their application's behavior and identify areas for optimization. With observability, developers can proactively address issues before they become major problems and provide a better user experience. Therefore, it is highly recommended to use observability in your Next.js applications to improve performance, optimize resources, and enhance user experience.

我们建议使用 OpenTelemetry 来检测你的应用。这是一种与平台无关的应用检测方式,允许你在不更改代码的情况下更改可观察性提供程序。阅读 官方 OpenTelemetry 文档 了解有关 OpenTelemetry 及其工作原理的更多信息。

¥We recommend using OpenTelemetry for instrumenting your apps. It's a platform-agnostic way to instrument apps that allows you to change your observability provider without changing your code. Read Official OpenTelemetry docs for more information about OpenTelemetry and how it works.

本文档在整个文档中使用了 Span、Trace 或 Exporter 等术语,所有这些都可以在 OpenTelemetry 可观测性入门 中找到。

¥This documentation uses terms like Span, Trace or Exporter throughout this doc, all of which can be found in the OpenTelemetry Observability Primer.

Next.js 开箱即用地支持 OpenTelemetry 检测,这意味着我们已经检测了 Next.js 本身。当你启用 OpenTelemetry 时,我们将自动将你的所有代码(例如 getStaticProps)封装在具有有用属性的跨度中。

¥Next.js supports OpenTelemetry instrumentation out of the box, which means that we already instrumented Next.js itself. When you enable OpenTelemetry we will automatically wrap all your code like getStaticProps in spans with helpful attributes.

入门

¥Getting Started

OpenTelemetry 是可扩展的,但正确设置它可能会非常冗长。这就是为什么我们准备了 @vercel/otel 包来帮助你快速入门。

¥OpenTelemetry is extensible but setting it up properly can be quite verbose. That's why we prepared a package @vercel/otel that helps you get started quickly.

使用 @vercel/otel

¥Using @vercel/otel

首先,你必须安装 @vercel/otel

¥To get started, you must install @vercel/otel:

npm install @vercel/otel

接下来,在项目的根目录中创建一个自定义 instrumentation.ts(或 .js)文件(如果使用的话,则在 src 文件夹内):

¥Next, create a custom instrumentation.ts (or .js) file in the root directory of the project (or inside src folder if using one):

import { registerOTel } from '@vercel/otel'

export function register() {
registerOTel({ serviceName: 'next-app' })
}
import { registerOTel } from '@vercel/otel'

export function register() {
registerOTel({ serviceName: 'next-app' })
}

有关其他配置选项,请参阅 @vercel/otel 文档

¥See the @vercel/otel documentation for additional configuration options.

很高兴知道

¥Good to know

  • instrumentation 文件应该位于项目的根目录中,而不是位于 apppages 目录中。如果你使用的是 src 文件夹,请将文件与 pagesapp 一起放入 src 中。

    ¥The instrumentation file should be in the root of your project and not inside the app or pages directory. If you're using the src folder, then place the file inside src alongside pages and app.

  • 如果你使用 pageExtensions 配置选项 添加后缀,你还需要更新 instrumentation 文件名以匹配。

    ¥If you use the pageExtensions config option to add a suffix, you will also need to update the instrumentation filename to match.

  • 我们创建了一个你可以使用的基本 with-opentelemetry 示例。

    ¥We have created a basic with-opentelemetry example that you can use.

手动 OpenTelemetry 配置

¥Manual OpenTelemetry configuration

@vercel/otel 包提供了许多配置选项,应该可以满足大多数常见用例。但如果它不满足你的需求,你可以手动配置 OpenTelemetry。

¥The @vercel/otel package provides many configuration options and should serve most of common use cases. But if it doesn't suit your needs, you can configure OpenTelemetry manually.

首先你需要安装 OpenTelemetry 软件包:

¥Firstly you need to install OpenTelemetry packages:

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

现在你可以在 instrumentation.ts 中初始化 NodeSDK。与 @vercel/otel 不同,NodeSDK 与 Edge Runtime 不兼容,因此你需要确保仅在 process.env.NEXT_RUNTIME === 'nodejs' 时导入它们。我们建议创建一个新文件 instrumentation.node.ts,仅在使用节点时有条件地导入该文件:

¥Now you can initialize NodeSDK in your instrumentation.ts. Unlike @vercel/otel, NodeSDK is not compatible with edge runtime, so you need to make sure that you are importing them only when process.env.NEXT_RUNTIME === 'nodejs'. We recommend creating a new file instrumentation.node.ts which you conditionally import only when using 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 { SEMRESATTRS_SERVICE_NAME } from '@opentelemetry/semantic-conventions'
import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-node'

const sdk = new NodeSDK({
resource: new Resource({
[SEMRESATTRS_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 { SEMRESATTRS_SERVICE_NAME } from '@opentelemetry/semantic-conventions'
import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-node'

const sdk = new NodeSDK({
resource: new Resource({
[SEMRESATTRS_SERVICE_NAME]: 'next-app',
}),
spanProcessor: new SimpleSpanProcessor(new OTLPTraceExporter()),
})
sdk.start()

这样做相当于使用 @vercel/otel,但可以修改和扩展 @vercel/otel 未公开的一些功能。如果需要边缘运行时支持,则必须使用 @vercel/otel

¥Doing this is equivalent to using @vercel/otel, but it's possible to modify and extend some features that are not exposed by the @vercel/otel. If edge runtime support is necessary, you will have to use @vercel/otel.

测试你的仪器

¥Testing your instrumentation

你需要一个具有兼容后端的 OpenTelemetry 收集器来本地测试 OpenTelemetry 跟踪。我们建议使用我们的 OpenTelemetry 开发环境

¥You need an OpenTelemetry collector with a compatible backend to test OpenTelemetry traces locally. We recommend using our OpenTelemetry dev environment.

如果一切正常,你应该能够看到标记为 GET /requested/pathname 的根服务器跨度。该特定跟踪的所有其他跨度都将嵌套在其下方。

¥If everything works well you should be able to see the root server span labeled as GET /requested/pathname. All other spans from that particular trace will be nested under it.

Next.js 跟踪的跨度比默认发出的跨度要多。要查看更多跨度,必须设置 NEXT_OTEL_VERBOSE=1

¥Next.js traces more spans than are emitted by default. To see more spans, you must set NEXT_OTEL_VERBOSE=1.

部署

¥Deployment

使用 OpenTelemetry Collector

¥Using OpenTelemetry Collector

使用 OpenTelemetry Collector 进行部署时,可以使用 @vercel/otel。它既可以在 Vercel 上工作,也可以在自托管时工作。

¥When you are deploying with OpenTelemetry Collector, you can use @vercel/otel. It will work both on Vercel and when self-hosted.

在 Vercel 上部署

¥Deploying on Vercel

我们确保 OpenTelemetry 在 Vercel 上开箱即用。

¥We made sure that OpenTelemetry works out of the box on Vercel.

按照 Vercel 文档 将你的项目连接到可观察性提供商。

¥Follow Vercel documentation to connect your project to an observability provider.

自托管

¥Self-hosting

部署到其他平台也很简单。你将需要启动自己的 OpenTelemetry Collector 以接收和处理来自 Next.js 应用的遥测数据。

¥Deploying to other platforms is also straightforward. You will need to spin up your own OpenTelemetry Collector to receive and process the telemetry data from your Next.js app.

为此,请按照 OpenTelemetry Collector 入门指南 操作,它将引导你设置收集器并将其配置为从 Next.js 应用接收数据。

¥To do this, follow the OpenTelemetry Collector Getting Started guide, which will walk you through setting up the collector and configuring it to receive data from your Next.js app.

一旦收集器启动并运行,你就可以按照各自的部署指南将 Next.js 应用部署到你选择的平台。

¥Once you have your collector up and running, you can deploy your Next.js app to your chosen platform following their respective deployment guides.

自定义导出器

¥Custom Exporters

OpenTelemetry Collector 不是必需的。你可以将自定义 OpenTelemetry 导出器与 @vercel/otel手动 OpenTelemetry 配置 结合使用。

¥OpenTelemetry Collector is not necessary. You can use a custom OpenTelemetry exporter with @vercel/otel or manual OpenTelemetry configuration.

自定义跨度

¥Custom Spans

你可以使用 开放遥测 API 添加自定义范围。

¥You can add a custom span with OpenTelemetry APIs.

npm install @opentelemetry/api

以下示例演示了一个获取 GitHub star 并添加自定义 fetchGithubStars 范围来跟踪获取请求结果的函数:

¥The following example demonstrates a function that fetches GitHub stars and adds a custom fetchGithubStars span to track the fetch request's result:

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

register 函数将在你的代码在新环境中运行之前执行。你可以开始创建新的跨度,它们应该正确添加到导出的跟踪中。

¥The register function will execute before your code runs in a new environment. You can start creating new spans, and they should be correctly added to the exported trace.

Next.js 中的默认跨度

¥Default Spans in Next.js

Next.js 自动检测多个跨度,为你提供有关应用性能的有用见解。

¥Next.js automatically instruments several spans for you to provide useful insights into your application's performance.

Span 上的属性遵循 OpenTelemetry 语义约定。我们还在 next 命名空间下添加了一些自定义属性:

¥Attributes on spans follow OpenTelemetry semantic conventions. We also add some custom attributes under the next namespace:

  • next.span_name - 重复的跨度名称

    ¥next.span_name - duplicates span name

  • next.span_type - 每个跨度类型都有一个唯一的标识符

    ¥next.span_type - each span type has a unique identifier

  • next.route - 请求的路由模式(例如 /[param]/user)。

    ¥next.route - The route pattern of the request (e.g., /[param]/user).

  • next.rsc(真假) - 该请求是否是 RSC 请求,例如预取。

    ¥next.rsc (true/false) - Whether the request is an RSC request, such as prefetch.

  • next.page

    • 这是应用路由使用的内部值。

      ¥This is an internal value used by an app router.

    • 你可以将其视为通往特殊文件的路径(例如 page.tslayout.tsloading.ts 等)

      ¥You can think about it as a route to a special file (like page.ts, layout.ts, loading.ts and others)

    • 只有与 next.route 配对时才能用作唯一标识符,因为 /layout 可以用来标识 /(groupA)/layout.ts/(groupB)/layout.ts

      ¥It can be used as a unique identifier only when paired with next.route because /layout can be used to identify both /(groupA)/layout.ts and /(groupB)/layout.ts

[http.method] [next.route]

  • next.span_typeBaseServer.handleRequest

此跨度代表 Next.js 应用的每个传入请求的根跨度。它跟踪请求的 HTTP 方法、路由、目标和状态代码。

¥This span represents the root span for each incoming request to your Next.js application. It tracks the HTTP method, route, target, and status code of the request.

属性:

¥Attributes:

render route (app) [next.route]

  • next.span_typeAppRender.getBodyResult

该跨度表示在应用路由中渲染路由的过程。

¥This span represents the process of rendering a route in the app router.

属性:

¥Attributes:

  • next.span_name

  • next.span_type

  • next.route

fetch [http.method] [http.url]

  • next.span_typeAppRender.fetch

此跨度表示在代码中执行的获取请求。

¥This span represents the fetch request executed in your code.

属性:

¥Attributes:

可以通过在你的环境中设置 NEXT_OTEL_FETCH_DISABLED=1 来关闭此跨度。当你想要使用自定义获取工具库时,这非常有用。

¥This span can be turned off by setting NEXT_OTEL_FETCH_DISABLED=1 in your environment. This is useful when you want to use a custom fetch instrumentation library.

executing api route (app) [next.route]

  • next.span_typeAppRouteRouteHandlers.runHandler

此跨度表示应用路由中 API 路由处理程序的执行。

¥This span represents the execution of an API route handler in the app router.

属性:

¥Attributes:

  • next.span_name

  • next.span_type

  • next.route

getServerSideProps [next.route]

  • next.span_typeRender.getServerSideProps

该跨度代表特定路由的 getServerSideProps 的执行。

¥This span represents the execution of getServerSideProps for a specific route.

属性:

¥Attributes:

  • next.span_name

  • next.span_type

  • next.route

getStaticProps [next.route]

  • next.span_typeRender.getStaticProps

该跨度代表特定路由的 getStaticProps 的执行。

¥This span represents the execution of getStaticProps for a specific route.

属性:

¥Attributes:

  • next.span_name

  • next.span_type

  • next.route

render route (pages) [next.route]

  • next.span_typeRender.renderDocument

该跨度表示针对特定路由渲染文档的过程。

¥This span represents the process of rendering the document for a specific route.

属性:

¥Attributes:

  • next.span_name

  • next.span_type

  • next.route

generateMetadata [next.page]

  • next.span_typeResolveMetadata.generateMetadata

该跨度表示为特定页面生成元数据的过程(单个路由可以具有多个这些跨度)。

¥This span represents the process of generating metadata for a specific page (a single route can have multiple of these spans).

属性:

¥Attributes:

  • next.span_name

  • next.span_type

  • next.page

resolve page components

  • next.span_typeNextNodeServer.findPageComponents

该跨度表示解析特定页面的页面组件的过程。

¥This span represents the process of resolving page components for a specific page.

属性:

¥Attributes:

  • next.span_name

  • next.span_type

  • next.route

resolve segment modules

  • next.span_typeNextNodeServer.getLayoutOrPageModule

此跨度表示布局或页面的代码模块的加载。

¥This span represents loading of code modules for a layout or a page.

属性:

¥Attributes:

  • next.span_name

  • next.span_type

  • next.segment

start response

  • next.span_typeNextNodeServer.startResponse

该零长度跨度表示响应中发送第一个字节的时间。

¥This zero-length span represents the time when the first byte has been sent in the response.