跳到内容
Pages Router指南OpenTelemetry

如何使用 OpenTelemetry 为你的 Next.js 应用进行埋点

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

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

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

本文档在整个过程中使用了诸如 _Span_、_Trace_ 或 _Exporter_ 等术语,所有这些术语都可以在 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`)文件

你的项目/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` 不兼容 edge runtime,因此你需要确保仅当 `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 { resourceFromAttributes } 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: resourceFromAttributes({
    [ATTR_SERVICE_NAME]: 'next-app',
  }),
  spanProcessor: new SimpleSpanProcessor(new OTLPTraceExporter()),
})
sdk.start()

这样做相当于使用 ` @vercel/otel `,但可以修改和扩展 ` @vercel/otel ` 未暴露的一些功能。如果需要 edge runtime 支持,你将必须使用 ` @vercel/otel `。

测试你的埋点

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

如果一切顺利,你应该能够看到根服务器 span,标记为 `GET /requested/pathname`。该特定跟踪中的所有其他 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 应用程序部署到你选择的平台。

自定义 Exporters

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

自定义 Spans

你可以使用 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` 函数将在你的代码在新环境中运行之前执行。你可以开始创建新的 span,它们应该正确添加到导出的跟踪中。

Next.js 中的默认 Spans

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.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 方法、路由、目标和状态代码。

属性

渲染路由 (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 请求。

属性

此 span 可以通过在你的环境中设置 `NEXT_OTEL_FETCH_DISABLED=1` 来关闭。当你想要使用自定义 fetch 埋点库时,这很有用。

执行 api 路由 (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

渲染路由 (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

解析页面组件

  • next.span_type: NextNodeServer.findPageComponents

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

属性

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

解析分段模块

  • next.span_type: NextNodeServer.getLayoutOrPageModule

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

属性

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

开始响应

  • next.span_type: NextNodeServer.startResponse

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