OpenTelemetry
您需要知道: 此功能是实验性的,您需要通过在
next.config.js中提供experimental.instrumentationHook = true;来明确选择加入。
可观察性对于理解和优化您的 Next.js 应用的行为和性能至关重要。
随着应用程序变得越来越复杂,识别和诊断可能出现的问题变得越来越困难。通过利用可观察性工具(如日志记录和指标),开发人员可以深入了解其应用程序的行为并识别优化的领域。通过可观察性,开发人员可以主动解决问题,防止其成为重大问题,并提供更好的用户体验。因此,强烈建议在您的 Next.js 应用程序中使用可观察性,以提高性能、优化资源并增强用户体验。
我们建议使用 OpenTelemetry 来检测您的应用程序。 这是一种与平台无关的方式来检测应用,允许你在不改变代码的情况下改变你的可观察性提供者。 阅读官方 OpenTelemetry 文档以了解有关 OpenTelemetry 及其工作原理的更多信息。
本文档使用了诸如 Span、 Trace 或 Exporter 等术语,所有这些术语都可以在the OpenTelemetry Observability Primer中找到。
Next.js 开箱即支持 OpenTelemetry 检测,这意味着我们已经对 Next.js 本身进行了检测。
当您启用 OpenTelemetry 时,我们会自动将所有代码(如getStaticProps)包装在带有有用属性的 spans 中。
开始
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" });
}
import { registerOTel } from "@vercel/otel";
export function register() {
registerOTel({ serviceName: "next-app" });
}
参阅@vercel/otel 文档以获取其他配置选项。
您需要知道
instrumentation文件应位于项目的根目录中,而不是在app或pages目录中。如果您使用src文件夹, 那么请将文件放在与pages和app同级的src文件夹中。- 如果您使用
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 运行时,因此您需要确保仅在process.env.NEXT_RUNTIME === 'nodejs'时导入它们。我们建议创建一个新的文件instrumentation.node.ts,并仅在使用 Node.js 时有条件地导入它:
export async function register() {
if (process.env.NEXT_RUNTIME === "nodejs") {
await import("./instrumentation.node.ts");
}
}
export async function register() {
if (process.env.NEXT_RUNTIME === "nodejs") {
await import("./instrumentation.node.js");
}
}
import { NodeSDK } from "@opentelemetry/sdk-node";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
import { Resource } from "@opentelemetry/resources";
import { SEMRESATTRS_SERVICE_NAME } from "@opentelemetry/semantic-conventions";
import { SimpleSpanProcessor } from "@opentelemetry/sdk-trace-node";
const sdk = new NodeSDK({
resource: new Resource({
[SEMRESATTRS_SERVICE_NAME]: "next-app",
}),
spanProcessor: new SimpleSpanProcessor(new OTLPTraceExporter()),
});
sdk.start();
import { NodeSDK } from "@opentelemetry/sdk-node";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
import { Resource } from "@opentelemetry/resources";
import { SEMRESATTRS_SERVICE_NAME } from "@opentelemetry/semantic-conventions";
import { SimpleSpanProcessor } from "@opentelemetry/sdk-trace-node";
const sdk = new NodeSDK({
resource: new Resource({
[SEMRESATTRS_SERVICE_NAME]: "next-app",
}),
spanProcessor: new SimpleSpanProcessor(new OTLPTraceExporter()),
});
sdk.start();
这样做相当于使用@vercel/otel, ,但可以修改和扩展一些 @vercel/otel未公开的功能。如果需要 Edge 运行时支持,您将不得不使用@vercel/otel.
测试您的检测
您需要一个兼容后端的 OpenTelemetry 收集器来本地测试 OpenTelemetry traces。 我们建议使用我们的OpenTelemetry 开发环境。
如果一切正常,您应该能够看到标记为GET /requested/pathname的根服务器 span。
所有来自该特定 trace 的其他 spans 都将嵌套在其下。
Next.js 追踪的 spans 比默认情况下发出的更多。
要查看更多 spans,您必须设置NEXT_OTEL_VERBOSE=1。
部署
使用 OpenTelemetry Collector
当您使用 OpenTelemetry Collector 部 署时,您可以使用@vercel/otel。
它在 Vercel 和自托管时都能正常工作。
在 Vercel 上部署
我们确保 OpenTelemetry 在 Vercel 上开箱即用。
请参阅 Vercel 文档以将您的项目连接到可观察性提供商。
自托管
部署到其他平台也很简单。您需要启动自己的 OpenTelemetry 收集器来接收和处理来自您的 Next.js 应用的遥测数据。
要做到这一点,请按照OpenTelemetry Collector 入门指南 操作,该指南将引导您设置收集器并配置它以接收来自您的 Next.js 应用的数据。
一旦您的收集器启动并运行,您可以按照各自的平台部署指南将您的 Next.js 应用部署到您选择的平台。
自定义导出器
OpenTelemetry Collector 不是必需的。您可以使用@vercel/otel 或 手动配置 OpenTelemetry 来使用自定义的 OpenTelemetry 导出器。
自定义 Spans
您可以使用OpenTelemetry APIs添加自定义 span。
npm install @opentelemetry/api
以下示例演示了一个获取 GitHub stars 的函数,并添加了一个自定义的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函数将在您的代码在新环境中运行之前执行。
您可以开始创建新的 spans,它们应该被正确地添加到导出的 trace 中。
Next.js 中默认的 Spans
Next.js 会自动为您检测服务器 spans,以提供有关应用性能的有用见解。
spans 上的属性遵循OpenTelemetry 语义约定。我们还在 next命名空间下添加了一些自定义属性:
next.span_name- duplicates span namenext.span_type- each span type has a unique identifiernext.route- The route pattern of the request (e.g.,/[param]/user).next.rsc(true/false) - Whether the request is an RSC request, such as prefetch.next.page- This is an internal value used by an app router.
- You can think about it as a route to a special file (like
page.ts,layout.ts,loading.tsand others) - It can be used as a unique identifier only when paired with
next.routebecause/layoutcan be used to identify both/(groupA)/layout.tsand/(groupB)/layout.ts
[http.method] [next.route]
next.span_type:BaseServer.handleRequest
This span represents the root span for each incoming request to your Next.js application. It tracks the HTTP method, route, target, and status code of the request.
Attributes:
- Common HTTP attributes
http.methodhttp.status_code
- Server HTTP attributes
http.routehttp.target
next.span_namenext.span_typenext.route
render route (app) [next.route]
next.span_type:AppRender.getBodyResult.
This span represents the process of rendering a route in the app router.
Attributes:
next.span_namenext.span_typenext.route
fetch [http.method] [http.url]
next.span_type:AppRender.fetch
This span represents the fetch request executed in your code.
Attributes:
- Common HTTP attributes
http.method
- Client HTTP attributes
http.urlnet.peer.namenet.peer.port(only if specified)
next.span_namenext.span_type
This span can be turned off by setting NEXT_OTEL_FETCH_DISABLED=1 in your environment. This is useful when you want to use a custom fetch instrumentation library.
executing api route (app) [next.route]
next.span_type:AppRouteRouteHandlers.runHandler.
This span represents the execution of an API route handler in the app router.
Attributes:
next.span_namenext.span_typenext.route
getServerSideProps [next.route]
next.span_type:Render.getServerSideProps.
This span represents the execution of getServerSideProps for a specific route.
Attributes:
next.span_namenext.span_typenext.route
getStaticProps [next.route]
next.span_type:Render.getStaticProps.
This span represents the execution of getStaticProps for a specific route.
Attributes:
next.span_namenext.span_typenext.route
render route (pages) [next.route]
next.span_type:Render.renderDocument.
This span represents the process of rendering the document for a specific route.
Attributes:
next.span_namenext.span_typenext.route
generateMetadata [next.page]
next.span_type:ResolveMetadata.generateMetadata.
This span represents the process of generating metadata for a specific page (a single route can have multiple of these spans).
Attributes:
next.span_namenext.span_typenext.page
resolve page components
next.span_type:NextNodeServer.findPageComponents.
This span represents the process of resolving page components for a specific page.
Attributes:
next.span_namenext.span_typenext.route
resolve segment modules
next.span_type:NextNodeServer.getLayoutOrPageModule.
This span represents loading of code modules for a layout or a page.
Attributes:
next.span_namenext.span_typenext.segment
start response
next.span_type:NextNodeServer.startResponse.
This zero-length span represents the time when the first byte has been sent in the response.