参考
OpenTelemetry
go-sequent 可选的 obs 包:命令延迟、成功/失败计数、OCC 冲突与 Outbox 积压的 span/指标,以及 Provider 配置与边界。
OpenTelemetry
包:obs
obs 通过厂商中立的 OpenTelemetry API,让运维看到写路径的健康状况。它是可选的:没配置 provider 时,所有 instrument 都是空操作。
instrumentation 名称为 github.com/go-sequent/go-sequent。
作用
对账本来说,延迟和冲突都集中在 CommandService.Execute:事务、追加、以及 SyncInTxn(写事务内同步更新读模型)的 Projector。obs 暴露命令耗时、结果、OCC(用 ExpectedVersion 挡住并发写冲突)冲突,以及可选的 Outbox(事务内记待发消息,事后轮询投递)积压。库本身不绑定某一家 APM。
OpenTelemetry 数据是运行时信号,不是审计事实来源。对账与合规仍依赖事件流、hash chain(按聚合串联事件哈希,用来发现篡改)和命令记录(command.AuditOf、commands 表)。
能看到什么
- 慢命令:按
command.type看sequent.command.duration_ms。 - 成功与失败率:
sequent.command.total,带status=ok|error。 - 热点聚合上的冲突风暴:
sequent.optimistic_conflict.total。 - Outbox 积压:
sequent.outbox.depth(需提供深度函数)。
接线
obs 不是命令中间件。通过门面选项挂接,会设置 App.Obs 与 Service.Obs:
// 应用侧:先安装 TracerProvider、MeterProvider 与 exporter。
inst, err := obs.New(obs.Config{
OutboxDepth: func(ctx context.Context) int64 {
n, _ := ob.Depth(ctx)
return n
}, // 可选;为 nil 时不产生 sequent.outbox.depth
})
app := sequent.New(sequent.Config{},
sequent.WithObs(inst),
sequent.WithStore(store, tx),
)
也可以直接赋值 svc.Obs = inst。nil 表示不产生遥测。
Provider 由你负责
obs.New 使用全局的 otel.Tracer 与 otel.Meter。若应用没有调用 otel.SetTracerProvider 和 otel.SetMeterProvider,instrument 就是空操作,测试里也很安全。库不自带 OTLP、Prometheus 或 stdout exporter,由宿主进程安装。
Execute 如何使用它
StartCommand开始 spansequent.Execute。- 运行事务与 UnitOfWork。
- Commit 返回
ErrOptimisticConcurrency时,RecordConflict增加冲突计数。 RecordCommand记录延迟与结果计数,然后结束 span。
批量 Execute 的 command.type 是第一条命令的类型加 +batch。
产出的 span 与指标
| 类型 | 名称 | 说明 |
|---|---|---|
| Span | sequent.Execute |
属性 command.type。出错时记录错误并把状态设为 Error。 |
| Histogram | sequent.command.duration_ms |
command.type;单位毫秒 |
| Counter | sequent.command.total |
command.type、status = ok 或 error |
| Counter | sequent.optimistic_conflict.total |
无额外属性 |
| Counter | sequent.events.appended |
API 存在,但框架在追加时不会调用 |
| Observable gauge | sequent.outbox.depth |
仅当设置了 Config.OutboxDepth |
公开 API:Instruments、Config、New、StartCommand、RecordCommand、RecordConflict、RecordEvents。
它不做什么
- 不内置 exporter,也不创建 provider。
- 不自动埋点 HTTP 或 gRPC。
- 没有 Projector、Workflow 或 Outbox 轮询器的 span。
RecordEvents没有挂到Repository.Commit或EventStore.Append上。留给应用在自己的边界调用;不调用的话sequent.events.appended会一直为零。- 不能替代审计轨迹。
不要把密钥和个人数据放进 span 属性与日志。内置属性只包含命令类型。
如何使用这些信号
- 对
error率上升,以及各命令类型sequent.command.duration_ms的 p99 设告警。 sequent.optimistic_conflict.total往上爬,往往说明有热点聚合,或故障切换后正在追赶。见 唯一键与 OCC与 故障转移。sequent.outbox.depth持续升高,说明轮询器落后或卡住了。见 Publisher。
相关
文档随 go-sequent 源码更新;若与 API 不一致,以源码为准。