跳到主要内容

OpenTelemetry

备注

该功能处于实验阶段,您需要在 next.config.js 中显式选择通过 experimental.instrumentationHook = true; 启用它。

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

随着应用变得越来越复杂,识别和诊断可能出现的问题变得越来越困难。 通过利用观测工具(如日志记录和指标),开发人员可以深入了解应用的行为,找出需要优化的领域。 通过观测,开发人员可以在问题变得严重之前主动解决问题,提供更好的用户体验。 因此,强烈建议在 Next.js 应用中使用观测,以改善性能、优化资源并提升用户体验。

我们建议使用 OpenTelemetry 来为您的应用添加仪表。它是一种平台无关的仪表方法, 允许您更改观测提供程序而无需更改代码。 有关 OpenTelemetry 的更多信息以及它是如何工作的,请阅读官方 OpenTelemetry 文档。

本文档使用像 Span、Trace 或 Exporter 这样的术语,它们都可以在 OpenTelemetry 观测入门手册 中找到。

Next.js 支持开箱即用的 OpenTelemetry 仪表,这意味着我们已经为 Next.js 本身添加了仪表。 启用 OpenTelemetry 后,我们将自动将您的所有代码(例如 getStaticProps)包装在带有有用属性的 Span 中。

备注

我们目前仅在无服务器函数中支持 OpenTelemetry 绑定。我们不提供用于边缘或客户端代码的支持。

入门指南​

OpenTelemetry 是可扩展的,但适当设置可能会相当冗长。 这就是为什么我们准备了一个 @vercel/otel 包,帮助您快速入门。 如果需要自定义设置,它并不可扩展,您应该手动配置 OpenTelemetry。

使用 @vercel/otel​

要开始,您必须安装 @vercel/otel:

npm install @vercel/otel

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

your-project/instrumentation.ts

import { registerOTel } from '@vercel/otel'

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

温馨提示:​

  • 仪表文件应该位于项目的根目录,而不是在 app 或 pages 目录中。 如果使用 src 文件夹,则将文件放在 src 文件夹旁边。
  • 如果使用 pageExtensions 配置选项添加后缀,您还需要更新仪表文件的文件名以匹配。
  • 我们创建了一个基本的 with-opentelemetry 示例,您可以使用它。

手动配置 OpenTelemetry​

如果我们的包装器 @vercel/otel 不符合您的需求,您可以手动配置 OpenTelemetry。

首先,您需要安装 OpenTelemetry 包:

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

现在,您可以在 instrumentation.ts 中初始化 NodeSDK。 由于 OpenTelemetry API 与 edge runtime 不兼容,因此您需要确保仅在 process.env.NEXT_RUNTIME === 'nodejs' 时才引入它们。我们建议在仅在使用 node 时有条件地导入的 instrumentation.node.ts 文件中创建新文件:

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

这样做相当于使用 @vercel/otel,但是可以进行修改和扩展。 例如,您可以使用 @opentelemetry/exporter-trace-otlp-grpc 替代 @opentelemetry/exporter-trace-otlp-http,或者您可以指定更多的资源属性。

测试您的仪表​

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

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

Next.js 比默认情况下发出的 Span 更多。要查看更多的 Span,您必须设置 NEXT_OTEL_VERBOSE=1。

部署​

使用 OpenTelemetry Collector​

在部署时使用 OpenTelemetry Collector 时,您可以使用 @vercel/otel。 它将在 Vercel 上和自托管时都正常工作。

在 Vercel 上部署​

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

请按照 Vercel 文档连接您的项目到观测提供程序。

自托管​

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

要做到这一点,请按照 OpenTelemetry Collector 入门指南 进行操作, 该指南将引导您设置收集器并配置其接收来自 Next.js 应用的数据。

一旦您的收集器运行起来,您可以按照各自的部署指南在您选择的平台上部署您的 Next.js 应用。

自定义导出器​

我们建议使用 OpenTelemetry Collector。 如果在您的平台上不可能使用它,您可以使用具有手动 OpenTelemetry 配置的自定义 OpenTelemetry 导出器。

自定义 Span​

您可以使用 OpenTelemetry API 添加自定义 Span。

npm install @opentelemetry/api

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

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 函数将在您的代码在新环境中运行之前执行。 您可以开始创建新的 Spans,并且它们应该会被正确地添加到导出的跟踪中。

Next.js 中的默认 Spans​

Next.js 自动为您仪表了一些 Span,以提供对应用性能的有用见解。

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

  • next.span_name - 重复的 Span 名称
  • next.span_type - 每个 Span 类型都有一个唯一的标识符
  • next.route - 请求的路由模式(例如 /[param]/user)。
  • next.page
    • 这是应用程序路由器内部的一个内部值。
    • 您可以将其视为指向特殊文件(如 page.ts、layout.ts、loading.ts 等)的路由。
    • 仅在与 next.route 配对使用时,它可以用作唯一标识符,因为 /layout 可用于同时标识 /(groupA)/layout.ts 和 /(groupB)/layout.ts。

[http.method] [next.route]​

  • next.span_type: BaseServer.handleRequest

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

属性:

render route (app) [next.route]​

  • next.span_type: AppRender.getBodyResult

此 Span 表示在应用程序路由器中渲染路由的过程。

属性:

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

fetch [http.method] [http.url]​

  • next.span_type: AppRender.fetch

此 Span 表示您代码中执行的 fetch 请求。

属性:

executing api route (app) [next.route]​

  • next.span_type: AppRouteRouteHandlers.runHandler

此 Span 表示在应用程序路由器中执行 API 路由处理程序的过程。

属性:

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

getServerSideProps [next.route]​

  • next.span_type: Render.getServerSideProps

此 Span 表示为特定路由执行 getServerSideProps 的过程。

属性:

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

getStaticProps [next.route]​

  • next.span_type: Render.getStaticProps

此 Span 表示为特定路由执行 getStaticProps 的过程。

属性:

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

render route (pages) [next.route]​

  • next.span_type: Render.renderDocument

此 Span 表示为特定路由渲染文档的过程。

属性:

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

generateMetadata [next.page]​

  • next.span_type: ResolveMetadata.generateMetadata

此 Span 表示为特定页面生成元数据的过程(单个路由可能具有多个此类 Span)。

属性:

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