跳到内容

OpenTelemetry

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

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

我们建议使用 OpenTelemetry 来检测你的应用程序。这是一种与平台无关的检测应用程序的方式,它允许你更改可观测性提供商而无需更改你的代码。阅读 官方 OpenTelemetry 文档 以获取有关 OpenTelemetry 及其工作原理的更多信息。

本文档在全文中使用诸如 SpanTraceExporter 等术语,所有这些都可以在 OpenTelemetry 可观测性入门指南 中找到。

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

开始使用

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

使用 @vercel/otel

要开始使用,请安装以下软件包

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

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

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

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

须知:

  • instrumentation 文件应该位于项目的根目录中,而不是在 apppages 目录中。如果你正在使用 src 文件夹,则将该文件放在 src 内部,与 pagesapp 并列。
  • 如果你使用 pageExtensions 配置选项 添加后缀,你还需要更新 instrumentation 文件名以匹配。
  • 我们创建了一个基本的 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。与 @vercel/otel 不同,NodeSDK 与边缘运行时不兼容,因此你需要确保仅在 process.env.NEXT_RUNTIME === 'nodejs' 时导入它们。我们建议创建一个新的文件 instrumentation.node.ts,仅在使用 node 时有条件地导入它

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

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

测试你的检测

你需要一个带有兼容后端的 OpenTelemetry Collector 来在本地测试 OpenTelemetry 追踪。我们建议使用我们的 OpenTelemetry 开发环境

如果一切正常,你应该能够看到标记为 GET /requested/pathname 的根服务器 span。来自该特定追踪的所有其他 span 将嵌套在它之下。

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

部署

使用 OpenTelemetry Collector

当你使用 OpenTelemetry Collector 部署时,你可以使用 @vercel/otel。它在 Vercel 和自托管环境下都有效。

在 Vercel 上部署

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

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

自托管

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

为此,请按照 OpenTelemetry Collector 入门指南 进行操作,该指南将引导你完成设置 collector 并配置它以接收来自你的 Next.js 应用程序的数据。

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

自定义导出器

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

自定义 Span

你可以使用 OpenTelemetry API 添加自定义 span。

终端
npm install @opentelemetry/api

以下示例演示了一个函数,该函数获取 GitHub 星星并添加一个自定义 fetchGithubStars span 以跟踪 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()
      }
    })
}

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

Next.js 中的默认 Span

Next.js 自动检测多个 span,以便为你提供有关应用程序性能的有用见解。

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

  • next.span_name - 复制 span 名称
  • next.span_type - 每种 span 类型都有唯一的标识符
  • next.route - 请求的路由模式(例如,/[param]/user)。
  • next.rsc (true/false) - 请求是否为 RSC 请求,例如预取。
  • 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 请求。

属性

可以通过在你的环境中设置 NEXT_OTEL_FETCH_DISABLED=1 来关闭此 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

resolve page components

  • next.span_type: NextNodeServer.findPageComponents

此 span 代表为特定页面解析页面组件的过程。

属性

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

resolve segment modules

  • next.span_type: NextNodeServer.getLayoutOrPageModule

此 span 代表加载布局或页面的代码模块。

属性

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

start response

  • next.span_type: NextNodeServer.startResponse

此零长度 span 代表响应中第一个字节发送的时间。