OpenTelemetry
可观察性对于理解和优化 Next.js 应用程序的行为和性能至关重要。
随着应用程序变得越来越复杂,识别和诊断可能出现的故障变得越来越困难。通过利用可观察性工具(例如日志和指标),开发人员可以深入了解其应用程序的行为并确定优化领域。借助可观察性,开发人员可以在问题演变成重大问题之前主动解决问题,并提供更好的用户体验。因此,强烈建议在您的 Next.js 应用程序中使用可观察性,以提高性能、优化资源并增强用户体验。
我们建议使用 OpenTelemetry 来检测您的应用程序。这是一种与平台无关的方式来检测应用程序,它允许您更改可观察性提供程序而无需更改代码。阅读OpenTelemetry 官方文档,以获取有关 OpenTelemetry 及其工作原理的更多信息。
本文档在整个文档中使用了诸如“跨度”、“跟踪”或“导出器”之类的术语,所有这些术语都可以在OpenTelemetry 可观察性入门中找到。
Next.js 开箱即用地支持 OpenTelemetry 检测,这意味着我们已经检测了 Next.js 本身。启用 OpenTelemetry 后,我们将自动用具有有用属性的跨度包装所有代码,例如getStaticProps
。
入门
OpenTelemetry 是可扩展的,但正确设置它可能非常冗长。因此,我们准备了一个包@vercel/otel
,可帮助您快速入门。
使用 @vercel/otel
要开始使用,请安装以下软件包
npm install @vercel/otel @opentelemetry/sdk-logs @opentelemetry/api-logs @opentelemetry/instrumentation
接下来,在项目的**根目录**中创建一个自定义instrumentation.ts
(或.js
)文件(如果使用 src
文件夹,则在其中)。
import { registerOTel } from '@vercel/otel'
export function register() {
registerOTel({ serviceName: 'next-app' })
}
请参阅@vercel/otel
文档以获取其他配置选项。
需知:
instrumentation
文件应位于项目的根目录中,而不是app
或pages
目录内。如果您使用src
文件夹,则将文件放在src
内,与pages
和app
并排。- 如果您使用
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 时有条件地导入它
export async function register() {
if (process.env.NEXT_RUNTIME === 'nodejs') {
await import('./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
。
测试您的 Instrumentation
您需要一个具有兼容后端的 OpenTelemetry 收集器来在本地测试 OpenTelemetry 追踪。我们建议您使用我们的 OpenTelemetry 开发环境。
如果一切正常,您应该能够看到标记为 GET /requested/pathname
的根服务器跨度。该特定追踪中的所有其他跨度都将嵌套在其下。
Next.js 追踪的跨度比默认情况下发出的跨度更多。要查看更多跨度,您必须设置 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 配置 一起使用。
自定义跨度
您可以使用 OpenTelemetry API 添加自定义跨度。
npm install @opentelemetry/api
以下示例演示了一个获取 GitHub 星星并添加自定义 fetchGithubStars
跨度以跟踪获取请求结果的函数
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
函数将在您的代码在新环境中运行之前执行。您可以开始创建新的跨度,并且它们应该正确地添加到导出的追踪中。
Next.js 中的默认跨度
Next.js 自动为您检测多个跨度,以提供对应用程序性能的有用见解。
跨度上的属性遵循 OpenTelemetry 语义约定。我们还在 next
命名空间下添加了一些自定义属性
next.span_name
- 复制跨度名称next.span_type
- 每个跨度类型都有一个唯一的标识符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
此跨度表示对 Next.js 应用程序的每个传入请求的根跨度。它跟踪请求的 HTTP 方法、路由、目标和状态代码。
属性
- 常见 HTTP 属性
http.method
http.status_code
- 服务器 HTTP 属性
http.route
http.target
next.span_name
next.span_type
next.route
render route (app) [next.route]
next.span_type
:AppRender.getBodyResult
。
此跨度表示在应用路由器中渲染路由的过程。
属性
next.span_name
next.span_type
next.route
fetch [http.method] [http.url]
next.span_type
:AppRender.fetch
此跨度表示在您的代码中执行的 fetch 请求。
属性
- 常见 HTTP 属性
http.method
- 客户端 HTTP 属性
http.url
net.peer.name
net.peer.port
(仅在指定时)
next.span_name
next.span_type
可以通过在您的环境中设置NEXT_OTEL_FETCH_DISABLED=1
来关闭此跨度。当您想使用自定义 fetch 检测库时,这很有用。
执行 API 路由 (应用) [next.route]
next.span_type
:AppRouteRouteHandlers.runHandler
。
此跨度表示在应用路由器中执行 API 路由处理程序。
属性
next.span_name
next.span_type
next.route
getServerSideProps [next.route]
next.span_type
:Render.getServerSideProps
。
此跨度表示对特定路由执行getServerSideProps
。
属性
next.span_name
next.span_type
next.route
getStaticProps [next.route]
next.span_type
:Render.getStaticProps
。
此跨度表示对特定路由执行getStaticProps
。
属性
next.span_name
next.span_type
next.route
渲染路由 (页面) [next.route]
next.span_type
:Render.renderDocument
。
此跨度表示为特定路由渲染文档的过程。
属性
next.span_name
next.span_type
next.route
generateMetadata [next.page]
next.span_type
:ResolveMetadata.generateMetadata
。
此跨度表示为特定页面生成元数据的过程(单个路由可以有多个此类跨度)。
属性
next.span_name
next.span_type
next.page
解析页面组件
next.span_type
:NextNodeServer.findPageComponents
。
此跨度表示为特定页面解析页面组件的过程。
属性
next.span_name
next.span_type
next.route
解析分段模块
next.span_type
:NextNodeServer.getLayoutOrPageModule
。
此跨度表示加载布局或页面的代码模块。
属性
next.span_name
next.span_type
next.segment
开始响应
next.span_type
:NextNodeServer.startResponse
。
此零长度跨度表示响应中发送第一个字节的时间。
这有帮助吗?