AI 工程实践
OpenTelemetry GenAI 真实链路实验:24 个 Span 如何穿过 Collector 到达 Jaeger
用真实 OpenTelemetry Node SDK、OTLP/HTTP、Collector 和 Jaeger 查询 API,验证 GenAI span 的批处理、采样、导出失败、属性治理、业务终态关联与内存保留边界。
时间与证据
2026 年 7 月 15 日,我把上一篇 OpenTelemetry GenAI Trace 合同实验 从进程内 evaluator 推进到一条实际运行的遥测链路。新的问题不是“这组 JSON 是否满足本地 schema”,而是:真实 Node SDK 生成的 span 经过 BatchSpanProcessor、OTLP/HTTP、Collector 处理器和 Jaeger 存储后,查询端还能否给出同一棵树、同一组受控属性和可判定的失败终态。
本文的“真实”只修饰遥测管线。SDK、exporter、Collector 容器、Jaeger 容器、Prometheus metrics 和查询 API 都实际运行;Agent、模型、检索、工具调用和业务结果仍由实验代码合成。实验没有请求模型,没有向量数据库,没有真实用户,也没有连续运行。证据等级因此是 reproduced,不能写成 field-tested。
上游身份全部固定:OpenTelemetry JavaScript package 指向完整 commit 40d67b7690a61bd9af0a4e5b5b9f4a14b11fc50e;Collector Contrib 使用 0.156.0 的多平台镜像 digest sha256:125bdbeb...8108,镜像标签内的 release commit 为 aa158b23c8f89d795b21a05a49b3978565dfebd4;Jaeger 使用 2.19.0 digest sha256:ede48642...c68b,运行日志报告 commit 48f1e46121d1c428a6c989d08e7d69df4bccae82。固定结果还保存当前 linux/arm64 image ID、大小和输入文件哈希,避免用移动 tag 或后来改过的配置解释旧结果。
文档证据与运行证据承担不同职责。Node SDK README、ratio sampler 源码、BatchSpanProcessor 源码和 OTLP HTTP exporter 文档解释组件设计;本文是否真的收到 24 个 span,只由 Collector metrics 和 Jaeger 查询响应证明。
固定工件位于 labs/genai-otel-integration/:
compose.yaml固定 Collector 与 Jaeger 镜像 digest、端口和网络边界;config/otel-collector.yaml固定 receiver、memory limiter、属性删除、batch 和 exporter;src/emit.mjs使用真实 SDK 生成 Agent、采样、业务和 exporter 故障四组输入;src/run-experiment.mjs从干净容器状态启动、查询、重建 Jaeger 并生成报告;test/report.test.mjs用 9 个测试检查冻结结果、自哈希、敏感值排除和版本身份;results/2026-07-15-results.json保存本次 canonical query evidence 和所有终态。
结果文件为 21,970 bytes,SHA-256 是 f97f23147880aa0e437b93750e800290c7fb14afb62e9e7f6db5801c04e779a9。报告加入自引用字段之前的 payload SHA-256 是 0c6475c2f8d67d56202455657fa4c5eae80a17b7db9755c7a20a71500eb7d7ef。前者固定磁盘字节,后者固定报告语义载荷,两者都不能替代具体断言。
为什么合成合同通过还不够
上一篇实验已经能拒绝 orphan span、错误 kind、缺少 error.type、未知价格、业务错链和内容泄漏,但所有输入都在同一 Node.js 进程中读取 JSON。中间没有序列化协议、异步 batch、网络、Collector processor、后端映射和查询模型。因此至少有六类源内测试看不到的问题:
- SDK 的 sampler 可能在 span 进入 evaluator 之前就不记录它;
- BatchSpanProcessor 可能因为 queue、batch 或 flush 行为没有把全部 span 交给 exporter;
- OTLP exporter 回调失败不等于业务代码一定捕获或处理失败;
- Collector 可能删除、改写或丢弃属性,也可能因后端不可达重试或失败;
- Jaeger 的 tag、status 和 parent reference 映射可能与应用内对象不同;
- 应用认为发送成功,权威后端仍可能查询不到,尤其在异步管线和存储重建后。
所以本次验收不以“SDK 没报错”结束。每个预期 trace id 都必须由 Jaeger HTTP API 反查;采样 drop 与 exporter failure 也必须由同一个权威接口确认不存在。Collector metrics 用来解释中间计数,不能替代最终查询。
实验设计
一条链路,两个批处理边界
运行拓扑如下:
NodeSDK
-> BatchSpanProcessor(maxExportBatchSize=4)
-> OTLPTraceExporter(http://127.0.0.1:24318/v1/traces)
-> Collector OTLP receiver
-> memory_limiter(128 MiB)
-> attributes/governance
-> batch(send_batch_size=5, timeout=200 ms)
-> OTLP HTTP exporter(http://jaeger:4318)
-> Jaeger 2.19 memory storage
-> GET /api/traces/{traceId}
应用 processor 的 batch 上限固定为 4,schedule delay 固定为 60 秒,脚本通过 forceFlush() 主动完成本轮输出;Collector 再按 5 个 span 一批处理,剩余不足 5 个的尾批由 200 ms timeout 发送。两个 batch 是不同故障域:应用 batch 影响进程内 queue 与 exporter 调用,Collector batch 影响后端请求与 Collector 内存。只观察其中一个会漏掉另一层丢失。
实验没有把完整 Jaeger API 响应直接固定,因为 start time、duration 和内部 process id 会随运行变化。查询器只保留:
traceId
spanId
operationName
parentSpanIds
serviceName
tags
这足以检查树、服务和属性,又不会让微秒级 duration 使每次重放都产生假差异。删除可变字段不等于忽略它们的质量;延迟和时钟正确性只是本篇没有声称验证的另一项实验。
30 个 SDK span 尝试如何分成 24 个后端 span
四个独立 Node 进程共创建 30 个 span 尝试:
| 进程 | 创建或尝试 | 进入正常 exporter | Jaeger 终态 |
|---|---|---|---|
agent |
18 span / 14 traces | 18 | 14 traces 可查 |
sampling |
10 root traces | 5 | 5 可查,5 不存在 |
business |
1 root trace | 1 | 1 可查 |
failure |
1 root trace | 1 次失败 export | 不存在 |
| 合计 | 30 | 24 成功导出 | 20 traces / 24 spans 可查 |
agent 进程包含一条四 span 成功树、一条两 span model timeout 树和十二条独立 batch probes,所以 18 个 span 只形成 14 条 traces。sampling 创建十个合法固定 trace id,其中五个由 SDK sampler 直接返回 NOT_RECORD。failure span 被 processor 交给 OTLP exporter,但 endpoint 没有监听者,因此没有进入 Collector。
固定 ID generator 只用于让采样和查询可重放,不用于伪造生产分布。成功采样 id 的 XOR 累积值低于 0.5 阈值,drop id 高于阈值;决定仍由 SDK 的 TraceIdRatioBasedSampler(0.5) 作出,业务代码只读取 span.isRecording() 记录分支。
属性治理采用明确删除列表
Collector attributes processor 配置六个 delete action:
actions:
- key: gen_ai.input.messages
action: delete
- key: gen_ai.output.messages
action: delete
- key: gen_ai.tool.call.arguments
action: delete
- key: gen_ai.tool.call.result
action: delete
- key: app.user.id
action: delete
- key: app.request.id
action: delete
成功 Agent 根故意带入一个 .invalid 保留域 sentinel、合成 user id 和 request id;tool span 带入合成 arguments。它们不是客户数据,也不是凭据。验收只检查处理后的 Jaeger evidence:六个 key 都不应存在,sentinel 原值也不能进入冻结结果。同时 app.tenant.tier=enterprise 作为低基数维度保留,app.transaction.id 作为业务 join 键保留。
这里不能把“Collector 已删除”写成“敏感内容从未离开应用”。值仍经过 SDK、OTLP 序列化和 localhost 网络才被删除。更合理的生产策略是 SDK 默认不采集 raw content,Collector allowlist 或 delete 作为第二道防线;本负例只是证明下游治理规则真实执行。
业务结果使用独立服务与独立 trace
成功 Agent 根记录 app.transaction.id=txn-otel-integration-001,技术 status 保持 OpenTelemetry 推荐的成功默认值 UNSET。另一个 business-state-reconciler 服务在独立 trace 中记录同一 transaction id,但业务结果为:
app.business.outcome = rejected
app.business.reason_code = policy_denied
查询器分别从两个 trace 取值,再按 transaction id join。它不把业务结果伪装成 Agent 的子 span,因为真实系统中的最终业务状态可能在异步队列、数据库事务或人工审批后才形成。独立 trace 更能暴露“技术调用已经结束,业务结论后来才确定”的边界。
结果
9 个固定工件测试全部通过,结果摘要如下:
| 指标 | 固定结果 | 能支持的结论 |
|---|---|---|
| 正常 exporter 成功交付 | 24 spans | 三个正常进程实际完成 OTLP export |
| Collector accepted / sent / failed | 24 / 24 / 0 | 本轮 Collector 管线没有计数丢失 |
| Collector batch | 5 批 / 24 spans | 4 次 size trigger,1 次 timeout trigger |
| 预期 / 实际可查 traces | 20 / 20 | 正常路径最终进入 Jaeger 查询面 |
| SDK 50% sampler | 5 record / 5 drop | 固定 trace id 下两个分支都到达 |
| dropped trace 查询 | 0 / 5 found | 未记录项没有出现在后端 |
| exporter 不可达 | ECONNREFUSED |
flush 暴露失败,后端无对应 trace |
| Collector 删除 key | 6 / 6 | 明确列出的内容与高基数字段未进入查询证据 |
| 业务 join | technical success + rejected | 技术健康不能代替业务完成 |
| memory storage 重建 | true -> false | 容器替换会丢失内存 trace |
24 个 span 在两个 batch 层都守恒
应用层实际 exporter batch 为:
agent [4, 4, 4, 4, 2]
sampling [4, 1]
business [1]
八次应用 exporter 调用合计 24。Collector metrics 随后报告 receiver_accepted_spans=24、exporter_sent_spans=24、exporter_send_failed_spans=0。Collector batch histogram 的 sum 为 24、count 为 5,其中四次达到 size 5,最后四个 span 由 timeout 触发。
最后,Jaeger 的二十条 trace 恰好包含二十四个 span。这个等式同时跨越应用 queue、HTTP 请求、Collector receiver、两个 processor、Collector exporter、Jaeger receiver、memory store 和 query conversion。它仍不是 exactly-once 证明:本轮没有重试、重复请求或并发 race;计数相同只能说明这次受控执行没有观察到丢失或重复。
Head sampling 的五个 drop 在后端得到确认
ratio sampler 的十个输入交替排列,输出严格为五个 recording 与五个 non-recording。五个 recording span 被 [4, 1] 两批导出并可查;五个 drop id 对 Jaeger 的逐条查询均返回 HTTP 404,脚本把 404 明确解释为权威未找到,其他 HTTP 错误仍会使实验失败。
这个细节来自第一次运行的真实失败样本:脚本原先假定“trace 不存在”也会得到 HTTP 200 和空 data,Jaeger 实际返回 404。第一次 run 因此停止在第一个 dropped trace 查询,没有把 API 假设错误误记为实验失败。只修改 404 解释后,同一链路重跑通过。运行行为优先于源内猜测。
固定 5/5 不能外推生产 50% 的统计质量。生产 trace id 通常随机,短窗口计数会波动;更重要的是 head sampling 在错误发生前决定,可能系统性丢掉低频错误、长尾租户或稍后才变成 rejected 的业务结果。本文只证明 SDK 分支与查询终态,没有证明 0.5 是合理采样率。
Exporter 失败同时满足“报错”和“无写入”
负向控制只改变一项:把 endpoint 从 24318 改为无人监听的 24319。OTLP exporter 收到一个 span,回调 resultCode=1;BatchSpanProcessor.forceFlush() 抛出:
connect ECONNREFUSED 127.0.0.1:24319
测试随后用固定 trace id 查询 Jaeger,结果不存在。只看到异常还不够:如果 span 已在重试前局部写入,简单重试可能产生重复;只看到后端无数据也不够:应用若吞掉 exporter 错误,业务线程可能继续把遥测缺失当成健康。本例同时确认两个终态。
Node SDK 默认不会让每次遥测导出失败都自动转化为业务请求失败;这通常是正确的可用性取舍。工程责任转移到 metrics、queue、告警和观测自身的 SLO。生产 Collector 还应考虑 persistent queue、重试上限和容量隔离,否则“观测系统故障”可能反过来拖垮业务进程。
六个 key 被删除,但治理只覆盖已知 schema
Jaeger query evidence 的全部 tag key 集合中不存在六个删除项,合成 sentinel 字符串也没有进入结果文件;低基数 tenant tier、GenAI operation、model、token、tool name 和 transaction id 均保留。这个结果证明属性策略没有把所有分析维度一起删掉。
但 delete list 天然有 schema 漂移风险。如果框架把 gen_ai.input.messages 改名,把内容嵌入 event,或团队新增 prompt.preview,旧规则不会自动识别。高基数字段也不只 user/request id;conversation、tool call、document id、error message 和自由文本 reason code 都可能放大索引。真实治理需要:
- SDK 层 schema allowlist;
- Collector 层删除、转换和 cardinality 监控;
- 后端权限与索引配置;
- 短保留的隔离内容评测存储;
- schema 版本和迁移测试。
本文没有因为 6/6 就声称 PII 合规率为 100%。
技术成功仍对应业务 rejected
Agent 成功根 span 在 Jaeger 中没有 ERROR,查询器将缺省技术状态解释为 UNSET;业务 reconciler trace 则返回 rejected/policy_denied。两条 trace 的 transaction id 完全一致,所以固定 relation 是:
technical_success_business_rejected
这比上一篇纯 JSON join 多了一层证明:关联字段确实经过 SDK、Collector 和 Jaeger tag 映射后仍可查询,不是 evaluator 读取同一文件得到的自洽结果。它仍没有证明 business producer 权威;生产 join 还需要业务数据库主键、事件版本、幂等键、发生时间、最终状态来源和 reconciliation 水位。
Memory retention 用失败终态说明边界
Jaeger v2.19 all-in-one 配置在本轮使用 memory storage。脚本先查询成功 Agent trace,得到 preRestartFound=true;随后停止、删除并重新创建 Jaeger 容器,等待 query API ready,再查询同一 trace id,得到 postRestartFound=false。
这个负例把“内存后端不持久”从配置推断变成运行证据,也阻止文章把一次漂亮的查询截图冒充可运营存储。它没有测量按天 TTL,也没有比较 Elasticsearch、OpenSearch、ClickHouse 或 Badger。生产 retention 必须重新定义容量、TTL、索引、备份、恢复时间和删除合规,而不是把本轮 0 trace 当成后端选型结论。
复现与验证
宿主机需要 Docker Engine 与 Compose,且本机端口 24318、23133、28888、26686 和故障探针端口 24319 未占用。从仓库根目录运行:
npm ci
npm run lab:otel-integration:run
npm run lab:otel-integration:test
第一条命令安装 lockfile 中的固定 SDK 版本。第二条从干净 Compose 状态执行完整实验,默认输出 /tmp/younis-ai-lab-genai-otel-integration.json,结束时删除容器、网络和 volume。第三条验证已提交的固定工件。
比较 checked 与 replay:
jq 'del(.capturedAt, .payloadSha256)' \
labs/genai-otel-integration/results/2026-07-15-results.json \
> /tmp/genai-otel-checked.json
jq 'del(.capturedAt, .payloadSha256)' \
/tmp/younis-ai-lab-genai-otel-integration.json \
> /tmp/genai-otel-replayed.json
diff -u /tmp/genai-otel-checked.json /tmp/genai-otel-replayed.json
结果还固定四个输入身份:Compose 617 bytes、Collector config 1,079 bytes、emitter 7,950 bytes、runner 13,343 bytes,并分别保存 SHA-256。任何输入变化都应生成新工件并解释差异,不能覆盖旧 JSON 后继续引用旧 hash。
失败与边界
第一,业务负载仍是 synthetic。真实的是 telemetry runtime,不是 Agent 用户任务。模型名、token、检索源、tool 和业务 rejected 都是受控输入,不能推导模型准确率、用户满意度或真实成本。
第二,只有一次本机 capture。没有持续 2 至 4 周的任务量、P95、Collector queue 水位、查询延迟、存储增长、事故和恢复记录。reproduced 不能升级为 field-tested。
第三,固定 ID 改变了随机性。它让 sampler 分支和 API 查询可重放,却不代表生产 trace id 分布。短样本中的 5/5 是设计结果,不是统计估计。
第四,没有 parent propagation sampling。十条 sampling probe 都是根 span;没有验证 W3C Trace Context、跨服务 parent、远端 sampled flag、links 或 tail sampling。
第五,exporter 故障只覆盖连接拒绝。没有覆盖 DNS、TLS、HTTP 429/500、半开连接、响应超时、压缩错误、重试耗尽、queue overflow 或 Collector 到 Jaeger 的中断。
第六,memory limiter 没有被压到阈值。配置 128 MiB 只能证明 Collector 接受该配置,不证明高峰下的拒绝顺序、GC 抖动或 backpressure。
第七,属性删除发生得偏晚。sentinel 已经进入应用 SDK 与 Collector receiver;更严格的数据最小化必须在 instrumentation 之前阻止内容采集。
第八,后端查询证据是 canonical projection。它不固定 duration、start time、log/event、resource 全量字段和 Jaeger 内部 process id;这些字段需要各自的验收实验。
第九,业务 join 只有一个 transaction。没有重复事件、乱序、pending 到终态、跨租户、错键、reconciliation 或权威数据库对照。
第十,内存重建失败不是持久存储评测。它只证明当前默认后端不保留容器替换前的数据,不能代表任何生产 Jaeger deployment。
第十一,GenAI conventions 仍可能变化。本文延续固定 commit 63f8200... 的 Development 语义;operation、attribute 或 requirement level 更新时必须新建合同版本和迁移测试。
第十二,计数守恒不等于 exactly once。本轮没有 exporter retry、重复 delivery 和并发 race;24 accepted、24 sent、24 queryable 只能描述这次运行。
商业价值
最可能为这套能力付费的是已经让 Agent 调用知识库、CRM、工单、代码仓库或审批工具,并且需要对失败、成本和业务终态负责的组织。它增强的是现有 APM、日志和业务 reconciliation,而不是另做一块只展示 token 的“AI 仪表盘”。
购买者真正需要的是可回答的问题:
- 一次 rejected 业务结果之前调用了哪些模型、检索和工具;
- exporter 或 Collector 丢数据时,错误预算是否被发现;
- 高基数和内容字段是否在进入长期存储前被控制;
- 技术成功但业务未完成的比例是多少;
- 每个 fulfilled 结果消耗了多少模型、检索、工具和遥测成本;
- 某次部署、模型或策略变化是否提高失败与人工接管。
成本主要来自 instrumentation adapter、Collector 运维、持久存储与索引、属性治理、业务事件目录、告警、审计和人工 reconciliation。采样可以压低成本,却会改变故障与业务关联分母;删除内容可以降低风险,却会降低语义排障能力;持久后端提高可追溯性,也增加容量、权限和删除责任。没有单一配置同时最大化所有目标。
适合优先试点的场景有稳定 transaction id、明确最终状态、多个模型/检索/工具阶段和可撤销副作用,例如内部工单、文档审批、客服建议或代码任务。只做一次无状态文本生成、没有业务终态的应用,普通 tracing 加 token metrics 可能已经足够,不必承担完整 join 层成本。
不适合直接上线的情况包括:只能全量记录敏感 prompt 才能排障、业务系统没有权威终态、Collector 故障完全不可见、采样策略会漏掉稀有高风险动作、后端 retention 未定义,或工具副作用无法通过 transaction id 对账。可观测性不能修复业务状态本身不可验证。
未来 90 天的可证伪门槛应是:选择一个受控真实任务连续运行 2 至 4 周,公开匿名化任务量、采样前后关联完整率、Collector accepted/sent/failed、queue 水位、查询 P95、属性基数、存储增长、技术与业务分叉、事故和恢复。只有这些指标跨完整业务周期稳定,才讨论 field-tested;若做不到,保持内部实验,不把本次 24/24 宣传成生产可靠性。
从全栈工程迁移到 AI 系统工程
这项工作没有抛弃传统后端能力,而是把它们迁移到 Agent 运行面:
| 全栈能力 | 本实验中的 AI 系统能力 |
|---|---|
| request id 与调用链 | trace id、span id、parent reference |
| HTTP 客户端与失败处理 | OTLP exporter、flush error、重试边界 |
| 队列与批处理 | SDK batch、Collector batch、守恒计数 |
| schema validation | GenAI semantic contract、属性 allowlist |
| 数据库主键与对账 | transaction id、技术 trace 与业务终态 join |
| PII 与索引治理 | SDK metadata-only、Collector 删除、高基数预算 |
| 容器与存储 | digest 固定、health check、memory retention failure |
| 回归测试 | query evidence、自哈希、负向终态断言 |
新增的 AI 能力不是记住更多属性名,而是理解一次 Agent 任务同时存在技术执行、模型用量、内容治理和业务终态四条证据链。它们可以共享关联键,但不能互相替代。
面试表达
**30 秒版本:**我先用 synthetic JSON 校准 GenAI trace contract,再把同一结构接入真实 OpenTelemetry Node SDK、Collector 和 Jaeger。30 个 span 尝试中,5 个被 50% head sampler 正确丢弃,1 个因 exporter endpoint 不可达失败,剩余 24 个经 Collector 五批送达,20 条 trace 全部由 Jaeger API 反查。Collector 删除六类内容和高基数字段,独立业务 trace 还证明技术成功可以对应业务 rejected。它是可复现集成证据,不是生产 field test。
**3 分钟架构版本:**应用层用 BatchSpanProcessor(max=4) 包装真实 OTLP HTTP exporter;Collector 用 OTLP receiver、memory limiter、attributes delete 和 batch(size=5),再导出到固定 digest 的 Jaeger memory backend。验收不看 exporter 成功回调,而是逐 trace id 查询 Jaeger。成功路径同时核对应用 batch、Collector accepted/sent 和查询 span 数;负例分别验证 sampler drop、ECONNREFUSED 后端零写入、属性删除、业务终态分叉和容器重建后的 retention failure。结果 JSON 固定输入哈希、运行时、镜像身份、canonical query evidence 和 payload hash。
如果被追问为什么不是 field-tested,答案是:任务仍是合成输入、只有单次本机运行、没有持续流量、持久后端、queue 压力和真实业务数据库。证据升级必须依赖连续运行与权威业务终态,不能靠继续增加 fixture 数量。
复盘
这次最重要的修正不是某个 OpenTelemetry 配置,而是验收面的变化。源内 evaluator 可以证明合同逻辑,exporter 回调可以证明发送尝试,Collector metrics 可以证明中间计数,但只有 Jaeger query API 能证明当前后端终态。四层证据都需要,且结论范围不同。
第一次完整运行还暴露了一个很小但决定性的 API 假设:Jaeger 对不存在的 trace 返回 404,不是 200 加空数组。脚本最初因此停止。修正后将 404 作为“权威未找到”,其他状态仍 fail closed,才使 sampling drop 与 exporter failure 能被正确验证。这个失败样本比“第一次就绿”更有价值,因为它证明 runner 真正依赖实际后端行为。
下一步不再扩充 synthetic traces。应把当前 pipeline 接入一个有明确 transaction id 和可查询最终状态的受控真实任务,连续保存至少一个完整业务周期;同时替换 memory storage,加入 persistent queue、error-aware sampling、cardinality 预算、业务 reconciliation 和恢复演练。只有运行时间与真实任务能提升证据等级。
方法披露
本文由 AI 工具协助梳理实验矩阵、检查实现、组织文字和绘制原创 SVG;SDK 与容器版本、完整 commit、镜像 digest、Collector 配置、每个控制变量、运行日志、Jaeger 查询结果、Prometheus metrics、结果哈希、桌面与移动渲染均由本站对照实际文件和命令输出逐项复核。文章没有把 AI 生成解释、上游文档或预期配置当作本地运行证据。
实验在 Node.js v22.23.1、darwin arm64 宿主机和 Docker linux/arm64 容器中执行。真实运行组件只有 OpenTelemetry SDK、OTLP exporter、Collector 和 Jaeger;Agent、模型、retrieval、tool、token、transaction 与 business outcome 都是明确标注的 synthetic 输入,没有调用模型、向量库、外部工具、客户系统或生产遥测后端。.invalid sentinel 和高基数 marker 不包含真实用户数据或 secret。
结构化来源全部指向完整 40 位 commit 的仓库 tree/blob。来源日期采用对应 commit 或固定 release commit 的公开日期,访问日期为 2026-07-15。上游源码只解释 SDK、processor 和 Jaeger 配置;24 spans、20 traces、5/5 sampling、ECONNREFUSED、6/6 删除、业务 rejected 与 retention failure 只依据本仓库实际 capture。
桌面 SVG、独立移动 SVG 和 PNG 社交预览只呈现固定结果摘要。精确数据以 labs/genai-otel-integration/results/2026-07-15-results.json 为准,文件 SHA-256 为 f97f23147880aa0e437b93750e800290c7fb14afb62e9e7f6db5801c04e779a9。视觉中的“真实遥测管线、合成业务负载”是证据边界,不是装饰性说明。
修订记录
2026-07-15:初版发布;完成真实 Node SDK、Collector、Jaeger 与查询 API 集成,固定 24-span 结果、5/5 采样分支、exporter 失败、属性治理、业务关联和内存保留边界。
Reusable projects
关联可复用项目
本文已经进入以下工程项目;项目页提供固定版本、运行命令和结果工件。
- 已独立复现
本文验证真实 OpenTelemetry SDK 导出的 24 个 span 穿过 Collector 后可由 Jaeger API 查询,并覆盖采样、属性治理和 exporter 故障。
Source ledger
来源账本
以下来源用于核对事实、日期与当时可用范围。厂商自报性能不视为本站独立复现。
- OpenTelemetry JavaScript repository snapshot for SDK 2.9.0 and experimental 0.220.0 packages
- OpenTelemetry Node SDK README at the pinned package commit
- TraceIdRatioBasedSampler implementation at the pinned SDK commit
- BatchSpanProcessorBase implementation at the pinned SDK commit
- OTLP HTTP trace exporter README at the pinned SDK commit
- Collector Contrib attributes processor README at v0.156.0 commit
- Collector batch processor README at v0.156.0 commit
- Jaeger v2.19.0 all-in-one default configuration
- Jaeger v2.19.0 query extension documentation
- OpenTelemetry GenAI semantic conventions repository snapshot
讨论