ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Midway 全入口统一异步追踪改造:OpenTelemetry 能力内建于 Core 的落地实践

Midway 全入口统一异步追踪改造:OpenTelemetry 能力内建于 Core 的落地实践 后端微服务云原生【免费下载链接】midway A Node.js Serverless Framework for front-end/full-stack developers. Build the application for next decade. Works on AWS, Alibaba Cloud, Tencent Cloud and traditional VM/Container. Super easy integrate with React and Vue. 项目地址https://gitcode.com/gh_mirrors/mi/midway点击查看免费下载导读本文基于 Midway 仓库中add-unified-entry-async-tracing变更提案系统讲解 Midway 如何将基于 OpenTelemetry 的追踪能力从独立组件midwayjs/otel合并进midwayjs/core实现 HTTP、WebSocket、gRPC、MQTT、消息队列与任务调度等全入口的统一 root span 自动创建、异步上下文连续传播、协议级透传回传与出口自动注入。读者将掌握该改造的完整任务拆解、三层架构设计、可自定义扩展机制以及从midwayjs/otel迁移到midwayjs/core的具体路径可直接用于理解并落地 Midway 应用的端到端链路追踪。一、背景为什么要把追踪能力统一收进 Core在本次变更之前Midway 的 tracing 能力分散在core与可选组件midwayjs/otel之间带来一系列问题见 proposal.mdHTTP、WebSocket、gRPC、MQTT 等入口的追踪行为不一致用户需要重复接入HTTP client、gRPC client、WS emit、MQTT publish 等出口缺少统一的上下文注入异步链路await/Promise/定时器/事件回调中的追踪上下文存在丢失风险用户需要自定义命名、提取、注入、采样策略时缺少统一扩展点midwayjs/otel是可选组件难以作为所有 framework/client 的默认能力基线。因此本次变更的核心决策是默认采用 OpenTelemetry 作为追踪标准Tracer API 创建 span、Context API 维护活动上下文、Propagation API 完成提取与注入并且Tracing API 内建于core不再依赖独立otel包见 design.md 的 Context 与 Key Decisions 部分。变更范围一览维度内容基础承载packages/coreFramework 入口层web、web-koa、web-express、ws、socketio、grpc、mqtt、kafka、rabbitmq、bull、bullmq、commander、cron、faas、one-shot、piscina、mcp出口客户端层axios、redis、cache-manager、oss、cos、tablestore、etcd、consul以及各消息/RPC 组件的 producer/client 侧Out of Scopepackages/api-bridge前端侧、packages/tags废弃组件本次不改二、总体架构核心编排 协议适配 扩展点design.md 将整个方案抽象为三层模型Core Entry Tracing Orchestrator核心入口追踪编排器请求进入框架入口时创建或恢复追踪上下文通过 OpenTelemetrycontext维护 active span并与 Midway async context manager 绑定确保跨异步边界上下文不丢失决策 root span 的生命周期开始、结束、异常标记提供默认 no-op 与可配置 OTel 执行器保证追踪失败不影响主流程。Protocol Entry Adapters协议入口适配层HTTP按 OTel propagator 从请求头提取默认 W3C Trace Context并在响应头回传追踪标识gRPC从 metadata 提取并在响应 metadata 回传WebSocket在连接与消息处理阶段按 OTel context 注入/继承上下文并暴露可回传映射。Customization Extension Points可自定义扩展点提取策略、注入策略、命名策略、属性增强、协议开关、OTel 扩展替换/包装默认 propagator 与 span processor。同时design.md 明确了几条关键决策决策 1默认自动化优先各入口默认启用自动 root span 异步上下文传播降低零配置成本决策 2扩展点前置且可组合自定义逻辑通过统一扩展点插入不要求 fork 入口实现决策 2A能力并入 coretracing API 与默认 OTel 实现统一放 core避免可选组件导致的依赖分裂决策 3失败安全追踪相关故障不应中断业务请求主流程失败时回退到最小可用行为决策 4协议一致语义不同协议保持一致的 entry start / handler run / finalize 生命周期语义。三、核心实现MidwayTraceService 与入口/出口编排 API改造后core 中提供统一的追踪服务MidwayTraceService实现在 packages/core/src/service/traceService.ts并通过 packages/core/src/index.ts 导出。3.1 配置项与默认值Config(tracing) protected tracingOptions: { enable?: boolean; onError?: throw | ignore; logOnError?: boolean; };初始化时合并默认值见init()this.tracingConfig { enable: true, // 默认开启追踪 onError: ignore, // 追踪出错默认忽略不抛给业务 logOnError: false, // 默认不打印追踪错误日志 ...(this.tracingOptions ?? {}), };也就是说业务侧只需在配置文件中给出tracing配置键即可覆盖默认行为tracing: enable: true onError: ignore # 可选 throw | ignore logOnError: trueonError: throw表示追踪异常时上抛ignore表示忽略并继续执行业务。这就是失败安全原则的配置化体现——默认ignore保证追踪故障绝不中断业务主流程。3.2 入口编排runWithEntrySpan入口追踪的核心方法为runWithEntrySpan(name, options, callback)它完成提取 → 建链 → 执行 → 回传 → 完结的完整编排// 关键逻辑摘录 const getter options.getter ?? this.defaultGetter; const setter options.setter ?? this.defaultSetter; let parentContext context.active(); if (options.carrier) { try { parentContext propagation.extract(context.active(), options.carrier, getter); } catch (err) { this.handleTraceError(err, extract entry context); } } return trace.getTracer(this.currentTracerName).startActiveSpan( name, { kind: options.kind ?? SpanKind.SERVER, attributes: spanAttributes }, parentContext, async span { // callback 执行成功后 // span.setStatus({ code: SpanStatusCode.OK }) // 若提供 responseCarrier则 propagation.inject(context.active(), responseCarrier, setter) // 异常时 // span.setStatus({ code: SpanStatusCode.ERROR }); span.recordException(err); throw err // finally 中 span.end() } );从中可以提炼出入口编排的关键语义提取从carrier请求头、metadata、消息头等按 OTel propagator 提取父级上下文优先恢复链路根 span以SpanKind.SERVER创建入口根 span回传处理完成后通过responseCarrier把当前上下文注入响应HTTP 响应头、gRPC 响应 metadata 等实现端到端关联状态标记成功置OK异常置ERROR并recordExceptionfinally中保证span.end()失败安全extract/inject任意一步异常都会被handleTraceError捕获默认忽略不中断业务。3.3 出口编排runWithExitSpan 与 injectContext出口侧核心方法为runWithExitSpan(name, options, callback)用于 HTTP client、gRPC client、MQTT publish、Kafka/RabbitMQ producer、Bull/BullMQ producer 等框架托管的出口调用// 关键逻辑摘录 const carrier options.carrier ?? {}; return trace.getTracer(this.currentTracerName).startActiveSpan( name, { kind: options.kind ?? SpanKind.CLIENT, attributes: spanAttributes }, async span { try { try { propagation.inject(context.active(), carrier, setter); // 出口自动注入 } catch (err) { this.handleTraceError(err, inject exit context); // 注入失败安全回退 } const result await callback(span); span.setStatus({ code: SpanStatusCode.OK }); return result; } catch (err) { span.setStatus({ code: SpanStatusCode.ERROR }); span.recordException(err as Error); throw err; } finally { span.end(); } } );同时提供轻量的injectContext(carrier, setter?)供无需创建子 span、只需把当前上下文注入到载体的场景直接使用。注意defaultGetter/defaultSetter对多种 carrier 形态做了兼容优先使用carrier.get/carrier.setHeader/carrier.set否则退化为普通对象属性写入这保证了同一套注入逻辑可以适配 headers、metadata、消息属性等不同协议载体。3.4 Trace 装饰器与 ctx.traceId在init()中服务通过decoratorService.registerMethodHandler(TRACE_KEY, ...)注册了Trace装饰器的方法级切面进入方法时以createSpan(options.metadata[spanName])创建 spanSpanKind.CLIENT方法成功置OK并end()异常置ERROR、recordException后重新抛出getTraceId()通过trace.getSpan(context.active())?.spanContext().traceId读取当前活动 span 的 traceId这正是ctx.traceId能力的来源。用户可直接从midwayjs/core导入Trace、MidwayTraceService即TraceService并通过ctx.traceId在请求上下文中读取链路标识。四、任务拆解从规格冻结到发布验证关联文档 tasks.md 是本次改造的完整实施清单全部勾选完成。以下按七个阶段还原其内容并补充实现细节。阶段 1规格与范围冻结确认入口与出口协议清单HTTP、WebSocket、gRPC、MQTT 及同类协议与术语定义冻结默认行为基于 OpenTelemetry 自动 root span、异步传播、透传与回传冻结失败安全原则与兼容边界不影响业务主流程。该阶段产出的规格文件位于 openspec/changes/add-unified-entry-async-tracing/specs包含request-entry-tracing、request-egress-tracing、tracing-customization、tracing-core-consolidation四份能力规格。阶段 2核心追踪编排实现在 core 定义统一入口追踪编排接口与生命周期钩子将入口追踪编排与 async context manager 对齐定义统一错误标记与 span 完结语义即上文runWithEntrySpan中的OK/ERROR/recordException/end流程将midwayjs/otel的核心 tracing API 合并到 core含Trace、TraceService、ctx.traceId移除packages/otel并完成对内引用替换。阶段 3协议入口接入17 个包HTTP请求提取 响应回传WebSocket连接/消息语义 上下文映射gRPCmetadata 提取与回传MQTT消息 metadata 提取与上下文恢复Kafka / RabbitMQ消息 headers 提取与上下文恢复Bull / BullMQ Workerjob metadata 恢复Commander / Cron / FaaS / OneShot / Piscina / MCP任务执行上下文追踪补充同类入口的最小一致性适配按协议能力映射。阶段 4协议出口接入HTTP clientheader 注入gRPC clientmetadata 注入WebSocket emit事件上下文注入MQTT publish消息属性注入Kafka / RabbitMQ producerheaders 注入Bull / BullMQ producerjob metadata 注入Redis / Cache / OSS / COS / Tablestore / Etcd / Consul 客户端出口注入定义出口注入失败时的回退与日志语义对应源码中handleTraceError的logOnError分支。阶段 5可自定义机制协议级开关与默认策略覆盖能力基于 OpenTelemetry propagator 的自定义提取/注入扩展点入口 出口自定义 span 命名与属性增强扩展点明确自定义优先级与回退规则。阶段 6测试与验证core 异步上下文连续性测试await/定时器/事件回调HTTP/WS/gRPC/MQTT 入口追踪测试Kafka/RabbitMQ/Bull/BullMQ/Commander/Cron/FaaS 等入口追踪测试各出口注入测试HTTP client/gRPC client/WS emit/MQTT publish/Kafka producer/RabbitMQ producerRedis/Cache/OSS/COS/Tablestore/Etcd/Consul 客户端出口注入测试明确并验证 Out of Scopeapi-bridge、tags不在改造清单自定义扩展点测试提取、注入、命名、属性运行受影响包测试pnpm -C package test。阶段 7文档与发布准备更新文档默认行为、配置方式、扩展示例补充迁移说明与兼容性说明提供从midwayjs/otel到midwayjs/core的迁移清单导入路径、配置键、装饰器执行规格校验openspec validate add-unified-entry-async-tracing --strict --no-interactive。五、规格需求解读入口追踪的四个核心要求request-entry-tracing 规格 定义了入口侧的四类需求5.1 全入口自动创建请求根追踪上下文系统基于 OpenTelemetry在 HTTP、WebSocket、gRPC、MQTT 及同类入口自动创建或恢复请求级根追踪上下文并在处理完成后正确结束HTTP请求进入入口时自动创建/恢复根 span结束时完成状态标记与span.end()WebSocket为连接级或消息级处理创建/恢复上下文并保证消息处理完成后生命周期正确结束长连接场景需区分连接级与消息级两类语义这正是 design.md 中多协议语义映射存在边界差异特别是 WS 长连接这一风险点的应对gRPC调用进入服务端入口时创建/恢复根 span调用完成时记录状态并结束MQTT消息进入订阅处理入口时创建/恢复根 span处理完成时记录状态并结束。5.2 异步链路上下文连续await/Promise 链式调用中后续异步步骤可读取与入口一致的 trace 上下文定时器与事件回调中回调内仍可读取请求入口追踪上下文。这正是 core 中把 OTel active context 与 Midway async context manager 绑定的意义所在也是阶段 6 中异步上下文连续性测试await/定时器/事件回调要验证的场景。5.3 协议级透传与回传从标准与兼容字段提取优先识别 W3C Trace Contexttraceparent/tracestate或兼容标识如x-trace-id并恢复上下文HTTP 响应回传追踪标识gRPC 与 WebSocket 通过 metadata 或上下文映射回传追踪标识MQTT 入口消息处理并转发/回推下游消息时按协议能力携带可关联的追踪标识。5.4 追踪失败不影响业务主流程某次请求的追踪初始化出现异常时请求处理流程继续执行系统仅记录可诊断错误信息——对应源码handleTraceError中onError: ignorelogOnError的组合逻辑。六、规格需求解读出口注入与安全回退request-egress-tracing 规格 定义了出口侧的两类需求6.1 全协议出口自动注入框架托管的出口调用自动注入当前 OpenTelemetry 追踪上下文出口类型注入位置HTTP clientW3C Trace Context 到请求头gRPC client追踪上下文到 gRPC metadataWebSocket emit事件元信息或约定字段MQTT publish消息属性或约定字段Kafka / RabbitMQ producer消息 headersBull / BullMQ produceraddJobToQueue/runJobjob metadata 或约定字段ServiceFactory 客户端Redis/OSS/COS/Tablestore/Etcd/Consul按客户端能力注入上下文或关联标识6.2 出口注入失败时安全回退注入过程抛异常时业务出口调用继续执行系统记录注入失败日志并标注协议类型——对应runWithExitSpan中 inject 的 try/catch 与handleTraceError(err, inject exit context)。七、可自定义机制扩展点与优先级tracing-customization 规格 定义了四类扩展能力可配置的入口/出口策略按协议启停默认入口追踪如关闭 WebSocket 入口追踪或出口注入如关闭 MQTT 出口注入其他协议不受影响自定义 span 命名策略未覆盖场景回退默认规则自定义提取与注入扩展点注册自定义提取器私有字段规则优先失败回退默认策略注册自定义 OTel propagator 替换默认 W3C Trace Context自定义响应回传注入逻辑写入响应头、metadata 或会话上下文保持协议兼容边界属性增强配置属性增强器如tenantId、region每个入口 span 创建后自动追加业务属性优先级与失败回退自定义扩展执行异常时记录错误并回退到默认实现请求主流程不中断。在源码层面这些扩展点对应runWithEntrySpan/runWithExitSpan的getter、setter、attributes、meta参数getter/setter支持传入自定义TextMapGetter/TextMapSetter或基于 propagator 的策略attributes携带midway.protocol等协议属性meta支持common/entry/exit三方向属性解析器resolveTraceMeta业务方可在同一解析器中按方向差异化追加标签。八、能力合并与迁移从 midwayjs/otel 到 midwayjs/coretracing-core-consolidation 规格 明确了合并后的能力契约Core 提供 Trace 装饰器与服务启用 tracing 后可直接从midwayjs/core获取Trace与MidwayTraceService不再依赖独立midwayjs/otel导入Core 提供 ctx.traceId请求上下文存在活动 trace 时可通过上下文对象读取traceId行为与原组件语义保持一致移除 midwayjs/otel 包并提供迁移路径这是BREAKING CHANGE升级说明须给出等价导入路径与配置/API 迁移映射。迁移清单对应 tasks.md 的 7.3 项归纳如下原 midwayjs/otel 用法迁移后 midwayjs/core 用法import { TraceService } from midwayjs/otelimport { MidwayTraceService } from midwayjs/coreimport { Trace } from midwayjs/otelimport { Trace } from midwayjs/core组件级配置统一为tracing配置键enable/onError/logOnErrorctx.traceIdctx.traceId语义不变由 core 内建服务提供迁移后所有 framework/client 仅依赖core的 tracing 接口不再感知组件化差异tracing 运行时能力保持语义兼容且随 core 成为默认能力基线。九、风险与缓解策略design.md 记录了三类已知风险及对应缓解扩展点过多增加配置复杂度→ 提供稳定默认值并限制必填项多协议语义映射存在边界差异尤其 WS 长连接→ 定义连接级与消息级两类语义并要求显式配置优先级异步上下文在第三方库中可能断链→ 定义降级策略与诊断日志保证业务可运行。这三条恰好对应了默认自动化优先 失败安全 协议一致语义的决策组合体现了默认零配置可用、异常不影响业务、边界显式声明的整体设计取向。十、验证方式与回归保证规格层面的验收对应 design.md 的 Validation Strategy包括协议级验收HTTP/WS/gRPC 至少各有一条入口链路验证异步连续性验收await、定时器、事件回调三个场景验证 trace 连续自定义扩展验收覆盖提取器、命名器、属性增强、协议开关四类扩展点回归验收关闭该能力时保持现有行为兼容。实施层面可对受影响的包逐个运行测试命令验证例如pnpm -C packages/core test pnpm -C packages/web test pnpm -C packages/grpc test并最终通过openspec validate add-unified-entry-async-tracing --strict --no-interactive完成规格一致性校验见 tasks.md 的 7.4 项。小结本次add-unified-entry-async-tracing变更让 Midway 的追踪能力实现了三个层面的统一API 统一Trace、MidwayTraceService、ctx.traceId全部内建于 core、入口统一HTTP/WS/gRPC/MQTT/消息队列/任务调度自动建链与异步传播、出口统一HTTP client、gRPC client、WS emit、MQTT publish、Kafka/RabbitMQ producer、Bull/BullMQ producer 及 ServiceFactory 客户端自动注入。配合协议级开关、自定义提取/注入/命名/属性增强扩展点与失败不影响主流程的安全回退原则开发者可以零配置获得端到端链路追踪能力同时保留充分的定制空间。赞分享后端微服务云原生【免费下载链接】midway A Node.js Serverless Framework for front-end/full-stack developers. Build the application for next decade. Works on AWS, Alibaba Cloud, Tencent Cloud and traditional VM/Container. Super easy integrate with React and Vue. 项目地址https://gitcode.com/gh_mirrors/mi/midway点击查看免费下载相关推荐Midway 全入口异步链路追踪内建 Core基于 OpenTelemetry 的统一入口/出口追踪架构与实践Midway 全入口异步链路追踪内建 Core基于 OpenTelemetry 的统一入口/出口追踪架构与实践 导读 Midway 在 v4 时代将原本分散在后端微服务云原生Midway 统一入口异步追踪基于 OpenTelemetry 的 Core 内建全协议 Tracing 架构解析Midway 统一入口异步追踪基于 OpenTelemetry 的 Core 内建全协议 Tracing 架构解析 Midway 作为面向 Node.js 前后端微服务云原生Loki 仓库内 vendored MinIO Go Client SDKminio-go/v7快速上手指南安装、客户端初始化与 S3 文件上传实战Loki 仓库内 vendored MinIO Go Client SDKminio go/v7快速上手指南安装、客户端初始化与 S3 文件上传实战 Mi后端微服务云原生上一篇如何使用Spring Roo Shell实现零代码生成Java应用完整教程下一篇GARbro视觉小说资源提取工具完全攻略新手到高手一步到位创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表