跳到主要内容

如何设置 OpenTelemetry 监控

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

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

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

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

Next.js 开箱即用地支持 OpenTelemetry 监控,这意味着我们已经对 Next.js 本身进行了监控。

当您启用 OpenTelemetry 时,我们将自动用有用的属性将所有代码(如 getStaticProps)包装在 spans 中。

开始使用

OpenTelemetry 是可扩展的,但正确设置它可能相当冗长。 这就是为什么我们准备了一个 @vercel/otel 包来帮助您快速开始。

使用 @vercel/otel

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

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

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

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

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 示例供您使用。

提示

  • instrumentation 文件应该在项目的根目录中,而不是在 apppages 目录内。如果您使用 src 文件夹,请将文件放在 src 内,与 pagesapp 并列。
  • 如果您使用 pageExtensions 配置选项 添加后缀,您还需要更新 instrumentation 文件名以匹配。
  • 我们创建了一个基本的 with-opentelemetry 示例供您使用。

手动 OpenTelemetry 配置

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

首先,您需要安装 OpenTelemetry 包:

Terminal
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,您仅在节点使用时有条件地导入:

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 收集器和一个兼容的后端来在本地测试 OpenTelemetry 跟踪。 我们建议使用我们的 OpenTelemetry 开发环境

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

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

部署

使用 OpenTelemetry 收集器

当您使用 OpenTelemetry 收集器部署时,您可以使用 @vercel/otel。 它将在 Vercel 和自托管时都工作。

在 Vercel 上部署

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

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

自托管

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

为此,请按照 OpenTelemetry 收集器入门指南,该指南将指导您设置收集器并配置它以从 Next.js 应用接收数据。

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

自定义导出器

OpenTelemetry 收集器不是必需的。您可以使用自定义 OpenTelemetry 导出器与 @vercel/otel手动 OpenTelemetry 配置

自定义 Span

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

Terminal
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 中的默认 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 表示在代码中执行的获取请求。

属性:

通过设置环境中的 NEXT_OTEL_FETCH_DISABLED=1 可以关闭此 span。当您想要使用自定义获取监控库时,这很有用。

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 表示响应中发送第一个字节的时间。