Fastify 如何用 diagnostics_channel 订阅请求追踪事件?
【免费下载链接】fastifyFast and low overhead web framework, for Node.js项目地址: https://gitcode.com/GitHub_Trending/fa/fastify
在已经跑起来的 Fastify 服务里,你往往需要在不改动任何 handler 代码的前提下追踪请求生命周期:请求进入、进入异步阶段、出错、结束分别发生在什么时刻。Fastify v5 起原生支持 Node.js 内置的diagnostics_channel模块,按请求发布一组固定的追踪事件,外部包(如链路追踪工具)通过订阅这些 channel 即可拿到每个请求的request、reply和路由信息。本文基于仓库中的 Hooks 参考文档 与 v5 迁移指南 给出订阅、验证和初始化事件的完整做法。
Fastify 发布的事件有哪些
fastify.initialization事件在实例初始化时发布一次;其余五个事件按请求发布,遵循 Tracing Channel 命名。事件名、触发条件和 payload 如下(来自 Hooks.md 的 Diagnostics Channel Hooks 章节):
| 事件 | 触发条件 | payload |
|---|---|---|
fastify.initialization | 初始化时 | { fastify } |
tracing:fastify.request.handler:start | 始终触发 | { request, reply, route: { url, method } } |
tracing:fastify.request.handler:end | 始终触发 | { request, reply, route: { url, method }, async: Bool } |
tracing:fastify.request.handler:asyncStart | promise/async handler | { request, reply, route: { url, method } } |
tracing:fastify.request.handler:asyncEnd | promise/async handler | { request, reply, route: { url, method } } |
tracing:fastify.request.handler:error | 请求出错时 | { request, reply, route: { url, method }, error: Error } |
几个需要注意的行为:同一个请求的所有事件携带的是同一个消息对象实例;route.url是匹配到的路由模式(例如/collection/:id)而不是实际请求路径,route.method是 HTTP 方法(例如GET);handler 是async函数或返回Promise时才会触发asyncStart/asyncEnd。
订阅追踪事件并验证
下面的脚本把订阅逻辑放在创建 Fastify 实例之前(“instrumentation tools first”的常见方式),定义一个路由后监听随机端口并发请求验证。结构上参考了 v5 迁移指南的示例 和 同步请求测试、错误场景测试 的写法:
'use strict' const diagnostics = require('node:diagnostics_channel') const Fastify = require('fastify') diagnostics.subscribe('tracing:fastify.request.handler:start', (msg) => { console.log('start', msg.route.url, msg.route.method) }) diagnostics.subscribe('tracing:fastify.request.handler:end', (msg) => { console.log('end', msg.route.url, msg.route.method, 'async:', msg.async) }) diagnostics.subscribe('tracing:fastify.request.handler:error', (msg) => { console.log('error', msg.error) }) const fastify = Fastify() fastify.route({ method: 'GET', url: '/:id', handler: function (req, reply) { return { hello: 'world' } } }) async function main () { const server = await fastify.listen({ port: 0 }) const response = await fetch(server + '/7') console.log(response.status, await response.text()) await fastify.close() } main()运行后可以看到文档示例中给出的输出形态:start事件打印出路由模式/:id与方法GET;请求完成后end事件打印同样的route.url/route.method,并额外携带async布尔属性(此处为同步 handler,故为false)。请求本身返回200和{hello:"world"},说明订阅没有干扰正常处理。
验证事件行为时,以仓库测试的断言为准:
- 正常同步请求:
start与end各触发一次且携带同一消息对象,errorchannel 不触发(见 sync-request 测试)。 - handler 抛错(如
throw new Error('borked')):error事件触发且msg.error instanceof Error、error.message为'borked',随后end仍然触发;响应为500(见 error-request 测试)。 - async handler:在
start/end之外还会触发asyncStart与asyncEnd,四个事件同为同一消息对象(见 async-request 测试)。
用fastify.initialization订阅初始化事件
对于追踪类插件,更典型的做法是订阅fastify.initialization,在实例创建时给它挂上onRequest/onResponse钩子,而不是逐个请求手动管理 span。这是 Hooks.md 给出的示例(已按文档原样保留):
const tracer = /* retrieved from elsewhere in the package */ const dc = require('node:diagnostics_channel') const channel = dc.channel('fastify.initialization') const spans = new WeakMap() channel.subscribe(function ({ fastify }) { fastify.addHook('onRequest', (request, reply, done) => { const span = tracer.startSpan('fastify.request.handler') spans.set(request, span) done() }) fastify.addHook('onResponse', (request, reply, done) => { const span = spans.get(request) span.finish() done() }) })这段代码需要在创建 Fastify 实例之前加载(即文档所说的典型 “require instrumentation tools first” 方式),此时可以通过拿到的fastify实例添加钩子、插件、路由或做任何其他修改。tracer是追踪包自身提供的对象,需要替换为你自己包的实现。
限制与注意事项
- 文档明确提示:Node.js 的 TracingChannel 类 API 目前是实验性的,可能在 Node.js 的 semver-patch 版本中发生破坏性变更,升级 Node.js 后需要回归验证这些事件名和 payload 结构。
- 实现上,请求处理代码只在存在订阅者时才发布事件(见 handle-request.js 中对
channels.hasSubscribers的判断),没有订阅者时这些追踪事件不会发布,因此对未接入追踪的应用没有运行时影响;同理,fastify.initialization也没有订阅者时不会发布(见 init 测试)。 - 事件对象是同一实例的复用,不要跨请求缓存消息对象;跨请求保存数据(如 span)应使用
WeakMap以request为键,这正是fastify.initialization示例的做法。
需要继续深入了解钩子与追踪事件的配合方式时,可完整阅读 Diagnostics Channel Hooks 一节,以及 v5 迁移指南中 Diagnostic Channel support 章节。
【免费下载链接】fastifyFast and low overhead web framework, for Node.js项目地址: https://gitcode.com/GitHub_Trending/fa/fastify
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考