news 2026/8/13 17:58:40

Micrometer 系列【55】统一观测:ObservationConvention | 观测约定

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Micrometer 系列【55】统一观测:ObservationConvention | 观测约定

文章目录

    • 1. 概述
    • 1.1 基础定义
    • 1.2 核心特征
      • 1.3 工作原理
        • (1)创建阶段
        • (2)启动观测
        • (3)执行业务逻辑
        • (4)观测结束
    • 2. 源码分析
      • 2.1 KeyValuesConvention:标记接口
      • 2.2 ObservationConvention:基础契约接口
      • 2.3 ChatModelObservationConvention:上层领域扩展接口
  • 3. 完整示例
    • 3.1 自定义上下文容器
    • 3.2 自定义观测 Convention 规范
    • 3.3 自定艺观测处理器
    • 3.4 业务服务类 & 测试入口
  • 4. 两种开发模式对比
    • 4.1 方式一:业务代码直接添加标签
    • 4.2 方式二:ObservationConvention 标准模式
    • 4.3 选型建议

1. 概述

Micrometer Observation体系提供统一可观测抽象,实现MetricsTracing数据同源采集。ObservationConvention是标签标准化核心契约,用来统一从业务上下文提取高低基数标签、定义观测名称。

早期开发方式直接在Observation.Context硬编码KeyValue,标签逻辑散落在业务代码;生产级框架(Spring AISpring Cloud)统一采用Convention模式,实现业务数据与标签抽取逻辑解耦。

本文基于原生API,讲解Convention定义、运行机制、源码细节以及完整可运行示例。

1.1 基础定义

一套标准化契约接口,负责从自定义Observation.Context中提取观测元信息。

核心方法:

  • getLowCardinalityKeyValues:提取低基数标签,同时用于监控指标Tag、链路追踪Span
  • getHighCardinalityKeyValues:提取高基数标签,仅允许放入链路 Span,禁止作为指标标签,防止时序爆炸;
  • getName():定义观测静态名称(指标名称);
  • getContextualName():动态上下文名称,用于链路界面展示;
  • supportsContext():判断当前规范实现是否匹配目标上下文类型。

1.2 核心特征

  1. 职责分离Context承载原始业务数据;Convention专注标签组装、命名规则;业务埋点不再关心标签规则。
  2. 强制区分高低基数:接口天然拆分两套标签方法,规范开发行为,规避高基数标签滥用风险。
  3. 分层扩展范式:顶层标记接口 → 泛型基础接口 → 领域专用子接口 → 默认通用实现 → 厂商/业务自定义实现,支持局部覆写。
  4. 无侵入扩展:新增业务维度、第三方适配时,仅新增Convention实现,无需改动埋点业务代码。
  5. 统一消费入口:所有ObservationHandler(指标处理器、追踪处理器)统一读取Convention产出的KeyValues,逻辑收敛。

1.3 工作原理

完整生命周期跟随Observation创建、启动、执行、停止流程。

(1)创建阶段

业务构建自定义Observation.Context,填充原始业务字段,不手动添加任何KeyValue;创建Observation实例并绑定对应ObservationConvention

此阶段仅完成对象绑定,不会触发标签提取。

(2)启动观测

调用observation.start()

  1. 框架内部检测绑定的Convention
  2. 主动调用getLowCardinalityKeyValues()getHighCardinalityKeyValues()提取标签;
  3. 调用getName()getContextualName()确定观测名称;
  4. ContextView+Convention产出标签传递给所有ObservationHandler#onStart

onStart阶段业务尚未执行,无法获取响应结果、异常信息。

(3)执行业务逻辑

observe()模板方法执行内部业务代码;业务可继续修改可变Context中的业务字段,但不建议动态追加标签,标签规则统一收敛在Convention

(4)观测结束

业务执行完成触发observation.stop()

  1. 再次通过Convention刷新高低基数标签;
  2. MetricsHandler使用低基数标签构建监控指标;TracingHandler将高低基数标签写入Span
  3. 观测生命周期结束,Convention实例可复用,Context上下文不可复用。

2. 源码分析

2.1 KeyValuesConvention:标记接口

标记型顶层接口,无任何方法。作用:语义归类,统一标识所有标签规范类,方便框架内部类型识别,区分普通业务类与观测规范实现。

publicinterfaceKeyValuesConvention{}

2.2 ObservationConvention:基础契约接口

  1. 使用泛型约束适配的上下文类型;
  2. 标签方法提供默认空实现,按需覆写;
  3. supportsContext用于匹配上下文类型;
  4. getName静态指标名,getContextualName链路展示动态名称。
publicinterfaceObservationConvention<TextendsObservation.Context>extendsKeyValuesConvention{ObservationConvention<Observation.Context>EMPTY=context->false;defaultKeyValuesgetLowCardinalityKeyValues(Tcontext){returnKeyValues.empty();}defaultKeyValuesgetHighCardinalityKeyValues(Tcontext){returnKeyValues.empty();}booleansupportsContext(Observation.Contextcontext);@NullabledefaultStringgetName(){returnnull;}@NullabledefaultStringgetContextualName(Tcontext){returnnull;}}

2.3 ChatModelObservationConvention:上层领域扩展接口

  1. 泛型锁定专属上下文ChatModelObservationContext
  2. 默认实现类型匹配方法,子类无需重复编写类型判断;
  3. 作为领域规范接口,统一约束该领域下全部规范实现。

参考Spring AI设计范式,基于基础接口做领域锁定:

publicinterfaceChatModelObservationConventionextendsObservationConvention<ChatModelObservationContext>{@OverridedefaultbooleansupportsContext(Observation.Contextcontext){returncontextinstanceofChatModelObservationContext;}}

3. 完整示例

场景:

  • 纯原生Java,无Spring
  • 根观测:创建订单;
  • 子观测:发起支付;
  • 采用标准Convention模式,Context不再手动添加KeyValue

3.1 自定义上下文容器

订单观测上下文容器,仅存放原始业务字段,标签提取逻辑交给Convention

publicclassOrderObservationContextextendsObservation.Context{privateStringorderNo;privateLonguserId;privateStringorderType;publicStringgetOrderNo(){returnorderNo;}publicvoidsetOrderNo(StringorderNo){this.orderNo=orderNo;}publicLonggetUserId(){returnuserId;}publicvoidsetUserId(LonguserId){this.userId=userId;}publicStringgetOrderType(){returnorderType;}publicvoidsetOrderType(StringorderType){this.orderType=orderType;}}

支付观测上下文容器:

importio.micrometer.observation.Observation;/** * */publicclassPaymentObservationContextextendsObservation.Context{privateStringorderNo;privateStringpayChannel;publicStringgetOrderNo(){returnorderNo;}publicvoidsetOrderNo(StringorderNo){this.orderNo=orderNo;}publicStringgetPayChannel(){returnpayChannel;}publicvoidsetPayChannel(StringpayChannel){this.payChannel=payChannel;}}

3.2 自定义观测 Convention 规范

订单观测规范接口:

publicinterfaceOrderObservationConventionextendsObservationConvention<OrderObservationContext>{@OverridedefaultbooleansupportsContext(Observation.Contextcontext){returncontextinstanceofOrderObservationContext;}}

订单观测规范默认实现,统一提取高低基数标签:

publicclassDefaultOrderObservationConventionimplementsOrderObservationConvention{publicstaticfinalStringOBSERVATION_NAME="order.create";@OverridepublicStringgetName(){returnOBSERVATION_NAME;}@OverridepublicStringgetContextualName(OrderObservationContextcontext){return"order "+context.getOrderType();}@OverridepublicKeyValuesgetLowCardinalityKeyValues(OrderObservationContextcontext){returnKeyValues.of(KeyValue.of("order.type",context.getOrderType()));}@OverridepublicKeyValuesgetHighCardinalityKeyValues(OrderObservationContextcontext){returnKeyValues.of(KeyValue.of("order.no",context.getOrderNo()),KeyValue.of("user.id",String.valueOf(context.getUserId())));}}

支付观测规范接口:

publicinterfacePaymentObservationConventionextendsObservationConvention<PaymentObservationContext>{@OverridedefaultbooleansupportsContext(Observation.Contextcontext){returncontextinstanceofPaymentObservationContext;}}

支付观测规范默认实现,统一提取高低基数标签:

publicclassDefaultPaymentObservationConventionimplementsPaymentObservationConvention{publicstaticfinalStringOBSERVATION_NAME="payment.create";@OverridepublicStringgetName(){returnOBSERVATION_NAME;}@OverridepublicStringgetContextualName(PaymentObservationContextcontext){return"payment "+context.getPayChannel();}@OverridepublicKeyValuesgetLowCardinalityKeyValues(PaymentObservationContextcontext){returnKeyValues.of(KeyValue.of("pay.channel",context.getPayChannel()));}@OverridepublicKeyValuesgetHighCardinalityKeyValues(PaymentObservationContextcontext){returnKeyValues.of(KeyValue.of("pay.order.no",context.getOrderNo()));}}

3.3 自定艺观测处理器

自定义观测处理器,读取Convention生成的标签进行打印

publicclassBizLogObservationHandlerimplementsObservationHandler<Observation.ContextView>{@OverridepublicvoidonStart(Observation.ContextViewcontextView){System.out.println("==== onStart ====");System.out.println("观测名称:"+contextView.getName());System.out.println("动态名称:"+contextView.getContextualName());System.out.println("低基数标签:"+contextView.getLowCardinalityKeyValues());System.out.println("高基数标签:"+contextView.getHighCardinalityKeyValues());System.out.println("================\n");}@OverridepublicvoidonStop(Observation.ContextViewcontextView){System.out.println("==== onStop ====");System.out.println("观测名称:"+contextView.getName());Throwableerror=contextView.getError();if(error!=null){System.out.println("异常信息:"+error.getMessage());}System.out.println("================\n");}@OverridepublicbooleansupportsContext(Observation.ContextViewcontext){returntrue;}}

3.4 业务服务类 & 测试入口

同上一篇,不再赘述!!!

4. 两种开发模式对比

4.1 方式一:业务代码直接添加标签

业务代码直接调用context.addLowCardinalityKeyValue()

优点

  1. 上手简单,代码直观,快速实现Demo、小型工具项目;
  2. 无需新增Convention接口与实现类,减少类数量;
  3. 支持运行时动态追加标签,灵活性高。

缺点

  1. 标签逻辑散落在各个业务埋点处;标签名称、规则修改,需要改动全部埋点代码;
  2. 无法统一管控高低基数规范,容易出现开发随意新增高基数指标标签,引发Prometheus时序爆炸;
  3. 业务代码与可观测规则强耦合,埋点代码臃肿;
  4. 缺少统一扩展入口;同类上下文想要差异化标签,只能修改业务代码;
  5. 不符合Spring AISpring Cloud等官方组件标准实现范式,无法对齐开源生态规范;
  6. ContextView只能读取已经存入的KeyValue;无法根据业务后置数据动态计算标签。

4.2 方式二:ObservationConvention 标准模式

优点

  1. 关注点分离Context只承载原始业务实体;标签抽取逻辑统一收敛到Convention;业务埋点干净纯粹;
  2. 统一管控标签规范,集中管理Tag名称、高低基数划分;标准化评审、统一修改;
  3. 天然支持分层扩展:通用默认实现 + 业务/厂商自定义子类,局部覆写标签逻辑,开闭原则;
  4. 框架自动在start()/stop()两个阶段重新执行标签提取;支持根据响应、异常等后置数据生成标签;
  5. 对齐MicrometerSpring AI官方最佳实践,便于后续对接各类中间件观测规范;
  6. 可统一设置观测静态名称、上下文展示名称,统一指标命名规范。

缺点

  1. 项目需要新增一组Convention接口、实现类,前期代码量更多;
  2. 学习成本更高,需要理解整套分层范式;
  3. 如果需要运行时动态标签,需要在Context中预先存入临时字段供Convention读取。

4.3 选型建议

  1. Demo、小型脚本、一次性工具:直接使用addLowCardinalityKeyValue,降低开发成本;
  2. 中大型业务项目、SDK、中间件组件、框架封装:强制使用ObservationConvention模式;
  3. 长期维护、多团队协作、需要统一监控规范的工程:优先Convention方案。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/13 17:58:19

揭秘张云网站建设背后的硬核逻辑与用户体验重塑之道:为何专业才是最好的流量密码

咱们今天不聊那些虚头巴脑的概念,也不搞什么高大上的互联网黑话堆砌。我就想跟您掏心窝子聊聊一个实在事:网站。特别是在现在这个人人都在做自媒体、人人都在搞私域流量的时代,为什么我们还死磕“张云网站建设”这件事?很多人问我,老板,我都小红书、抖音做得挺欢实了,为…

作者头像 李华
网站建设 2026/8/13 17:56:35

终极指南:用Godot的Metroidvania-System打造专业银河恶魔城游戏

终极指南&#xff1a;用Godot的Metroidvania-System打造专业银河恶魔城游戏 【免费下载链接】Metroidvania-System General-purpose framework for creating metroidvania games in Godot. 项目地址: https://gitcode.com/gh_mirrors/me/Metroidvania-System 想象一下&a…

作者头像 李华
网站建设 2026/8/13 17:55:04

2024新手必看网站搭建全套指南与高速下载工具选择实录,手把手教你从0到1

现在这个互联网时代,不管是想做个个人博客记录生活,还是想开个电商店铺卖东西,或者是搞个专业公司展示形象,拥有一个属于自己的独立网站几乎是必然的选择。但是,当你真正着手去准备的时候,往往会发现眼前是一片茫茫大海,各种名词、技术栈、服务器域名,听得人头都大了。…

作者头像 李华
网站建设 2026/8/13 17:53:02

Ethermint-archive架构深度剖析:Tendermint ABCI如何重塑区块链共识

Ethermint-archive架构深度剖析&#xff1a;Tendermint ABCI如何重塑区块链共识 【免费下载链接】ethermint-archive Ethereum on Tendermint using Cosmos-SDK! 项目地址: https://gitcode.com/gh_mirrors/et/ethermint-archive Ethermint-archive是一个基于Cosmos SDK…

作者头像 李华