ARTICLE DETAIL

资讯详情

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

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

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体系提供统一可观测抽象实现Metrics、Tracing数据同源采集。ObservationConvention是标签标准化核心契约用来统一从业务上下文提取高低基数标签、定义观测名称。早期开发方式直接在Observation.Context硬编码KeyValue标签逻辑散落在业务代码生产级框架Spring AI、Spring Cloud统一采用Convention模式实现业务数据与标签抽取逻辑解耦。本文基于原生API讲解Convention定义、运行机制、源码细节以及完整可运行示例。1.1 基础定义一套标准化契约接口负责从自定义Observation.Context中提取观测元信息。核心方法getLowCardinalityKeyValues提取低基数标签同时用于监控指标Tag、链路追踪SpangetHighCardinalityKeyValues提取高基数标签仅允许放入链路 Span禁止作为指标标签防止时序爆炸getName()定义观测静态名称指标名称getContextualName()动态上下文名称用于链路界面展示supportsContext()判断当前规范实现是否匹配目标上下文类型。1.2 核心特征职责分离Context承载原始业务数据Convention专注标签组装、命名规则业务埋点不再关心标签规则。强制区分高低基数接口天然拆分两套标签方法规范开发行为规避高基数标签滥用风险。分层扩展范式顶层标记接口 → 泛型基础接口 → 领域专用子接口 → 默认通用实现 → 厂商/业务自定义实现支持局部覆写。无侵入扩展新增业务维度、第三方适配时仅新增Convention实现无需改动埋点业务代码。统一消费入口所有ObservationHandler指标处理器、追踪处理器统一读取Convention产出的KeyValues逻辑收敛。1.3 工作原理完整生命周期跟随Observation创建、启动、执行、停止流程。1创建阶段业务构建自定义Observation.Context填充原始业务字段不手动添加任何KeyValue创建Observation实例并绑定对应ObservationConvention。此阶段仅完成对象绑定不会触发标签提取。2启动观测调用observation.start()框架内部检测绑定的Convention主动调用getLowCardinalityKeyValues()、getHighCardinalityKeyValues()提取标签调用getName()、getContextualName()确定观测名称将ContextViewConvention产出标签传递给所有ObservationHandler#onStart。onStart阶段业务尚未执行无法获取响应结果、异常信息。3执行业务逻辑observe()模板方法执行内部业务代码业务可继续修改可变Context中的业务字段但不建议动态追加标签标签规则统一收敛在Convention。4观测结束业务执行完成触发observation.stop()再次通过Convention刷新高低基数标签MetricsHandler使用低基数标签构建监控指标TracingHandler将高低基数标签写入Span观测生命周期结束Convention实例可复用Context上下文不可复用。2. 源码分析2.1 KeyValuesConvention标记接口标记型顶层接口无任何方法。作用语义归类统一标识所有标签规范类方便框架内部类型识别区分普通业务类与观测规范实现。publicinterfaceKeyValuesConvention{}2.2 ObservationConvention基础契约接口使用泛型约束适配的上下文类型标签方法提供默认空实现按需覆写supportsContext用于匹配上下文类型getName静态指标名getContextualName链路展示动态名称。publicinterfaceObservationConventionTextendsObservation.ContextextendsKeyValuesConvention{ObservationConventionObservation.ContextEMPTYcontext-false;defaultKeyValuesgetLowCardinalityKeyValues(Tcontext){returnKeyValues.empty();}defaultKeyValuesgetHighCardinalityKeyValues(Tcontext){returnKeyValues.empty();}booleansupportsContext(Observation.Contextcontext);NullabledefaultStringgetName(){returnnull;}NullabledefaultStringgetContextualName(Tcontext){returnnull;}}2.3 ChatModelObservationConvention上层领域扩展接口泛型锁定专属上下文ChatModelObservationContext默认实现类型匹配方法子类无需重复编写类型判断作为领域规范接口统一约束该领域下全部规范实现。参考Spring AI设计范式基于基础接口做领域锁定publicinterfaceChatModelObservationConventionextendsObservationConventionChatModelObservationContext{OverridedefaultbooleansupportsContext(Observation.Contextcontext){returncontextinstanceofChatModelObservationContext;}}3. 完整示例场景纯原生Java无Spring根观测创建订单子观测发起支付采用标准Convention模式Context不再手动添加KeyValue。3.1 自定义上下文容器订单观测上下文容器仅存放原始业务字段标签提取逻辑交给ConventionpublicclassOrderObservationContextextendsObservation.Context{privateStringorderNo;privateLonguserId;privateStringorderType;publicStringgetOrderNo(){returnorderNo;}publicvoidsetOrderNo(StringorderNo){this.orderNoorderNo;}publicLonggetUserId(){returnuserId;}publicvoidsetUserId(LonguserId){this.userIduserId;}publicStringgetOrderType(){returnorderType;}publicvoidsetOrderType(StringorderType){this.orderTypeorderType;}}支付观测上下文容器importio.micrometer.observation.Observation;/** * */publicclassPaymentObservationContextextendsObservation.Context{privateStringorderNo;privateStringpayChannel;publicStringgetOrderNo(){returnorderNo;}publicvoidsetOrderNo(StringorderNo){this.orderNoorderNo;}publicStringgetPayChannel(){returnpayChannel;}publicvoidsetPayChannel(StringpayChannel){this.payChannelpayChannel;}}3.2 自定义观测 Convention 规范订单观测规范接口publicinterfaceOrderObservationConventionextendsObservationConventionOrderObservationContext{OverridedefaultbooleansupportsContext(Observation.Contextcontext){returncontextinstanceofOrderObservationContext;}}订单观测规范默认实现统一提取高低基数标签publicclassDefaultOrderObservationConventionimplementsOrderObservationConvention{publicstaticfinalStringOBSERVATION_NAMEorder.create;OverridepublicStringgetName(){returnOBSERVATION_NAME;}OverridepublicStringgetContextualName(OrderObservationContextcontext){returnorder 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())));}}支付观测规范接口publicinterfacePaymentObservationConventionextendsObservationConventionPaymentObservationContext{OverridedefaultbooleansupportsContext(Observation.Contextcontext){returncontextinstanceofPaymentObservationContext;}}支付观测规范默认实现统一提取高低基数标签publicclassDefaultPaymentObservationConventionimplementsPaymentObservationConvention{publicstaticfinalStringOBSERVATION_NAMEpayment.create;OverridepublicStringgetName(){returnOBSERVATION_NAME;}OverridepublicStringgetContextualName(PaymentObservationContextcontext){returnpayment 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生成的标签进行打印publicclassBizLogObservationHandlerimplementsObservationHandlerObservation.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());ThrowableerrorcontextView.getError();if(error!null){System.out.println(异常信息:error.getMessage());}System.out.println(\n);}OverridepublicbooleansupportsContext(Observation.ContextViewcontext){returntrue;}}3.4 业务服务类 测试入口同上一篇不再赘述4. 两种开发模式对比4.1 方式一业务代码直接添加标签业务代码直接调用context.addLowCardinalityKeyValue()✅优点上手简单代码直观快速实现Demo、小型工具项目无需新增Convention接口与实现类减少类数量支持运行时动态追加标签灵活性高。❌缺点标签逻辑散落在各个业务埋点处标签名称、规则修改需要改动全部埋点代码无法统一管控高低基数规范容易出现开发随意新增高基数指标标签引发Prometheus时序爆炸业务代码与可观测规则强耦合埋点代码臃肿缺少统一扩展入口同类上下文想要差异化标签只能修改业务代码不符合Spring AI、Spring Cloud等官方组件标准实现范式无法对齐开源生态规范ContextView只能读取已经存入的KeyValue无法根据业务后置数据动态计算标签。4.2 方式二ObservationConvention 标准模式✅优点关注点分离Context只承载原始业务实体标签抽取逻辑统一收敛到Convention业务埋点干净纯粹统一管控标签规范集中管理Tag名称、高低基数划分标准化评审、统一修改天然支持分层扩展通用默认实现 业务/厂商自定义子类局部覆写标签逻辑开闭原则框架自动在start()/stop()两个阶段重新执行标签提取支持根据响应、异常等后置数据生成标签对齐Micrometer、Spring AI官方最佳实践便于后续对接各类中间件观测规范可统一设置观测静态名称、上下文展示名称统一指标命名规范。❌缺点项目需要新增一组Convention接口、实现类前期代码量更多学习成本更高需要理解整套分层范式如果需要运行时动态标签需要在Context中预先存入临时字段供Convention读取。4.3 选型建议Demo、小型脚本、一次性工具直接使用addLowCardinalityKeyValue降低开发成本中大型业务项目、SDK、中间件组件、框架封装强制使用ObservationConvention模式长期维护、多团队协作、需要统一监控规范的工程优先Convention方案。
返回列表