AI 工程实践
OpenTelemetry 持久恢复实验:SIGKILL 后 7 个 Span 如何从磁盘队列回到 Jaeger
用 Collector file_storage 持久队列、Jaeger Badger 和两个 Docker named volumes,实际验证下游停机、双容器 SIGKILL、分步重建、零新入口恢复与查询终态。
时间与证据
上一篇 OpenTelemetry 真实链路实验证明了 24 个 span 可以从 Node SDK 穿过 Collector 到达 Jaeger,也刻意证明了默认 memory storage 在容器替换后丢失 trace。但它仍没有回答线上最难处理的中间状态:应用已经把遥测交给 Collector,Collector 暂时发不到后端,随后 Collector 自己也崩溃,这批数据最终在哪里。
2026 年 7 月 15 日,我新增 labs/otel-persistent-recovery/,把 Collector exporter queue 绑定到 bbolt file_storage,把 Jaeger 从 memory storage 换成 Badger,并用两个 Docker named volumes 分别保存 queue 与 trace。实验不是只执行 docker restart:Jaeger 与 Collector 依次被 docker kill,即 SIGKILL;两个旧容器随后都被删除,再按“只恢复 Jaeger -> 再恢复 Collector”的顺序重建。
“分步”是本实验最重要的证据设计。只恢复 Jaeger 时,3-span baseline 必须存在,证明 Badger volume 生效;7-span queued trace 必须返回 404,证明它尚未进入后端。再启动新 Collector 后,queued trace 才能出现。若直接同时启动两者,最终可查询虽然看似成功,却无法区分数据原本已在 Jaeger、来自应用重发,还是确实从 Collector volume 恢复。
上游证据固定到完整 commit。Collector persistent queue 文档明确说明:给 sending_queue.storage 配置 storage extension 后,不再使用内存 queue;Collector 在持久队列仍有 items 时被终止,重启会取回并继续导出。文档也明确警告 queue 满、磁盘空间不足或 I/O error 会导致 enqueue 失败和数据丢弃,而且 auth extension context 不会随持久队列保留。
Collector Contrib file storage 文档说明它使用本地文件系统,fsync 会在每次写入后强制同步,代价是性能下降。本实验使用 fsync: true,不是默认的性能优先设置。
Jaeger Badger 配置源码则揭示了另一个容易漏掉的边界:ephemeral: false 只选择磁盘目录,默认 SyncWrites=false,源码注释明确写着“Performance over durability”。实验因此把 YAML consistency 显式设为 true,运行日志必须出现 "SyncWrites":true。这能加强 SIGKILL 恢复条件,但不等于磁盘或节点故障已经验证。
固定运行身份:
| 组件 | 版本与不可变身份 |
|---|---|
| Node.js | v22.23.1, darwin arm64 |
| Node SDK / trace SDK | 0.220.0 / 2.9.0 |
| Collector Contrib | 0.156.0, manifest sha256:125bdbeb...8108 |
| Jaeger | 2.19.0, manifest sha256:ede48642...c68b |
| volume init | BusyBox 1.37.0-uclibc, manifest sha256:39e0df8c...315a |
| Docker Engine | 29.6.1, linux arm64 |
固定工件位于 labs/otel-persistent-recovery/results/2026-07-15-results.json,共 13,750 bytes,文件 SHA-256 为 7e9c5f17cc28b6ceb7522e45b8b78f541fd695085a19eff36be20fd39ee9f053,加入自引用字段前的 canonical payload SHA-256 为 4fc71e6de15c6608049f0fec29cefea3464d2a5923e30f7e4a75e44c11af46d7。11 个回归测试分别检查版本、存储合同、中断指标、volume 身份、分步查询、树结构、重复、恢复 metrics、启动日志和工件隐私。
证据等级仍是 reproduced。真实运行的是 SDK、Collector、bbolt、Badger、Docker volume 和 Jaeger query API;trace 内容、故障时间和负载规模是实验控制输入,没有持续真实 Agent 任务或客户流量。
实验设计
两个持久面不能混成一个“有磁盘”
完整链路为:
Node SDK
-> OTLP/HTTP
-> Collector receiver
-> batch(size=5)
-> persistent sending queue
-> file_storage / bbolt / fsync
-> collector_queue named volume
-> OTLP/HTTP exporter
-> Jaeger receiver
-> Badger / ephemeral=false / SyncWrites=true / TTL=48h
-> jaeger_badger named volume
-> Jaeger query API
Collector queue 与 Jaeger store 解决不同问题。queue 保存“Collector 已接收、尚未交付后端”的请求;Badger 保存“后端已经接收、应该可查询”的 spans。只给 Jaeger 挂 volume,Collector 在 outage 中崩溃仍会丢未交付数据;只给 Collector 持久 queue,Jaeger 重建后之前已交付的 baseline 仍会消失。
Collector exporter 配置:
retry_on_failure:
enabled: true
initial_interval: 500ms
max_interval: 2s
max_elapsed_time: 0s
sending_queue:
enabled: true
num_consumers: 1
queue_size: 100
storage: file_storage/queue
max_elapsed_time: 0s 表示 retry 不因总时长自动停止;它没有取消 queue capacity。queue 仍只有 100 batches,磁盘仍可能满,retry 仍可能长期积压。生产系统需要同时监控 queue_size/capacity、enqueue failure、oldest item age 与磁盘水位。
Jaeger 配置:
badger:
directories:
keys: /var/lib/jaeger/keys
values: /var/lib/jaeger/values
ephemeral: false
consistency: true
ttl:
spans: 48h
48 小时只是固定配置,不是本实验等待 48 小时测出的 retention 结果。真正的 TTL 实验必须跨越到期边界,记录写入、查询、maintenance 与删除时间;本文不会把配置值写成观察值。
先用失败证明 volume 权限不是自动成立
第一次直接给两个非 root 容器挂新 named volumes 时,实际启动失败:
Collector: open /var/lib/otelcol/file_storage/exporter_otlp_http_jaeger_traces: permission denied
Jaeger: mkdir /var/lib/jaeger/keys: permission denied
镜像 metadata 显示 Collector 使用 10001:10001,Jaeger 使用 10001。Docker 新 volume 根目录由 root 拥有,应用用户不能创建子目录。把两个服务都改成 root 虽然能快速通过,却扩大了长期运行权限。
最终 Compose 增加固定 digest 的一次性 storage-init:它以 0:0 创建四个目录、将两个实验 volume 递归 chown 10001:10001,然后退出。Collector 与 Jaeger 仍以镜像默认非 root 用户运行。这个模式不是所有 orchestrator 的最佳解;Kubernetes 可以使用 fsGroup、init container 与更细 securityContext,但原则相同:volume ownership 是部署合同,不能靠镜像恰好可写。
用两个确定性 trace 分离已交付与未交付
实验只生成两条 trace:
| trace | spans | 角色 |
|---|---|---|
d100...0001 |
1 root + 2 children | baseline,Jaeger 强杀前已查询确认 |
d200...0001 |
1 root + 6 children | outage 期间进入 Collector queue |
baseline 的 3 spans 证明 Jaeger volume;queued 的 7 spans 证明 Collector volume。固定 span id 与 parent reference 让恢复后不仅能数 7,还能检查“一根六子”的树没有被拆坏。
Node SDK 的 BatchSpanProcessor 以 [4, 3] 两次 OTLP 请求把 queued trace 交给 Collector。Collector batch processor 再按 5 spans 聚合,形成两个 exporter queue requests。应用 exporter 两次都返回 resultCode=0,这只表示 Collector receiver 已接受请求,不表示 Jaeger 已写入。
强杀顺序与权威验收
实验 runner 每次从 docker compose down --volumes 开始,按以下顺序执行:
- 启动 storage init、Jaeger 与 Collector。
- 发送 baseline,Jaeger API 必须返回 3 spans。
docker killJaeger。- 发送 queued trace,等待 Collector metrics 到达 accepted 10、sent 3、queue 2。
docker killCollector;从 stopped container 复制 queue 目录,只保存文件名与大小摘要。- 删除两个旧容器,保留两个 named volumes。
- 只启动新 Jaeger;baseline 必须仍为 3,queued 必须 404。
- 启动新 Collector;等待 queued trace 变为 7 spans,queue 变为 0。
- 比较容器已替换、volume 身份未变、span id 唯一且 parent tree 完整。
finally删除实验容器、网络与 volumes。
没有应用重发步骤。新 Collector 的 receiver counter 必须为 0,而 exporter sent counter 必须为 7。若 accepted 也变为 7,就不能证明恢复数据来自持久 queue。
结果
11/11 工件测试通过。固定结果如下:
| 验收面 | 中断或恢复结果 | 证据含义 |
|---|---|---|
| baseline | 3 -> 3 -> 3 spans | Jaeger 强杀、删除和全恢复后结构不变 |
| queued 应用 export | [4, 3],均 resultCode=0 |
Collector receiver 接受了 7 spans |
| outage Collector | accepted 10 / sent 3 | 7 spans 尚未交付 Jaeger |
| outage queue | 2 / 100 batches | 两个 exporter requests 留在 queue |
| bbolt 文件 | 32,768 bytes | stopped Collector 中存在 queue 数据库 |
| 容器 | Collector 与 Jaeger 均替换 | 不是原进程继续运行 |
| volumes | 两个 identity 前后一致 | 本机持久载体保持 |
| 只恢复 Jaeger | baseline 3 / queued 404 | queued 尚不在 Badger |
| 新 Collector 日志 | 7 items / 1,387 bytes | 从旧 queue metadata 恢复 |
| 新 Collector metrics | accepted 0 / sent 7 / queue 0 | 无新 ingress,queue 已排空 |
| 最终 queued trace | 7 unique / 0 duplicate | 本轮树完整,无观察到重复 |
应用成功发生在后端成功之前
Jaeger 已停止时,queued emitter 的两次 forceFlush() 都成功,OTLP exporter 回调均为 0。若应用只记录“exporter 没报错”,它会认为遥测已经安全进入后端。Collector metrics 同一时刻给出更完整的状态:
receiver accepted = 10
exporter sent = 3
queue size = 2 batches
queue capacity = 100 batches
enqueue failed = 0
10 包含最早的 3-span baseline 和 outage 的 7 spans;sent 仍为 3,所以差额 7 与 queue 对应。这个状态不是错误:异步队列的职责正是解耦接收与交付。但指标名称必须准确,不能把 accepted 命名成 stored、delivered 或 queryable。
生产 SLO 至少要区分:
ingress acceptance
queue durability
downstream delivery
backend indexing
query availability
任何一层成功都不能替代下一层。
SIGKILL 后的 queue 日志比“文件存在”更强
Collector 被强杀后,queue volume 中存在 exporter_otlp_http_jaeger_traces,大小 32,768 bytes。但 bbolt 空数据库也可能占空间,文件存在本身不能证明里面有 7 spans。
新 Collector 的固定日志给出更强证据:
Loaded queue metadata:
itemsSize=7
bytesSize=1387
dispatchedItems=1
Fetching items left for dispatch by consumers:
numberOfItems=1
Moved items for dispatching back to queue:
numberOfItems=1
强杀发生时,一个 batch 已被 consumer 取出并处于 dispatch 中,另一个仍未 dispatch。恢复逻辑把前者移回 queue,再由新 consumer 继续处理。最终 7 个 spans 全部出现,说明两个不同中间状态都被覆盖,而不是只恢复“尚未取出”的简单项。
分步启动排除了两个伪成功解释
新 Jaeger 先启动时:
- baseline trace 返回 3 spans;
- queued trace 返回 404;
- Collector 尚未启动。
这同时排除两种解释。第一,若 baseline 消失,说明 Badger volume 或同步写合同失败;第二,若 queued 已出现,说明它在强杀前已经进入 Jaeger,后续 Collector 恢复就没有证明力。
新 Collector 启动后,日志加载 7 items,queued trace 才变为可查询。新进程 metrics 是 accepted 0、sent 7、queue 0,进一步排除应用重发。容器 ID 不进入公开工件,但 runner 比较前后 ID 并只保存 collectorReplaced=true、jaegerReplaced=true,避免泄漏无复现意义的运行实例值。
7 unique、0 duplicate 不是 exactly-once
最终 Jaeger 返回 7 个 span id,集合大小也是 7,所以本轮 duplicateSpanCount=0。父子关系仍是一根六子。这个结果只能写成“本次恢复没有观察到重复”,不能升级为 exactly-once。
分布式导出存在经典不确定窗口:后端可能已经提交,但响应在网络中丢失;Collector 认为失败并重试,就可能重复发送。Jaeger 可能按 trace/span identity 覆盖、合并或返回重复,其他后端处理也可能不同。要验证更强语义,必须注入“提交后响应丢失”、部分 batch 成功、重复 delivery 与跨实例 consumer,并检查后端最终对象而不只看 exporter counter。
fsync 与 SyncWrites 把成本换成更窄的失败窗口
Collector file storage 使用 fsync: true;Jaeger Badger 使用 consistency: true,日志报告 SyncWrites=true。两者都是耐久性优先设置。结果证明本轮 SIGKILL 后数据仍在,却没有测量每次同步写对吞吐、P95、IOPS、SSD 写放大和容器 CPU 的成本。
生产决策不能只问“能不能恢复”,还要比较:
- 同步写开启前后的 ingestion P95 与最大稳定吞吐;
- queue 积压时的磁盘增长与 drain rate;
- volume 介质的 fsync 语义与云盘确认边界;
- 高峰时应用、Collector 和后端的背压顺序;
- 可接受数据损失窗口与恢复点目标。
如果每条低价值 debug trace 都要求同步落盘,成本可能高于数据价值;如果审计或高风险 Agent 动作必须可追溯,性能优先默认又可能不够。策略需要按信号价值分层,不应全局复制一个 queue 配置。
复现与验证
要求 Docker Engine 与 Compose 可用,本机端口 25318、24133、29888、27686 未占用:
npm ci
npm run lab:otel-recovery:run
npm run lab:otel-recovery:test
默认 replay 写入 /tmp/younis-ai-lab-otel-persistent-recovery.json。runner 无论成功或失败都会删除临时 queue snapshot;非 --keep-stack 模式还会删除实验容器、网络和 volumes。
比较固定载荷:
jq 'del(.capturedAt, .payloadSha256)' \
labs/otel-persistent-recovery/results/2026-07-15-results.json \
> /tmp/otel-recovery-checked.json
jq 'del(.capturedAt, .payloadSha256)' \
/tmp/younis-ai-lab-otel-persistent-recovery.json \
> /tmp/otel-recovery-replayed.json
diff -u /tmp/otel-recovery-checked.json \
/tmp/otel-recovery-replayed.json
结果固定 compose.yaml、Collector config、Jaeger config、emitter 和 runner 五个输入身份。原始 queue bytes 不进入 Git:它们会包含序列化遥测,生产环境还可能含标识或敏感 metadata。报告只保存文件名、大小和 Collector 自己输出的 item/byte counters。
失败与边界
第一,SIGKILL 不等于节点故障。Docker Desktop VM、宿主机、两个 named volumes 和存储介质全程健康。volume 删除、磁盘损坏、VM 丢失和跨节点调度都没有验证。
第二,named volume 不是备份。它把容器生命周期与数据生命周期分开,却仍属于单机故障域。生产恢复需要远程持久卷、快照、备份校验和异机恢复演练。
第三,只有 7 个 queued spans。queue 容量为 100 batches,本轮只占 2;没有触发 queue 满、磁盘满、bbolt max size、I/O error、enqueue rejection 或 block-on-overflow。
第四,没有验证部分提交。Jaeger 是完全停止或完全运行,没有构造“后端已写入但响应丢失”,所以本轮 0 duplicate 不能证明 exactly-once。
第五,只有一个 Collector consumer。没有多实例共享 queue,也没有测试同一 volume 的并发 writer。很多本地嵌入式数据库不允许多个 writer,不能把单实例 volume 直接挂给水平扩容副本。
第六,同步写成本未测。fsync=true 与 SyncWrites=true 加强本轮 crash 条件,但没有吞吐、P95、磁盘 latency、写放大或费用对照。
第七,持久 queue 扩大数据落盘范围。metadata-only trace 也可能含 conversation、transaction、tenant、tool call 或错误信息。加密、文件权限、备份、取证、删除和密钥管理必须进入治理范围。
第八,auth context 不随 queue 保留。OpenTelemetry 固定文档明确说明 auth extension context 被忽略。恢复后 exporter 若依赖临时认证上下文,必须重新建立凭据或使用稳定 workload identity,不能假定原请求身份仍在。
第九,48h TTL 只是配置。没有等待 48 小时、跨 maintenance 周期或证明精确删除上界。
第十,一次性 root init 仍是特权组件。它只挂两个实验 volume 并立即退出;生产需要更严格的 image provenance、capability、securityContext、只读根文件系统和变更审计。
第十一,Jaeger Badger 是本地实验后端。没有高可用、对象存储备份、跨区域复制、索引容量或查询并发评测。
第十二,任务负载仍是 synthetic。真实的是 telemetry recovery path,不是真实 Agent 运行周期,因此保持 reproduced。
商业价值
愿意为这项能力付费的团队,通常已经让 Agent 访问工单、代码、审批、CRM 或运营工具,并需要回答“事故发生时到底做了什么”。当遥测在下游维护、网络分区或 Collector 重启中丢失,最需要审计的失败窗口反而最先变成空白;持久 queue 的价值是缩小这个观测盲区。
它增强现有 APM 和审计管线,不替代业务事件存储。trace 可以解释调用链与错误,业务数据库仍负责权威副作用和最终状态。对于高风险 Agent,最合理的组合是:
业务操作 -> 权威事务/审计事件
技术执行 -> trace 与 metrics
两者通过 transaction id 关联
各自拥有独立耐久性与恢复 SLO
主要成本包括同步写延迟、volume 容量、持久后端、加密、备份、queue 监控、恢复演练和数据保留合规。持久化所有 debug 内容会迅速扩大风险与费用,所以应先做 metadata allowlist、采样分层和信号价值分类,再决定哪些队列需要磁盘耐久。
适合优先采用的场景是高价值、可追责、低到中等吞吐的 Agent 动作,例如审批建议、代码变更、客服工单和受控运营操作。不适合直接套用的是高吞吐、低价值、允许短窗口损失的 debug trace,或必须把敏感 prompt 全量写盘才能排障的系统。
未来 30 天可以设置可证伪门槛:
- queue 使用率持续低于容量预算,且后端中断时告警在规定时间触发;
- 恢复 drain rate 大于正常 ingress,积压可以在目标时间内清空;
enqueue_failed为零,磁盘水位和 oldest item age 有 owner;- 提交后响应丢失实验不会让业务报表双算;
- 备份可以在另一节点恢复,TTL 与删除审计一致;
- 同步写开启后的 P95 与成本仍在业务预算内。
这些条件未满足前,本地 7/7 只是恢复机制证据,不是生产可靠性承诺。
从全栈工程迁移到 AI 系统工程
| 全栈基础 | 本实验对应能力 |
|---|---|
| 消息队列 | Collector sending queue、retry、capacity 与 drain |
| 数据库 WAL | bbolt fsync、Badger SyncWrites、crash recovery |
| 容器运维 | 非 root UID、volume ownership、init container、SIGKILL |
| 状态机 | accepted、queued、sent、indexed、queryable 分层 |
| 幂等设计 | 固定 trace/span identity 与 duplicate 检查 |
| 备份恢复 | container replacement 与 volume preservation 的边界 |
| 安全治理 | 落盘内容、auth context、权限和 retention |
| 回归测试 | 分步启动、404 负例、零 ingress 恢复与 artifact hash |
Agent 系统增加了模型、检索和工具维度,但恢复问题仍然是经典分布式系统问题:确认发生在哪一层,未完成状态存在哪里,重试是否重复,权威终态如何查询。AI 名称不能替代这些基础合同。
面试表达
**30 秒版本:**我把 OpenTelemetry Collector exporter queue 接到 file_storage,Jaeger 接到 Badger,并显式开启 bbolt fsync 与 Badger SyncWrites。Jaeger 停机后 7 个 span 留在 2 个磁盘 batches;Collector 与 Jaeger 都被 SIGKILL、删除后,只恢复 Jaeger 时 baseline 仍在而 queued trace 是 404,再恢复 Collector 后新进程在 accepted=0 的情况下发送 7 个 queue spans,最终 7 个唯一 span、0 duplicate。它证明单机 volume 上的 crash recovery,不是 exactly-once 或节点级容灾。
**3 分钟版本:**我先固定 SDK、Collector、Jaeger 与 init image digest,处理非 root volume ownership。baseline 和 queued trace 分别证明 Jaeger store 与 Collector queue。故障时用 metrics 固定 accepted=10、sent=3、queue=2;强杀后比较容器已替换、volume identity 保持。新 Collector 日志加载 7 items/1387 bytes,其中一个 dispatch 中 batch 被放回 queue;最终 sent=7、accepted=0,排除了应用重发。限制包括 queue 未满、没有部分提交、没有多实例、没有节点丢失和同步写性能数据。
复盘
本轮最重要的发现是“挂 volume”之前还有权限与同步语义。第一次启动时两个服务都因 root-owned 新 volume 而失败;修复不应是让长期服务改成 root,而是用最小的一次性初始化建立目录所有权。随后 Jaeger 源码又显示 ephemeral=false 不自动启用同步写;如果不读运行日志,文章可能把优雅关闭后的持久化误写成 SIGKILL 耐久。
第二个收获是恢复顺序本身就是测试工具。只启动 Jaeger得到 baseline 3、queued 404,再启动 Collector 得到 queued 7,比“全部重启后页面有 trace”强得多。前者能证明每一份数据来自哪个持久面,后者只证明系统最终看起来正常。
第三个收获是 0 duplicate 必须保留窄表述。真正危险的是后端已提交但响应丢失,这次故障没有覆盖。下一实验应在 Collector 与后端之间注入提交后断连、部分 batch 成功和 queue overflow,再比较 Jaeger 与业务关联层的最终对象。
完成这些之前,结论保持明确:在固定单机 Docker 环境中,启用 fsync 的 Collector bbolt queue 与启用 SyncWrites 的 Jaeger Badger,可以让本次 7-span trace 经两个 SIGKILL 和两个容器替换后恢复到完整、无观察到重复的查询终态;它不证明 volume、磁盘、节点或生产流量可靠性。
方法披露
本文由 AI 工具协助设计故障矩阵、审查代码、组织文字与绘制原创 SVG。固定 commit、镜像 digest、UID、volume 权限、Collector/Jaeger 配置、SIGKILL 顺序、Prometheus metrics、启动日志、Jaeger 查询、结果哈希、视觉渲染和最终表述均由本站对照实际命令输出逐项核验。没有把上游文档、预期行为或 AI 生成说明当作本地结果。
第一次无 init container 的启动确实产生 Collector 与 Jaeger 两条 permission denied,随后只修改 volume 初始化条件再运行。最终权威结果来自干净 volumes 的完整 runner;开发期手工探针不进入统计分母。运行中没有调用模型、向量库、外部 Agent、客户系统或生产遥测后端。
实验只使用两个确定性 synthetic traces,不含 prompt、用户数据、token、凭据或真实 transaction id。原始 bbolt queue bytes、container id、Docker mountpoint 和临时目录没有写入 Git;固定 JSON 只保留文件名、大小、聚合 metrics、日志摘要和 canonical query evidence。
所有结构化来源均指向完整 40 位 commit 的 tree/blob 页面。OpenTelemetry 与 Jaeger 源码用于解释 storage、queue、fsync、SyncWrites 和查询边界;3-span baseline、2 batches、7 items、404、accepted 0/sent 7、7 unique/0 duplicate 只依据本仓库实际 capture。
桌面 SVG、独立移动 SVG 和 PNG 只表达固定恢复顺序,并明确标注同一 Docker host 与 named volumes。精确结果以 labs/otel-persistent-recovery/results/2026-07-15-results.json 为准,文件 SHA-256 为 7e9c5f17cc28b6ceb7522e45b8b78f541fd695085a19eff36be20fd39ee9f053。
修订记录
2026-07-15:初版发布;完成 Collector bbolt persistent queue、Jaeger Badger、非 root volume 初始化、双 SIGKILL、双容器替换、分步恢复、零新入口 drain、唯一 span 与结果工件验证。
Reusable projects
关联可复用项目
本文已经进入以下工程项目;项目页提供固定版本、运行命令和结果工件。
- 已独立复现
本文验证 Collector 与 Jaeger 被 SIGKILL 并删除后,保留 named volumes 可恢复 7 个 queued span,最终 7 unique、0 duplicate。
Source ledger
来源账本
以下来源用于核对事实、日期与当时可用范围。厂商自报性能不视为本站独立复现。
- OpenTelemetry Collector exporter helper persistent queue documentation at v0.156.0 commit
- Collector Contrib file storage extension README at v0.156.0 commit
- Collector Contrib file storage configuration source at v0.156.0 commit
- Collector batch processor README at v0.156.0 commit
- Jaeger v2.19.0 Badger deployment configuration
- Jaeger Badger configuration source including sync writes
- Jaeger Badger storage data model at v2.19.0 commit
- Jaeger v2.19.0 query extension documentation
- OpenTelemetry JavaScript repository snapshot for SDK 2.9.0 and experimental 0.220.0 packages
- OTLP HTTP trace exporter README at the pinned SDK commit
讨论