Next.js 分布式追踪实战:基于 Highlight 的 W3C Trace Context 全链路接入与源码解析
发布时间:2026/9/25 3:12:04来源:尧图网络
可观测性后端【免费下载链接】highlighthighlight.io: The open source, full-stack monitoring platform. Error monitoring, session replay, logging, distributed tracing, and more.项目地址https://gitcode.com/gh_mirrors/hi/highlight点击查看免费下载本篇指南围绕 Next.js 应用中分布式追踪Distributed Tracing的完整落地展开从浏览器客户端注入追踪上下文、Next.js 服务端中间件传播 W3C Trace Context 头到下游微服务接收 traceparent 并关联同一 Trace最终在 Highlight 平台中可视化跨服务的瀑布流。读完本文你将掌握 Highlight Next.js SDK 与 Node/Go SDK 的接入方式、withHighlightConfig各配置项的默认行为以及propagation.extract/inject在源码中如何串联起一次完整的跨服务调用链。什么是分布式追踪分布式追踪用于理解和监控跨多个服务运行的复杂应用的执行情况它把分散在不同服务中的操作span链接进同一条 trace从而更容易定位性能瓶颈和排查问题。在 Next.js 场景下这条链路通常覆盖三段浏览器端用户交互、页面渲染产生的操作Next.js 服务端middleware、API 路由、服务端组件中的业务逻辑下游微服务Next.js 的 API 路由发起的 HTTP 调用例如 Go 微服务。要实现三者关联关键在于追踪上下文trace context的跨进程传播。Highlight 采用的是 W3C 标准traceparent/tracestate头由 OpenTelemetry 的W3CTraceContextPropagator实现此外还携带一个 Highlight 特有的x-highlight-request头用于把服务端操作关联到触发该请求的用户会话Session Replay。整体数据流从源码结构看完整的数据流如下浏览器 (highlight.run) │ 1. 发出 fetch 请求自动携带 W3C trace context 头 │ 2. 初始化时把 sessionSecureID 写入 cookie ▼ Next.js middleware (highlightMiddleware) │ 3. 读取 cookie补写 x-highlight-request 头 ▼ API 路由 (withHighlight / runWithHeaders) │ 4. propagation.extract 提取入站上下文 → 创建服务端 span │ 5. propagation.inject 把 traceparent 注入出站请求头 ▼ Go 微服务 (chi middleware Go OTel SDK) 6. 提取 traceparent挂到同一条 trace输出 OTLP第一步客户端安装与初始化在 Next.js 项目中安装 Highlight 客户端 SDKyarn add highlight-run/next在 App Router 的app/layout.tsx或 Pages Router 的_app.tsx中渲染HighlightInit组件import { HighlightInit } from highlight-run/next/client export default function RootLayout({ children }: { children: React.ReactNode }) { return ( html langen body HighlightInit projectIdyour-project-id excludedHostnames{[localhost]} / {children} /body /html ) }客户端初始化完成后会自动为浏览器发出的请求注入追踪头。看 客户端入口源码 可以发现两件对追踪链路很关键的事会话 CookielocalH.init返回的sessionSecureID会被写入名为sessionSecureID的 cookienext-client.tsx#L42-L49。这是后续服务端把操作关联回会话回放Session Replay的基础。代理模式如果构建期注入了configureHighlightProxy true默认开启见下文withHighlightConfig初始化选项会被改写为backendUrl: /highlight-events和otlpEndpoint: window.location.originnext-client.tsx#L32-L40。也就是说浏览器上报的 OTLP 数据/v1/traces、/v1/metrics、/v1/logs会走你自己的域名由 Next.js 代理转发到 Highlight避免跨域与混合内容问题。第二步服务端 middleware 传播请求上下文客户端 cookie 只是标识真正把追踪头“补齐”并交给后续逻辑的是 Next.js 的middleware.ts// middleware.ts import { highlightMiddleware } from highlight-run/next/server import { NextResponse } from next/server export async function middleware(request: Request) { await highlightMiddleware(request) return NextResponse.next() }仓库中的 e2e 示例 e2e/nextjs/middleware.ts 与上面完全一致。highlightMiddleware的实现非常轻量highlight-middleware.ts#L3-L9export async function highlightMiddleware(request: Request) { const sessionSecureID (await cookies()).get(sessionSecureID)?.value const xHighlightRequest request.headers.get(x-highlight-request) if (!xHighlightRequest sessionSecureID) { request.headers.set(x-highlight-request, ${sessionSecureID}/) } }它从 cookie 取出sessionSecureID在请求头不存在x-highlight-request时补写一个${sessionSecureID}/格式的值。这个头会一路传到 API 路由服务端 SDK 据此解析出secureSessionId和requestId见 client.ts 的 parseHeaders把 span 打上highlight.session_id属性从而在后端日志、错误和 trace 与前端会话回放之间建立关联。第三步withHighlightConfig 与 OTLP 代理配置为了让浏览器与 Next.js 服务端能上报 OTLP 数据Next.js 需要用withHighlightConfig包装配置文件。它会自动在rewrites中追加以下代理规则源码见 with-highlight-config.ts#L141-L158sourcedestination用途/highlight-eventshttps://pub.highlight.io事件/会话等通用上报代理/v1/traceshttps://otel.highlight.io/v1/tracesOTLP trace 上报代理/v1/metricshttps://otel.highlight.io/v1/metricsOTLP metric 上报代理/v1/logshttps://otel.highlight.io/v1/logsOTLP log 上报代理配置示例// next.config.mjs import { withHighlightConfig } from highlight-run/next/config /** type {import(next).NextConfig} */ const nextConfig {} export default withHighlightConfig(nextConfig, { uploadSourceMaps: false, // 是否上传 source map默认生产构建且配置了 apiKey 时为 true configureHighlightProxy: true, // 是否注入 /highlight-events、/v1/* 代理重写默认 true apiKey: process.env.HIGHLIGHT_SOURCEMAP_UPLOAD_API_KEY, environment: process.env.ENVIRONMENT, serviceName: my-nextjs-app, })各选项的默认值可以直接从 getDefaultOpts 的源码确认选项默认值说明uploadSourceMaps生产构建NODE_ENV production且配置了apiKey或HIGHLIGHT_SOURCEMAP_UPLOAD_API_KEY时为true启用后会改写 webpackdevtool并注入上传插件同时把/:path*.map重写为 404 以防 source map 泄漏configureHighlightProxytrue注入上表中的 4 条代理 rewrite并把configureHighlightProxy作为构建期环境变量暴露给客户端代码apiKey上传 source map 时关联项目用的 API key也可用环境变量HIGHLIGHT_SOURCEMAP_UPLOAD_API_KEY提供appVersion优先取 NextgenerateBuildId()的结果上传 source map 时使用的版本标识environment环境标识用于区分 localhost 与生产环境的会话serviceName应用名sourceMapsPath.next/source map 文件根目录sourceMapsBasePath_next/上传后 source map URL 前缀sourceMapsBackendUrl未设置自托管部署时可选自托管 Highlight 部署的后端地址需要注意withHighlightConfig兼容next.config的三种形态对象、同步函数、异步函数见 withHighlightConfig 入口。第四步API 路由的追踪包装与 W3C 上下文传播Next.js 的 API 路由以及 Route Handler需要用 Node SDK 的 handler 包装让每个请求都运行在一个从入站头提取出来的 span 上下文里。仓库 e2e 中封装好的用法见 e2e/nextjs/pages/api/page-router-trace.tsimport { withPageRouterHighlight } from /app/_utils/page-router-highlight.config import { H } from highlight-run/next/server import { context, propagation } from opentelemetry/api export default withPageRouterHighlight(async function handler( req: NextApiRequest, res: NextApiResponse, ) { const { span } H.startWithHeaders(page-router-span, {}) const headers {} // 1) 手动复制入站头含 W3C traceparent转发给 Go 服务 await fetch(http://localhost:3010/x-highlight-request, { method: GET, headers: Object.entries(req.headers).reduce( (acc, [key, value]) ({ ...acc, [key, value ]: value }), {}, ), }) // 2) 用 OTel propagation API 把当前活跃 span 注入出站头 propagation.inject(context.active(), headers) await fetch(http://localhost:3010/traceparent, { method: GET, headers }) res.send(Trace sent!) span.end() })包装器内部做的事情本质上是 Node SDK 的runWithHeaders。从 client.ts#L425-L475 的实现可以看到完整的 W3C Trace Context 传播闭环async runWithHeadersT(name, headers, cb, options?) { const { span, ctx } this.startWithHeaders(name, headers, options) return await api.context.with(ctx, async () { propagation.inject(ctx, headers) // 注入 traceparent供出站请求继承 try { return await cb(span) } catch (error) { span.recordException(error) throw error } finally { span.end() } }) } startWithHeaders(spanName, headers, options?) { const ctx propagation.extract(api.context.active(), headers) // 1. 提取入站上下文 const span this.tracer.startSpan(spanName, options, ctx) // 2. 派生子 span const contextWithSpanSet api.trace.setSpan(ctx, span) let { secureSessionId, requestId } this.parseHeaders(headers) // 3. 解析 x-highlight-request // ...将 secureSessionId 写入 span 属性 highlight.session_id 并放入 baggage propagation.inject(contextWithSpanSet, headers) // 4. 注入更新后的上下文 return { span, ctx: contextWithSpanSet } }而W3CTraceContextPropagator正是该 SDK 注册的传播器见 client.ts#L221-L237 的 provider 配置因此propagation.extract/inject读写的就是标准traceparent头。这条链路解释了文章开头所说的机制服务端从入站请求提取 trace 头创建属于当前请求的 span再把更新后的上下文注入到所有出站请求头中——下游服务只要解析traceparent就能把自身操作挂到同一条 trace 上同时仍可为任意代码块开启新的嵌套 span。对于 Express 风格的框架Node SDK 还提供了通用的 middleware 与 errorHandler例如Handlers.middleware(options)会在每个请求上调用H.runWithHeaders(GET - /url, req.headers, ...)并自动附上http.request.method、http.route、http.response.status_code等语义约定属性Handlers.errorHandler则通过parseHeaders把错误关联回对应的会话与请求handlers.ts#L23-L42。第五步下游微服务接收 traceparent以仓库中的 Go 示例服务为例e2e/nextjs/go-service/main.goHighlight 的 Go SDK 基于 OpenTelemetry Go 模块初始化如下highlight.SetDebugMode(logger) highlight.SetOTLPEndpoint(http://localhost:4318) highlight.Start( highlight.WithServiceName(my-go-service), highlight.WithProjectID(1), highlight.WithSamplingRateMap(map[trace.SpanKind]float64{ trace.SpanKindServer: 1., }), ) defer highlight.Stop()Go 服务用对应框架的中间件接收上下文SDK 在sdk/highlight-go/middleware/下为多个常见框架提供了开箱即用的实现chifunc Middleware(next http.Handler) http.Handlerechofibergingorillamux以 chi 为例在路由注册前先套一层即可r.Use(highlightChi.Middleware)中间件内部使用 OTel 的propagation包从入站头提取traceparent使 Go 服务创建的 server span 直接成为 Next.js span 的子 span。从源码结构看Go SDK 还在 highlight.go#L90-L108 中定义了自己的 context keyHighlightRequestID、HighlightSessionSecureID用于在服务内跨层传递 Highlight 会话与请求标识实现与x-highlight-request头相同的会话关联能力。可用的初始化选项均为 functional options 风格见 highlight.go#L49-L88包括WithProjectID、WithServiceName、WithServiceVersion、WithEnvironment、WithSamplingRate与WithSamplingRateMap可按trace.SpanKind精细控制采样率。端到端可视化瀑布流视图完成上述接入后一次请求就会产生一条跨三段的 trace浏览器操作 → Next.js 服务端 span → Go 服务 span。在 Highlight 的 Trace 视图中瀑布流waterfall会清晰展示每个 span 的时间窗口与父子关系可以逐层展开定位是哪一段服务、哪一个操作耗时最长。由于会话 cookie 关联你还可以从 Trace 直接跳转回触发该请求的用户会话回放。与 OpenTelemetry、W3C 标准的关系需要强调两点这也是 Highlight 选择这套方案的原因W3C Trace Context 是开放标准traceparent/tracestate头的传播方式与任何可观测性厂商的追踪工具兼容接入 Highlight 不会造成供应商锁定——同一批头可以被 Jaeger、Zipkin、Honeycomb 等任何遵循该标准的基础设施消费。OpenTelemetry 提供了更厂商中立的 SDK 层Highlight 的 Node SDKhighlight-run/node与 Go SDK 都构建在官方 OpenTelemetry 包之上如 Node 端依赖opentelemetry/api、opentelemetry/propagator-b3体系中的W3CTraceContextPropagatorGo 端依赖go.opentelemetry.io/otel全家桶见 go.mod。这意味着你可以复用 OTel 的 API、语义约定和生态中间件同时把数据上报到 Highlight 的 OTLP 端点。关键文件索引内容路径客户端初始化组件cookie、代理模式sdk/highlight-next/src/next-client.tsx服务端 middlewarex-highlight-requestsdk/highlight-next/src/util/highlight-middleware.tsnext.config 包装与 OTLP 代理重写sdk/highlight-next/src/util/with-highlight-config.tsW3C 上下文提取/注入runWithHeaderssdk/highlight-node/src/client.tsExpress/serverless handlersdk/highlight-node/src/handlers.tsGo SDK 初始化与选项sdk/highlight-go/highlight.goGo 框架中间件chi/echo/fiber/gin/gorillamuxsdk/highlight-go/middleware/e2e 完整示例Next.js Go 服务e2e/nextjs/middleware.ts、e2e/nextjs/pages/api/page-router-trace.ts、e2e/nextjs/go-service/main.go小结在 Next.js 中落地分布式追踪的核心是“提取—注入”这一对称操作客户端 SDK 为请求自动附加追踪头并维护会话 cookiehighlightMiddleware把会话标识补齐到请求头withHighlightConfig配置 OTLP 代理API 路由经runWithHeaders/startWithHeaders从traceparent提取上下文、创建子 span 并注入出站头Go 微服务再用标准中间件提取上下文挂入同一条 trace。整条链路只依赖 W3C Trace Context 开放标准既能在 Highlight 中获得端到端瀑布流与会话回放的联动也能被任何兼容 OTel 的基础设施消费。赞分享可观测性后端【免费下载链接】highlighthighlight.io: The open source, full-stack monitoring platform. Error monitoring, session replay, logging, distributed tracing, and more.项目地址https://gitcode.com/gh_mirrors/hi/highlight点击查看免费下载相关推荐Plano 全链路追踪实战基于 OpenTelemetry 与 W3C Trace Context 的 AI Agent 可观测性指南Plano 全链路追踪实战基于 OpenTelemetry 与 W3C Trace Context 的 AI Agent 可观测性指南 本文以 Plano 的人工智能大模型后端API网关LLM 网关AI AgentAgent 编排可观测性AI 安全治理提示词注入防护GoFr 分布式追踪实战基于 W3C TraceContext 的跨服务全链路可观测GoFr 分布式追踪实战基于 W3C TraceContext 的跨服务全链路可观测 GoFr 在框架层内置了基于 OpenTelemetry 的分布式追踪能后端微服务云原生可观测性枪口飘上天别再忍保姆级开源压枪宏上手笔记让游戏外设自动化帮你稳住每一梭子枪口飘上天别再忍保姆级开源压枪宏上手笔记让游戏外设自动化帮你稳住每一梭子 还记得我第一次用满配 M416 打房区遭遇战前三发像模像样第四发准星开始画彩虹可观测性后端上一篇告别乱码5款Powerline字体打造完美终端显示效果下一篇react-redux-typescript-guide未来展望TypeScript与React生态系统发展趋势创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网站建设高端定制企业官网