Skip to main content

OpenTelemetry

note

该功能处于实验阶段,您需要在 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 中。

note

我们目前仅在无服务器函数中支持 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')
}

温馨提示:

  • 仪表文件应该位于项目的根目录,而不是在 apppages 目录中。 如果使用 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.tslayout.tsloading.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