Micrometer 系列【53】统一观测:ObservationHandler | 观测处理器
发布时间:2026/8/13 10:35:56 作者:尧图编辑部 阅读量:1,286

文章目录1. 概述2. ObservationHandler2.1 TracingObservationHandler2.1.1 PropagatingSenderTracingObservationHandler2.1.2 DefaultTracingObservationHandler2.1.3 PropagatingReceiverTracingObservationHandler2.2 MeterObservationHandler2.2.1 DefaultMeterObservationHandler2.2.2 TracingAwareMeterObservationHandler2.3 CompositeObservationHandler2.3.1 AllMatchingCompositeObservationHandler2.3.2 FirstMatchingCompositeObservationHandler2.4 ObservationTextPublisher3. 工作流程3.1 注册流程3.2 执行流程3.2.1 创建 SimpleObservation3.2.2 start()正序 onStart3.2.3 openScope()正序 onScopeOpened3.2.4 event()正序 onEvent可选3.2.5 stop()逆序 onStop3.2.6 scope.close()逆序 onScopeClosed1. 概述Observation是Micrometer 1.10.0引入的统一观测模型核心抽象用于封装一段程序操作并定义完整生命周期依托ObservationHandler插件机制实现一次埋点可扩展生成指标、分布式追踪Span、关联日志等多种可观测数据实现业务代码与监控能力解耦。ObservationHandler用于接入Observation的完整生命周期提供一系列生命周期回调方法。开发者可实现该接口在观测运行的各个阶段执行自定义行为。配合组合处理器可以为同一个Observation挂载多个处理器实现一次埋点同时生成指标、链路Span、关联日志等功能。2. ObservationHandler观察者模式的观察者接口。Observation被观察者在其生命周期每个节点start/scope开闭 /event/error/stop上同步遍历所有已注册handler调用对应回调。生命周期 ↔ 回调映射业务代码 回调正序 1→2→3 / 逆序 3→2→1 ───────────────────────────────────────────────────────────── Observation.start(...) → onStart 正序 try (Observation.Scope s observation.openScope()) → onScopeOpened 正序 ... observation.event(E) → onEvent 正序 } // s.close() → onScopeClosed 逆序 ... observation.error(e) → onError 正序 observation.stop() → onStop 逆序方法汇总方法签名触发时机职责onStartvoid onStart(T context)observation.start()开启性工作Tracing 族在此创建 spanMeter 族在此启动 Timer.SampleonErrorvoid onError(T context)observation.error(e)异常处理Tracing 族span.error(e)Meter 族用异常类名打 error tagonEventvoid onEvent(Observation.Event event, T context)observation.event(...)业务事件Tracing 族span.event(name)Meter 族Counter.increment()onScopeOpenedvoid onScopeOpened(T context)observation.openScope()作用域打开把 span 挂到线程上下文Tracing 族默认实现onScopeClosedvoid onScopeClosed(T context)scope.close()作用域关闭清理线程上下文。逆序通知后注册的先收到onScopeResetvoid onScopeReset(T context)已废弃 API 调用Deprecated仅老Scope.reset()触发Micrometer 自身不再使用清理请用 onScopeClosedonStopvoid onStop(T context)observation.stop()收尾Tracing 族命名打标结束 spanMeter 族记录 Timer。同样逆序通知supportsContextboolean supportsContext(Observation.Context context)注册/分发时唯一的抽象方法。告诉注册中心这个 handler 是否适用当前 Context是分发开关。注意参数不带泛型——匹配基于运行时类型2.1 TracingObservationHandler继承自ObservationHandler的标记父接口是所有分布式追踪处理器的顶层抽象。定义了创建Span、标签注入、异常标记、事件上报、线程上下文Scope管理、父子Span传递等通用分布式追踪逻辑。内置TracingContext用于在Observation.Context中缓存Span与线程追踪作用域信息。开发者实现该接口并提供Tracer实例即可完成链路追踪能力接入。三大追踪处理器完整对比表处理器上下文类型场景传播动作Span Kind使用位置DefaultTracingObservationHandlerObservation.Context本地方法、内部逻辑无传播未指定进程内埋点PropagatingSenderTracingObservationHandlerSenderContextHTTP客户端、消息生产者inject写入载体CLIENT调用方、发送方PropagatingReceiverTracingObservationHandlerReceiverContextHTTP服务端、消息消费者extract读取载体SERVER / CONSUMER被调用方、消费方2.1.1 PropagatingSenderTracingObservationHandler客户端/消息生产者追踪处理器创建CLIENT类型Span并把Trace信息注入请求载体实现分布式追踪跨进程传播2.1.2 DefaultTracingObservationHandler通用追踪处理器为普通Observation创建Span适用于本地逻辑埋点不包含Trace上下文跨进程传播逻辑。2.1.3 PropagatingReceiverTracingObservationHandler服务端/消息消费者追踪处理器从载体提取上游Trace信息创建SERVER/CONSUMER Span承接远端传递过来的分布式链路。2.2 MeterObservationHandler指标采集专用标记父接口用于在Observation生命周期中生成耗时、计数等监控指标和链路追踪处理器并行工作。2.2.1 DefaultMeterObservationHandlerObservation默认指标处理器自动生成调用耗时、活跃并发数、事件计数三类指标一次埋点产出时序监控数据。onStart时指标产出明细创建Timer.Sample记录起始时间用于最终计算单次耗时创建LongTaskTimer.Sample长任务计时器指标名${name}.active表征当前正在执行的请求并发量onStop时指标产出明细组装标签所有lowCardinalityKeyValueserror标签Timer.Sample.stop()→ 上报${name}Timerp95/p99、吞吐量停止LongTaskTimer样本活跃计数递减onEvent时指标产出明细生成Counter${name}.${eventName}计数12.2.2 TracingAwareMeterObservationHandler指标处理器装饰器保证指标stop阶段线程持有Span上下文用以支持指标Exemplar嵌入traceId。原生时序问题Observation.start()Observation.openScope()业务逻辑Observation.closeScope()// ⚠️ Scope销毁线程脱离Span上下文Observation.stop()// 执行DefaultMeterObservationHandler.onStop上报Timer当执行onStop时Scope已经关闭当前线程不再持有Span。如果指标采集逻辑需要读取tracer.currentSpan()获取traceIdExemplar此时读取不到。在委托执行delegate.onStop()之前手动把存储在TracingContext里的Span重新绑定到线程执行完毕自动释放Scope。2.3 CompositeObservationHandlerObservationRegistry支持注册多个Handler通过组合模式统一调度一批Handler实现「一次Observation生命周期事件分发到多个处理器」。CompositeObservationHandler是嵌套在ObservationHandler接口内部的组合器顶层接口同时提供两种内置实现2.3.1 AllMatchingCompositeObservationHandler遍历全部执行所有匹配成功的Handler。任意生命周期事件遍历内部所有Handler调用handler.supportsContext(context)判断是否匹配所有匹配成功的处理器依次执行对应生命周期方法supportsContext(context)只要列表中至少一个Handler匹配就返回true典型场景一次埋点同时产出指标 链路追踪2.3.2 FirstMatchingCompositeObservationHandler找到第一个匹配的Handler执行仅此一个。任意生命周期事件顺序遍历Handler找到第一个满足supportsContext(context)的处理器仅执行这一个后续Handler不再遍历supportsContext(context)存在首个匹配则返回true互斥处理器场景同一上下文只能选择一套处理逻辑不允许多个处理器同时生效。2.4 ObservationTextPublisher将观测上下文转换为文本并推送至自定义Consumer。ObservationHandler的内置实现用于调试观测生命周期它监听Observation全部生命周期事件将事件类型与观测上下文转换成文本输出到自定义接收器。支持配置过滤规则、自定义上下文格式化逻辑默认输出INFO日志。生产环境不建议常驻启用多用于开发排查埋点问题3. 工作流程3.1 注册流程业务代码ObservationRegistryobservationRegistryObservationRegistry.create();// 0observationRegistry.observationConfig()// 1.observationHandler(newDefaultTracingObservationHandler(tracer))// 2.observationHandler(newTracingAwareMeterObservationHandler(new// 3DefaultMeterObservationHandler(meterRegistry),tracer));observationConfig()返回一个ObservationRegistry.ObservationConfig实例内含4个CopyOnWriteArrayListobservationHandlersobservationPredicatesobservationConventionsobservationFiltersObservationHandler示例存放在observationHandlers中3.2 执行流程业务代码ObservationobservationObservation.createNotStarted(demo,observationRegistry);// 0 创建observation.start();// 1 starttry(Observation.Scopescopeobservation.openScope()){// 2 openScopeobservation.event(Event.of(step1));// 3 event可选// ... 业务代码 ...observation.error(ex);// 4 error可选observation.stop();// 5 stop}// 6 scope.close()3.2.1 创建 SimpleObservationSimpleObservation构造器中会调用getHandlersFromConfig(registry, context)方法通过supportsContext收集当前观测点支持的所有处理器DequeObservationHandlerdequenewArrayDeque(handlers.size());for(ObservationHandlerhandler:handlers){if(handler.supportsContext(context)){// ← 唯一的过滤点deque.add(handler);}}3.2.2 start()正序 onStartSimpleObservation#start()中调用notifyOnObservationStarted正序遍历所有处理器voidnotifyOnObservationStarted(){for(ObservationHandlerhandler:this.handlers){// 正序Deque 迭代顺序handler.onStart(this.context);}}DefaultTracingObservationHandler中会创建子Span并启动建立父子链路关联/** * Observation 生命周期启动回调 * 创建子Span并启动建立父子链路关联 * param context 当前观测上下文 */OverridepublicvoidonStart(Observation.Contextcontext){// 获取当前上下文已存在的父Span用于构建链路父子关系SpanparentSpangetParentSpan(context);// 存在父Span则基于父Span创建子Span无父Span则新建独立根SpanSpanchildSpanparentSpan!null?getTracer().nextSpan(parentSpan):getTracer().nextSpan();if(childSpan!null){// 启动Span计时childSpan.start();// 将创建好的Span存入观测上下文供后续scope、stop等生命周期使用getTracingContext(context).setSpan(childSpan);}}DefaultMeterObservationHandler中会初始化指标采集样本OverridepublicvoidonStart(Observation.Contextcontext){// 如果开启长任务计时器创建LongTaskTimer采样对象统计并发活跃请求if(shouldCreateLongTaskTimer){LongTaskTimer.SamplelongTaskSamplemeterRegistry.more().longTaskTimer(context.getName().active,createTags(context)).start();// 将采样实例存入上下文onStop阶段取出结束计时context.put(LongTaskTimer.Sample.class,longTaskSample);}// 创建单次耗时Timer采样记录起始时间点Timer.SamplesampleTimer.start(meterRegistry);// 存入上下文等待onStop计算耗时并上报指标context.put(Timer.Sample.class,sample);}3.2.3 openScope()正序 onScopeOpenedSimpleObservation.openScope()中会正序调用所有处理器的onScopeOpened方法voidnotifyOnScopeOpened(){for(ObservationHandlerhandler:this.handlers){handler.onScopeOpened(this.context);}}TracingObservationHandler会触发将Span绑定至当前线程/** * Observation Scope 开启回调将 Span 绑定至当前线程。 * param context 观测上下文 */OverridedefaultvoidonScopeOpened(Tcontext){TracingContexttracingContextgetTracingContext(context);SpanspantracingContext.getSpan();setMaybeScopeOnTracingContext(tracingContext,span);}3.2.4 event()正序 onEvent可选SimpleObservation.event()中会正序调用所有处理器的onEvent方法voidnotifyOnEvent(Eventevent){for(ObservationHandlerhandler:this.handlers){handler.onEvent(event,this.context);}}TracingObservationHandler会触发向Span追加事件记录/** * Observation 自定义事件回调向Span追加事件记录 * param event 观测事件对象 * param context 观测上下文 */OverridedefaultvoidonEvent(Eventevent,Tcontext){// 获取事件时间戳毫秒壁钟时间longtimestampevent.getWallTime();if(timestamp0){// 未指定时间戳使用Span当前系统时间记录事件getRequiredSpan(context).event(event.getContextualName());}else{// 使用事件自带的自定义时间戳写入Span事件getRequiredSpan(context).event(event.getContextualName(),timestamp,TimeUnit.MILLISECONDS);}}3.2.5 stop()逆序 onStopSimpleObservation.stop()中会执行收尾处理并通知所有Handler的onStop生命周期/** * 终止Observation执行收尾处理并通知所有Handler的onStop生命周期 */Overridepublicvoidstop(){// 如果配置了命名规范向上下文追加标签、更新上下文名称if(this.convention!null){// 添加低基数标签可作为指标Tagthis.context.addLowCardinalityKeyValues(convention.getLowCardinalityKeyValues(context));// 添加高基数标签仅用于链路不进入指标防止基数爆炸this.context.addHighCardinalityKeyValues(convention.getHighCardinalityKeyValues(context));StringnewContextualNameconvention.getContextualName(context);if(StringUtils.isNotBlank(newContextualName)){// 更新Observation上下文展示名称this.context.setContextualName(newContextualName);}}// 依次执行所有ObservationFilter对上下文进行转换/修改ContextmodifiedContextthis.context;for(ObservationFilterfilter:this.filters){modifiedContextfilter.map(modifiedContext);}// 分发onStop事件通知所有匹配的ObservationHandler执行收尾逻辑指标上报、Span结束等notifyOnObservationStopped(modifiedContext);}逆序遍历处理器/** * 分发Observation停止事件逆序执行所有Handler的onStop方法 * param context 经过Filter处理后的观测上下文 */SuppressWarnings(unchecked)voidnotifyOnObservationStopped(Contextcontext){// 逆序遍历处理器开启顺序 1→2→3停止顺序 3→2→1遵循先进后出的栈语义this.handlers.descendingIterator().forEachRemaining(handler-handler.onStop(context));}3.2.6 scope.close()逆序 onScopeClosedSimpleObservation.close()关闭当前Observation Scope执行Scope关闭生命周期、恢复上一层观测上下文/** * 关闭当前Observation Scope执行Scope关闭生命周期、恢复上一层观测上下文 */Overridepublicvoidclose(){if(currentObservationinstanceofSimpleObservation){SimpleObservationobservation(SimpleObservation)currentObservation;// 获取当前线程归属该Observation最新的ScopeSimpleScopelastScopeForThisObservationgetLastScope(this);if(lastScopeForThisObservation!null){// 缓存当前Scope至观测对象的线程映射observation.lastScope.put(Thread.currentThread(),lastScopeForThisObservation);}else{// 当前线程无活跃Scope移除线程映射observation.lastScope.remove(Thread.currentThread());}// 分发onScopeClosed事件通知所有Handler执行Scope关闭回调observation.notifyOnScopeClosed();}elseif(currentObservation!null!currentObservation.isNoop()){// 非SimpleObservation类型搭配SimpleScope属于不符合预期的组合打印调试日志log.debug(Custom observation type was used in combination with SimpleScope - thats unexpected);}else{// NoOp空观测仅打印跟踪日志log.trace(NoOp observation used with SimpleScope);}// 恢复线程上一层ObservationScope完成上下文出栈this.registry.setCurrentObservationScope(previousObservationScope);}逆序执行所有Handler的onScopeClosed生命周期方法/** * 分发Scope关闭事件逆序执行所有Handler的onScopeClosed生命周期方法 */voidnotifyOnScopeClosed(){// 栈语义Scope开启时处理器正序执行1→2→3关闭时逆序执行3→2→1先进后出IteratorObservationHandleriteratorthis.handlers.descendingIterator();while(iterator.hasNext()){ObservationHandlerhandleriterator.next();handler.onScopeClosed(this.context);}}