OpenTelemetry
可观测性对于理解和优化 Next.js 应用的行为和性能至关重要。
随着应用变得越来越复杂,识别和诊断可能出现的问题变得越来越困难。通过利用可观测性工具,如日志记录和指标,开发者可以深入了解应用的行为并识别需要优化的地方。有了可观测性,开发者可以在问题变成大麻烦之前主动解决,并提供更好的用户体验。因此,强烈建议在你的 Next.js 应用中使用可观测性来提高性能、优化资源和增强用户体验。
我们推荐使用 OpenTelemetry 来检测你的应用。这是一种平台无关的应用检测方式,允许你更换可观测性提供商而无需更改代码。阅读 OpenTelemetry 官方文档 以了解更多关于 OpenTelemetry 及其工作原理的信息。
本文档使用了诸如 Span、Trace 或 Exporter 等术语,这些都可以在 OpenTelemetry 可观测性入门 中找到。
Next.js 原生支持 OpenTelemetry 检测,这意味着我们已经对 Next.js 本身进行了检测。当你启用 OpenTelemetry 时,我们会自动用带有有用属性的 spans 包装你的所有代码,如 getStaticProps
。
入门
OpenTelemetry 是可扩展的,但正确设置可能会相当冗长。这就是为什么我们准备了一个包 @vercel/otel
,帮助你快速入门。
使用 @vercel/otel
首先,安装以下包:
接下来,在项目的根目录(或者如果使用 src
文件夹则在其中)创建一个自定义的 instrumentation.ts
(或 .js
) 文件:
查看 @vercel/otel
文档 了解更多配置选项。
值得注意的是
instrumentation
文件应该在你项目的根目录中,而不是在app
或pages
目录内。如果你使用src
文件夹,那么将文件放在src
中,与pages
和app
并列。- 如果你使用
pageExtensions
配置选项 添加后缀,你还需要更新instrumentation
文件名以匹配。- 我们创建了一个基本的 with-opentelemetry 示例供你使用。
手动 OpenTelemetry 配置
@vercel/otel
包提供了许多配置选项,应该能满足大多数常见用例。但如果它不符合你的需求,你可以手动配置 OpenTelemetry。
首先,你需要安装 OpenTelemetry 包:
现在你可以在 instrumentation.ts
中初始化 NodeSDK
。
与 @vercel/otel
不同,NodeSDK
与边缘运行时不兼容,所以你需要确保只在 process.env.NEXT_RUNTIME === 'nodejs'
时导入它们。我们建议创建一个新文件 instrumentation.node.ts
,只在使用 node 时有条件地导入:
这样做相当于使用 @vercel/otel
,但可以修改和扩展一些 @vercel/otel
没有暴露的功能。如果需要边缘运行时支持,你将不得不使用 @vercel/otel
。
测试你的检测
你需要一个带有兼容后端的 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 导出器,结合 @vercel/otel
或 手动 OpenTelemetry 配置。
自定义 Span
你可以使用 OpenTelemetry API 添加自定义 span。
以下示例演示了一个获取 GitHub 星星数的函数,并添加了一个自定义的 fetchGithubStars
span 来跟踪获取请求的结果:
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.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 方法、路由、目标和状态码。
属性:
- 通用 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
这个 span 表示在应用路由器中渲染路由的过程。
属性:
next.span_name
next.span_type
next.route
fetch [http.method] [http.url]
next.span_type
:AppRender.fetch
这个 span 表示在你的代码中执行的获取请求。
属性:
- 通用 HTTP 属性
http.method
- 客户端 HTTP 属性
http.url
net.peer.name
net.peer.port
(仅当指定时)
next.span_name
next.span_type
可以通过在你的环境中设置 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 表示响应中发送第一个字节的时间。