
可观测性后端【免费下载链接】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点击查看免费下载Vercel Edge Runtime 以极低的冷启动延迟和按量计费的成本优势正成为 Node.js serverless 之后最受关注的服务端运行形态但它的非 Node.js 兼容特性让以 OpenTelemetry 为代表的观测 SDK 面临无法部署、数据丢失的双重挑战。本文以 highlight.io 的 Edge Runtime 支持实现为线索剖析highlight-run/cloudflare与highlight-run/next两个 SDK 如何通过 fork、补丁与窥探内部状态等手段在边缘运行时中完成 trace、log、error 与 metric 的可靠上报。读完你将理解 Edge 运行时的底层约束、highlight 的解决思路以及如何在 Vercel Edge Function 中正确接入并等待观测数据落盘。为什么选择 Vercel Edge冷启动、延迟与成本的账本Vercel Edge Runtime 之所以被视为下一个大事件根本原因在于它构建在 Cloudflare Workers 之上而后者恰好解决了传统 serverless 的两大痛点冷启动与网络延迟。可以把 Cloudflare Workers 类比为浏览器里的 Web Workers API浏览器中一个 JavaScript 主线程可以派生出近乎无限数量的 Web WorkerCloudflare 做了同样的事情——由单个 Node.js 进程派生出近乎无限数量的 Cloudflare Worker。差异在于浏览器中的每个 Worker 都运行在用户自己的设备上而 Cloudflare 的 Worker 会就近部署到其全球数据中心的任意位置。这带来三个可量化收益告别冷启动函数实例常驻在边缘节点请求到来时无需重新拉起运行时更低的网络延迟代码距离用户更近往返时间显著缩短极低的边际成本每个 Worker 进程的资源开销极小Cloudflare 因此能维持非常低的定价即使叠加 Vercel 的加价整体成本依然有竞争力。为什么不选 Vercel Edge兼容性是最大的隐性成本Vercel Edge 的速度与成本是有代价的Edge Worker 明确不是 Node.js 兼容的。这一点在初期可能并不显眼但当你尝试把一个依赖 Node API 的函数部署为 Edge Function 时会遇到形形色色的X API is not supported报错。背后的机制是凡是被打包进 Edge Function 的每一行代码都必须 Edge 兼容Vercel 会在构建阶段静态分析你的代码排查违规的 API 调用。因此即使某行不兼容代码在运行时永远不会被执行Vercel 也不会允许你部署它。如果你必须使用某个不兼容的包只有两条路整体改用 Node.js Runtime放弃 Edge 的低延迟与低成本优势本地打补丁使用patch-package或yarn patch、pnpm patch等包管理器自带的补丁命令在本地修改依赖后重新构建。highlight 恰恰选择了第二条路详见下文这条路有趣的地方在于你不仅要维护补丁本身还要保证补丁在 CI/CD 中可复现、能随包一起发布。highlight 如何实现 Edge 支持fork、补丁与精心打包highlight 的 Edge Runtime 支持建立在两个关键工程决策之上。决策一forkopentelemetry-sdk-workers并发布为自有包团队采用了 Richard SimpsonGitHub 用户 RichiCoder1开源的opentelemetry-sdk-workers包作为基础。他们将其 fork 并做了一些关键修改移除了其中 Edge 不兼容的 API 调用然后以highlight-run/opentelemetry-sdk-workers的名字发布到 NPM供highlight-run/cloudflare和highlight-run/next两个 SDK 消费。决策二不 fork opentelemetry-js改用yarn patch打补丁opentelemetry-js官方仓库中存在多处 Edge 不兼容的 API 调用。团队刻意抵制了 fork 它的冲动——因为这套代码库体量太大维护成本过高。取而代之的方案是在 CI/CD 流水线中使用yarn patch对不兼容的 API 调用逐一打补丁打包时格外小心确保被打过补丁的文件作为highlight-run/next的一部分发布到 NPM。也就是说最终用户拿到的是补丁后的 OTEL而无需自行处理任何兼容性问题。这一点可以从 sdk/highlight-next/package.json 的exports字段得到印证highlight-run/next/server在不同运行时条件下指向不同的构建产物——edge、edge-light、worker、workerd条件全部解析到./dist/server.edge.js而常规require/import才指向 Node.js 构建。为什么这些补丁是必要的serverless 生命周期与 OTEL 的后台导出范式要理解为什么需要如此大费周章必须看清两个运行时的本质差异。serverless线程一释放进程就终止Serverless 函数在线程空闲的瞬间就会被关闭。如果你没有在等待一个异步过程或者没有正在执行的命令你的 Node.js 或 Edge Worker 随时可能被提前终止。这决定了任何稍后再说的异步行为都不可靠。OTEL为常驻服务端而生的后台导出模型opentelemetry-js简称 OTEL假设自己运行在标准的、永续在线的 Node.js 运行时中。它天生是为 express.js 这类基于服务器的环境设计的其核心范式是后台异步数据导出span 被采集后进入队列由后台处理器批量导出导出过程并不被await。正是这个范式导致了一个严重的实际问题在测试期间highlight 的大部分错误根本没有到达服务器。原因在于——即使代码里写了await OTEL 的 flush 函数该 Promise 确实 resolve 了但进程随后立刻关闭而此时 OTEL 还排着队等待把数据 POST 到 highlight 的服务器。await只保证了flush 调用返回并未保证导出请求真正完成。解法在 TypeScript 的假私有里偷数据幸运的是TypeScript 并不会真正让类的内部成员变为私有。你可以给属性标上private但代码一旦被打包就可以在那一行加上//ts-ignore绕过类型检查去读取内部数据。highlight 正是这么做的窥探 OTEL 的内部状态等待其所有 Fetch 调用全部完成之后才释放 serverless 进程。团队还特别说明所依赖的这些内部实现是稳定多年的老代码短期内不太可能变更——这是敢扒内裤式集成的前提。源码印证一highlight-run/cloudflare的 Fetch 化导出器highlight-run/cloudflare是整个 Edge 方案的地基。其入口 sdk/highlight-cloudflare/src/index.ts 仅导出H对象与HighlightEnv类型全部实现集中在 sdk.ts。自定义导出器用 fetch 替代 Node 网络栈OTEL 默认的 HTTP 导出器依赖 Node 的http/https模块这在 Edge 上不可用。highlight 的解决方式是手写两个基于 Webfetch的导出器见 sdk/highlight-cloudflare/src/exporter.tsOTLPTraceExporterFetchL20-L61实现SpanExporter接口通过JsonTraceSerializer.serializeRequest序列化 span 批量再用fetch(this.url, { method: POST, headers: { Content-Type: application/json }, body })上报OTLPMetricExporterFetchL63-L109同构实现负责/v1/metrics端点。两个导出器的shutdown()与forceFlush()都是 noop唯一真正的动作就是那一次fetch——这是整个 Edge 兼容性的核心。SDK 初始化完整的数据管线sdk.ts 的H.init组装了整条观测管线设置全局传播器W3CBaggagePropagatorW3CTraceContextPropagator组成的CompositePropagator支持 W3C 分布式追踪上下文默认 OTLP 端点为https://otel.highlight.io:4318可用HIGHLIGHT_OTLP_ENDPOINT环境变量覆盖导出器配置concurrencyLimit: 100、timeoutMillis: 5_000BatchSpanProcessor参数maxExportBatchSize: 100、maxQueueSize: 1_000、exportTimeoutMillis与scheduledDelayMillis均为 5 秒使用AlwaysOnSampler全量采样Resource携带service.name、highlight.project_id、telemetry.distro.name/version等属性monkeypatch 五个 console 方法debug、error、info、log、warn见 L42-L48每次调用都会创建一个highlight.logspan 并附加log.severity、log.message、exception.stacktrace、highlight.project_id等事件属性——这就是 Edge 环境下日志采集的实现方式。关键flush 与 runWithHeadersH.flushL262-L277依次对 tracerProvider 和 meterProvider 调用forceFlush()并捕获无内容可刷时抛出的异常。这正是应对 serverless 提前终止的关键 API。H.runWithHeadersL279-L329则承担了请求级链路管理从请求头提取入站 header用propagation.extract还原父级 trace 上下文解析X-Highlight-Request头得到secureSessionId以/分割取第一段以startActiveSpan开启 span把 sessionId 写入 span 属性处理完回调后若返回的是Response对象则把 HTTP 状态码与响应头除set-cookie外写入 span 属性异常时recordException后重新抛出finally中结束 span。缺失性能 API 的补丁sdk.ts 顶部有一条特殊导入import ./navigator注释写明Required to patch missing performance API in Cloudflare Workers对应文件 sdk/highlight-cloudflare/src/navigator.ts——这是 fork 之外又一个Edge 不兼容即打补丁的具体例证。源码印证二highlight-run/next的 Edge 集成层Edge 方案的用户侧入口在highlight-run/next。其 Edge 构建产物入口为 sdk/highlight-next/src/server.edge.ts对外暴露H来自 util/highlight-edge.tshighlightMiddleware来自 util/highlight-middleware.tsisNodeJsRuntimeEdgeHighlight仅在process.env.NEXT_RUNTIME edge时返回包装器否则直接抛错同时PageRouterHighlight、AppRouterHighlight在 Edge 运行时会显式抛出不要在 Edge runtime 使用的错误——即文章所述的手动端点包装 API 三件套。包装器的执行流util/with-highlight-edge.ts 展示了 Edge 包装器的完整逻辑若配置了enableFsInstrumentation打印警告并将其置为false文件系统插桩在 Edge 不可用调用H.initEdge(env)完成初始化用H.runWithHeaders(${request.method} - ${request.url}, request.headers, ...)包裹原 handler并为 span 打上next.runtime: edge属性关键在finally块每次请求结束都await H.flush()——这正是把后台导出强制变成请求内同步落盘以对抗 serverless 提前终止的核心手段。initEdgeEdge 与 Cloudflare 的桥接util/highlight-edge.ts 的initEdge把 Node 风格配置翻译成 Cloudflare 风格projectID→HIGHLIGHT_PROJECT_IDotlpEndpoint→HIGHLIGHT_OTLP_ENDPOINT对serviceVersion、enableFsInstrumentation输出不支持警告最终调用CloudflareH.init(cloudflareEnv, env.serviceName)。同时该文件还定义了一系列显式抛错的占位方法如H.init、H.stop确保在 Edge 运行时误用 Node 专属 API 时立即得到清晰报错。度量方面则统一走recordMetric通道所有计数器、直方图、UpDownCounter 都被映射为 gauge 记录并以highlight.session_id、highlight.trace_id标签关联会话与请求。Middleware 兜底补齐会话头util/highlight-middleware.ts 提供的highlightMiddleware会在请求缺少x-highlight-request头时从sessionSecureIDCookie 读取会话 ID 并写入该头——确保进入 Edge Function 的请求都能带上会话上下文供runWithHeaders提取。端到端示例仓库的 e2e/cloudflare-worker/src/index.ts 给出了最小可运行的接入范式在 Worker 的fetch入口调用H.init({ HIGHLIGHT_PROJECT_ID: 1 }, e2e-cloudflare-app)用H.runWithHeaders(worker, request.headers, doRequest)包裹业务逻辑catch 到异常时H.consumeError(e)后重新抛出业务代码里console.log会被 SDK 的 monkeypatch 自动采集为日志 spanH.setAttributes则可附加自定义属性。这正是 Highlight 在 Vercel Edge 场景下的同构用法。未来演进从手动包装到自动插桩当前highlight-run/next依赖手动 API 端点包装即用AppRouterHighlight、PageRouterHighlight、EdgeHighlight逐个包裹端点。原文档作者规划了两条自动化路线可以作为后续跟踪的方向基于next.config.js的自动包装利用 Rollup 与静态分析在 Next.js 编译阶段自动生成新端点、包装它们并替换原有代码。设想很诱人但作者也坦承极其复杂且易出错需要大量验证才能成熟发布 codemod基于 jscodeshift 编写一次性代码迁移脚本直接改写代码库——把新包装的 API 端点提交进仓库无需任何运行时魔法缺点是每新增端点后需要重跑一次或者后续改为手动包装。两条路线都尚未在仓库中落地是否实现取决于highlight-run/next的社区采纳情况。结语Edge 兼容的本质是重新定义异步边界回顾 highlight 的 Edge 支持方案可以提炼出三条可复用的工程经验兼容性不是二选一而是可修补的通过 fork 小型依赖opentelemetry-sdk-workers、对大型依赖打补丁yarn patch修补 opentelemetry-js、手写 fetch 化导出器可以把原本 Node 专属的观测栈移植到 Edge 上serverless 下必须显式控制导出时机把 OTEL 的后台导出范式改写为请求结束前的await flush()是保证数据不丢的关键——with-highlight-edge.ts 的finally { await H.flush() }就是这条原则的代码化身内部 API 可以依赖但要有边界//ts-ignore偷读 OTEL 内部状态的做法依赖的是多年稳定的老代码这一前提属于有风险但有明确理由的技术债。对开发者而言如果你正在 Vercel 上部署 Edge Function且需要 error monitoring、session replay、logging 与分布式追踪能力highlight-run/next的EdgeHighlighthighlightMiddleware组合就是当下可以直接采用的接入方式而其底层 highlight-run/cloudflare 的 sdk.ts 与 exporter.ts 也是理解Edge 环境下 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点击查看免费下载相关推荐探索 Vercel Edge Runtime下一代边缘计算框架探索 Vercel Edge Runtime下一代边缘计算框架 是一个创新的开源项目它旨在提供一种全新的、高性能的、低延迟的方式来运行 Web 应用和服务小爱音箱接入 ChatGPT 完整指南用 MiGPT 4 个阶段跑通专属语音助手小爱音箱接入 ChatGPT 完整指南用 MiGPT 4 个阶段跑通专属语音助手 MiGPT 是个把小爱音箱接入 ChatGPT、豆包等大模型的开源项目装上可观测性后端终极指南WebAssembly边缘函数如何赋能Vercel与FastlyServerless架构终极指南WebAssembly边缘函数如何赋能Vercel与FastlyServerless架构 WebAssembly简称Wasm作为高性能的二进制指令编程语言上一篇Pwndbg配置迁移验证工具检查新配置正确性下一篇如何快速掌握AI视频分析面向初学者的完整实战指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考