文章目录
- [1. 生命周期](#1. 生命周期)
-
- [1.1 Handler 回调](#1.1 Handler 回调)
- [1.2 生命周期事件](#1.2 生命周期事件)
-
- [1.2.1 start 观测启动事件](#1.2.1 start 观测启动事件)
- [1.2.2 stop 观测终止事件](#1.2.2 stop 观测终止事件)
- [1.2.3 error 异常事件](#1.2.3 error 异常事件)
- [1.2.4 event 自定义事件](#1.2.4 event 自定义事件)
- [1.2.5 scope started 作用域开启事件](#1.2.5 scope started 作用域开启事件)
- [1.2.6 scope stopped 作用域关闭事件](#1.2.6 scope stopped 作用域关闭事件)
- [1.3 执行流程](#1.3 执行流程)
- [2. ObservationView 接口](#2. ObservationView 接口)
-
- [2.1 基础定位](#2.1 基础定位)
- [2.2 三个方法](#2.2 三个方法)
-
- [2.2.1 etContextView()](#2.2.1 etContextView())
- [2.2.2 getObservationRegistry()](#2.2.2 getObservationRegistry())
- [2.2.3 getEnclosingScope()](#2.2.3 getEnclosingScope())
- [3. Observation 接口](#3. Observation 接口)
-
- [3.1 基础定位](#3.1 基础定位)
- [3.2 生命周期方法](#3.2 生命周期方法)
-
- [3.2.1 start()](#3.2.1 start())
- [3.2.2 openScope ()](#3.2.2 openScope ())
- [3.2.3 error (Throwable error)](#3.2.3 error (Throwable error))
- [3.2.4 event (Event event)](#3.2.4 event (Event event))
- [3.2.5 stop ()](#3.2.5 stop ())
- [3.3 链式配置方法](#3.3 链式配置方法)
-
- [3.3.1 ntextualName(String contextualName)](#3.3.1 ntextualName(String contextualName))
- [3.3.2 parentObservation(Observation parentObservation)](#3.3.2 parentObservation(Observation parentObservation))
- [3.3.3 lowCardinalityKeyValue / lowCardinalityKeyValues](#3.3.3 lowCardinalityKeyValue / lowCardinalityKeyValues)
- [3.3.4 highCardinalityKeyValue / highCardinalityKeyValues](#3.3.4 highCardinalityKeyValue / highCardinalityKeyValues)
- [3.3.4 observationConvention(ObservationConvention<?> observationConvention)](#3.3.4 observationConvention(ObservationConvention<?> observationConvention))
- [3.3.4 getContext()](#3.3.4 getContext())
- [3.3.4 isNoop()](#3.3.4 isNoop())
- [3.4 静态工厂方法](#3.4 静态工厂方法)
-
- [3.4.1 createNotStarted()](#3.4.1 createNotStarted())
- [3.4.2 start () 静态重载](#3.4.2 start () 静态重载)
- [3.5 封装模板工具方法](#3.5 封装模板工具方法)
-
- [3.4.1 observe () 系列(Runnable / Supplier / Checked)](#3.4.1 observe () 系列(Runnable / Supplier / Checked))
- [3.5.2 scoped () 系列](#3.5.2 scoped () 系列)
- [4. SimpleObservation](#4. SimpleObservation)
-
- [4.1 核心成员](#4.1 核心成员)
- [4.2 构造函数](#4.2 构造函数)
-
- [4.2.1 构造函数 1:基于名称构建](#4.2.1 构造函数 1:基于名称构建)
- [4.2.2 构造函数2:基于 ObservationConvention 构建](#4.2.2 构造函数2:基于 ObservationConvention 构建)
- [4.2.3 内部辅助静态方法](#4.2.3 内部辅助静态方法)
- [4.3 生命周期核心方法](#4.3 生命周期核心方法)
-
- [4.3.1 start()](#4.3.1 start())
- [4.3.2 openScope()](#4.3.2 openScope())
- [4.3.3 event()](#4.3.3 event())
- [4.3.4 error()](#4.3.4 error())
- [4.3.5 stop()](#4.3.5 stop())
1. 生命周期
生命周期 描述了 Observation 从 start() 正式启动观测开始,直到 stop() 结束观测为止的整个运行流程。
只有吃透完整生命周期与事件触发时机,才能写出规范、无泄漏、链路完整的埋点代码,否则极易出现 Span 丢失、标签缺失、上下文错乱、内存泄漏等线上疑难问题。
1.1 Handler 回调
想要执行观测,需要通过 ObservationRegistry 注册若干 ObservationHandler 对象。Handler 的全部能力,依托 Observation 生命周期事件驱动。
ObservationHandler 仅对自身支持的 Observation.Context 实现作出响应,它可以通过响应观测的生命周期事件,创建计时器(Timer)、追踪跨度(Span)以及关联日志。
只需使用 Observation 对代码完成一次埋点,注册多少个 ObservationHandler,就能获得对应数量的可观测能力。
1.2 生命周期事件
重要区分:
start/stop/error/event:观测主体生命周期事件 ,管控一次观测(Timer/Span)的起止;scope started/scope stopped:作用域事件,仅控制追踪上下文在线程内是否生效,不影响观测本身是否运行。
观测状态流转图:
text
Observation Context
Created(已创建) ----------> Started(已启动) ----------> Stopped(已终止)
观测作用域状态流转图:
javascript
Observation Context
Scope Started(作用域开启) ----------> Scope Finished(作用域结束)
1.2.1 start 观测启动事件
触发时机 :调用 Observation.start()
执行逻辑:
- 执行
ObservationConvention,填充观测名称、高低基数标签; - 正向遍历所有通过
supportsContext校验的ObservationHandler,执行onStart(Context)。
典型 Handler 行为 :
- 追踪处理器:创建分布式追踪
Span; - 指标处理器:记录起始时间戳,用于后续耗时计算。
规范约束:所有自定义标签、父观测、观测策略配置,建议在 start() 调用之前完成;观测启动后新增标签,存在无法被处理器捕获的风险。
1.2.2 stop 观测终止事件
触发时机 :调用 Observation.stop()
执行逻辑:
- 再次执行
ObservationConvention补充标签; - 依次执行所有
ObservationFilter,允许运行时修改上下文; - 逆序遍历 匹配的
ObservationHandler,执行onStop(Context)。
典型 Handler 行为 :
- 追踪处理器:结束
Span,上报追踪数据; - 指标处理器:计算执行耗时,生成并上报
Timer指标。
⚠️ 关键约束:
start()和stop()必须成对出现;遗漏stop()将造成Span永久悬挂、指标缺失、内存泄漏。stop()不会自动关闭Scope,必须手动执行scope.close()。
1.2.3 error 异常事件
触发时机 :调用 Observation.error(Throwable)
执行逻辑:
- 将异常存入
Context; - 正向遍历匹配的
ObservationHandler,执行onError(Context)。
典型 Handler 行为 :
- 追踪处理器:为
Span标记异常、设置错误状态码,写入异常堆栈信息。
⚠️ 常见误区:
- 调用
error()仅仅标记异常,不会终止观测生命周期 ,依旧必须调用stop()。
1.2.4 event 自定义事件
触发时机 :调用 Observation.event(Event)
执行逻辑:正向遍历匹配的 ObservationHandler,执行 onEvent(Event, Context)。
适用场景:在观测运行期间记录业务关键节点,例如「开始调用工具」「收到第三方响应」等,事件会作为日志节点嵌入追踪 Span 中。
约束:仅允许在 start() 之后、stop() 之前调用;观测终止后再添加事件会被处理器忽略。
1.2.5 scope started 作用域开启事件
触发时机 :调用 Observation.openScope()
执行逻辑:创建 Scope 对象,正向遍历处理器执行 onScopeOpened(Context),并将观测上下文绑定到当前线程。
典型 Handler 行为 :
- 将
traceId、spanId、Baggage等信息写入线程本地变量(ThreadLocal/MDC),保证同线程下游代码自动继承追踪上下文。
1.2.6 scope stopped 作用域关闭事件
触发时机 :调用 Observation.Scope.close()
执行逻辑:遍历处理器执行 onScopeClosed(Context),清理线程本地追踪上下文,Scope 栈向上回退。
⚠️ 核心边界:
close()是Scope实例自身的方法,不属于Observation接口,它只负责生产Scope对象;scope.close()只会清理线程上下文,不会停止观测、不会触发 stop 事件。观测依然处于运行状态,计时持续进行;- 规范写法优先使用
try-with-resources,保证作用域一定会关闭,避免上下文栈错乱。
1.3 执行流程

createNotStarted() // 创建对象,无事件触发【不属于生命周期事件】
↓ 预配置标签
start() // 触发 start 事件
↓
openScope() // 触发 scope started 事件
↓
执行业务代码
├─ observation.event() // 触发 event 事件
└─ observation.error() // 触发 error 事件(异常场景)
↓
scope.close() // 触发 scope stopped 事件
↓
stop() // 触发 stop 事件
完整时序图:

2. ObservationView 接口
2.1 基础定位
包路径:io.micrometer.observation.ObservationView
版本:Micrometer 1.10.0 引入
核心作用: 对外暴露只读能力,禁止修改观测生命周期与上下文。
ObservationView 是 Observation 的只读视图接口 ,实现读写分离、最小权限控制。只提供查询能力,屏蔽所有观测生命周期修改操作,保证分布式追踪、metrics 埋点链路不会被外部代码随意破坏。
java
public interface ObservationView {
default ObservationRegistry getObservationRegistry() {
return ObservationRegistry.NOOP;
}
ContextView getContextView();
@Nullable
default Observation.Scope getEnclosingScope() {
return Observation.Scope.NOOP;
}
}
很多
ObservationHandler、回调只需要读取上下文,不需要调用start()/stop()/lowCardinalityKeyValue(),对外只传递ObservationView,避免外部代码错误篡改观测状态。
2.2 三个方法
2.2.1 etContextView()
获取只读上下文视图:
- 无法调用
addLowCardinalityKeyValue、put、setError等修改方法; - 只能读取
name、tags、error、parentObservation; - 底层实现:
SimpleObservation直接返回自身Context(Context同时实现ContextView)。
java
/**
* Returns the {@link ContextView} attached to this observation.
* @return corresponding context
*/
ContextView getContextView();
2.2.2 getObservationRegistry()
默认实现返回 NOOP 注册表;
SimpleObservation重写该方法,返回绑定真实ObservationRegistry。- 用途:
Handler在回调内可以拿到当前观测归属的registry。
java
/**
* Returns the {@link ObservationRegistry} attached to this observation.
* @return corresponding observation registry
* @since 1.10.10
*/
default ObservationRegistry getObservationRegistry() {
return ObservationRegistry.NOOP;
}
2.2.3 getEnclosingScope()
获取当前线程上一层嵌套 Scope ,默认返回 NOOP;SimpleObservation 重写:从 lastScope(Thread → Scope map)读取当前线程绑定的外层 Scope。
适用场景:
- 判断当前观测是否被嵌套执行、区分父子
Scope;
3. Observation 接口
3.1 基础定位
这是 Micrometer Observation 顶层接口,定义观测生命周期、作用域模型、上下文、异步工具方法 ;SimpleObservation 是唯一标准实现,NOOP 是空实现(关闭观测时生效)。
顶层设计思想:一次埋点,多观测输出 。业务代码只编写一套 Observation 埋点;通过注册不同 ObservationHandler,可以同时产出:Metrics(Timer/Counter)、Tracing Span、日志MDC 注入、事件告警等。
内部类型:
| 内部类型 | 说明 |
|---|---|
Context |
可变数据容器,ConcurrentHashMap + name + error + parent + KeyValues |
ContextView |
Context 的只读视图接口 |
Scope |
AutoCloseable,代表 observation 在线程上的活跃期 |
Event |
任意自定义事件,Event.of(name, contextualName) |
CheckedRunnable<E> / CheckedCallable<T,E> / CheckedFunction<T,R,E> |
支持受检异常的函数式接口 |
关键边界总结(可直接放进文档总结)
两套生命周期严格分离
Observation 主体生命周期:start() → stop()
Scope 作用域生命周期:openScope() → Scope.close()
Scope.close() 是 Scope 接口方法,Observation不存在 close () 方法;
配置方法(标签、parent、convention)必须放在 start() 之前;
observe() 全自动生命周期;scoped() 只管理作用域,不启停观测;
error() 仅标记异常,不能替代 stop();
createNotStarted 属于实例创建阶段,不属于观测生命周期。
3.2 生命周期方法
Observation(观测)生命周期:从 start() 正式启动观测开始,直到 stop() 结束观测为止的整个运行时间段。
3.2.1 start()
作用 :正式启动观测;初始化计时、执行 ObservationConvention 填充标签、正向依次触发所有 ObservationHandler#onStart()。
配套约束:
- 必须在
createNotStarted()之后执行; - 禁止多次调用
start (); start()必须在stop()之前调用;NOOP Observation调用无副作用。
java
/**
* Starts the observation. Remember to call this method, otherwise timing calculations
* will not take place.
* @return this
*/
Observation start();
3.2.2 openScope ()
作用 :创建线程作用域 Scope,将当前观测绑定到线程本地 (ThreadLocal);让 MDC、Tracing 上下文、Baggage 在当前线程可见。
配套约束:
Scope必须close (),优先try-with-resources- 不要手动缓存
Scope在全局变量;Scope绑定线程 - 跨线程不能直接传递
Scope对象,需要使用scope.makeCurrent () openScope可以多次调用(嵌套场景),close顺序必须逆序
java
/**
* When put in scope, additional operations can take place by the
* {@link ObservationHandler}s such as putting entries in thread local.
* @return new scope
*/
Scope openScope();
Scope 内置三个关键方法(属于生命周期配套):
java
interface Scope extends AutoCloseable {
void close(); // 关闭作用域,回退上层scope,触发onScopeClosed
void reset(); // 清空当前线程所有Observation ThreadLocal,不维护栈
void makeCurrent(); // 异步恢复上下文专用,重建Scope栈
}
3.2.3 error (Throwable error)
作用 :标记观测发生异常,向所有 Handler 推送异常信息;不会自动停止观测。
java
/**
* Signals an error.
* @param error error
* @return this
*/
Observation error(Throwable error);
❌ 误区:调用 error () ≠ stop (),依然必须手动 stop ()
3.2.4 event (Event event)
作用 :在观测生命周期内添加自定义事件(Span 内部事件日志),用于记录关键节点。
java
/**
* Signals an arbitrary {@link Event}.
* @param event event
* @return this
*/
Observation event(Event event);
区分:event 是自定义节点日志;error 专门用于异常;不要用 event 替代 error。
3.2.5 stop ()
作用:观测生命周期终点,代表本次观测正式结束。
java
/**
* Stop the observation. Remember to call this method, otherwise timing calculations
* won't be finished.
*/
void stop();
3.3 链式配置方法
作用 :预配置观测元数据;启动后再设置,存在标签无法被捕获的风险,必须在 start () 之前调用。
3.3.1 ntextualName(String contextualName)
设置上下文名称(动态 Span 名称)。区别于固定观测名称,可根据运行时信息动态覆盖 Span 展示名称,例如 HTTP 请求路径。
java
/**
* Sets the name that can be defined from the contents of the context. E.g. a span
* name should not be the default observation name but one coming from an HTTP
* request.
* @param contextualName contextual name
* @return this
*/
Observation contextualName(@Nullable String contextualName);
3.3.2 parentObservation(Observation parentObservation)
手动指定父观测,构建父子追踪链路。异步场景无法依靠 Scope 自动继承父链路时,手动传入父 Observation。正常同步代码打开 Scope 后,框架自动回填父观测,无需手动调用。
java
/**
* If you have access to a previously created {@link Observation} you can manually set
* the parent {@link Observation} using this method - that way you won't need to open
* scopes just to create a child observation.
*
* If you're using the {@link #openScope()} method then the parent observation will be
* automatically set, and you don't have to call this method.
* @param parentObservation parent observation to set
* @return this
*/
Observation parentObservation(@Nullable Observation parentObservation);
3.3.3 lowCardinalityKeyValue / lowCardinalityKeyValues
添加低基数标签。标签取值范围有限(模板路由、状态码、操作名称);可用于指标聚合分组。
java
Observation lowCardinalityKeyValue(KeyValue keyValue);
default Observation lowCardinalityKeyValue(String key, String value);
default Observation lowCardinalityKeyValues(KeyValues keyValues);
3.3.4 highCardinalityKeyValue / highCardinalityKeyValues
添加高基数标签。取值无限(原始 URL、用户 ID、traceId);一般仅用于分布式追踪,禁止大量用于指标分组,防止指标爆炸。
java
Observation lowCardinalityKeyValue(KeyValue keyValue);
default Observation lowCardinalityKeyValue(String key, String value);
default Observation lowCardinalityKeyValues(KeyValues keyValues);
3.3.4 observationConvention(ObservationConvention<?> observationConvention)
为当前观测绑定自定义 Convention。必须在 start () 之前设置;Convention 负责统一生成名称、标签,实现埋点代码与元数据解耦。
java
/**
* Sets an observation convention that can be used to attach key values to the
* observation. Implementations should only set the convention when it supports (see:
* {@link ObservationConvention#supportsContext(Context)}) the current
* {@link Context}. WARNING: You must set the ObservationConvention to the Observation
* before it is started.
* @param observationConvention observation convention
* @return this
*/
Observation observationConvention(ObservationConvention<?> observationConvention);
3.3.4 getContext()
定位:获取观测可变上下文 Context。
说明:Context 是 Handler 之间传递自定义数据的容器;getContextView() 返回只读视图。
java
/**
* Returns the context attached to this observation.
* @return corresponding context
*/
3.3.4 isNoop()
定位:判断当前是否为空操作观测(NOOP)。
场景:当观测被 ObservationPredicate 禁用、registry 为 null 时,返回 NOOP 实例,所有生命周期方法无副作用。
java
default boolean isNoop() {
return this == NOOP;
}
3.4 静态工厂方法
3.4.1 createNotStarted()
作用:创建观测实例,不会启动观测。
创建观测实例,不属于生命周期:
java
static Observation createNotStarted(String name, @Nullable ObservationRegistry registry);
static <T extends Context> Observation createNotStarted(String name, Supplier<T> contextSupplier,
@Nullable ObservationRegistry registry);
static <T extends Context> Observation createNotStarted(@Nullable ObservationConvention<T> customConvention,
ObservationConvention<T> defaultConvention, Supplier<T> contextSupplier,
@Nullable ObservationRegistry registry);
3.4.2 start () 静态重载
定位 :内部等价 createNotStarted(...).start();创建并立刻启动观测。观测一旦创建已经启动,无法预先链式配置标签。
java
static Observation start(String name, @Nullable ObservationRegistry registry);
static <T extends Context> Observation start(String name, Supplier<T> contextSupplier,
@Nullable ObservationRegistry registry);
3.5 封装模板工具方法
重点区分 observe () vs scoped ()
observe():自动执行 start() + stop();完整管理观测生命周期;
scoped() 不会调用 start () /stop (),仅管理 Scope;
适用场景:外层已经启动观测,内层代码临时开启线程上下文。
3.4.1 observe () 系列(Runnable / Supplier / Checked)
全自动管理完整生命周期,自动打开、关闭 Scope,自动 start/stop,适合同步简单场景,减少模板代码。
内部标准流程
java
start()
try (Scope scope = openScope()) {
执行业务逻辑
} catch (Throwable error) {
error(error);
throw error;
} finally {
stop();
}
java
default void observe(Runnable runnable);
default <T> T observe(Supplier<T> supplier);
default <E extends Throwable> void observeChecked(CheckedRunnable<E> checkedRunnable);
default <T,E extends Throwable> T observeChecked(CheckedCallable<T,E> checkedCallable);
3.5.2 scoped () 系列
java
default void scoped(Runnable runnable);
default <T> T scoped(Supplier<T> supplier);
内部流程
go
try (Scope scope = openScope()) {
执行业务
} catch (Exception exception) {
error(exception);
throw exception;
}
wrap() / wrapChecked()
把原始函数包装为带观测的函数,用于线程池任务包装。
tryScoped () 静态工具
java
static void tryScoped(@Nullable Observation parent, Runnable action);
定位:父观测可能为 null 的安全封装;如果 parent 不为 null 执行 scoped;否则直接运行业务。常用于异步回调、拦截器通用逻辑。
4. SimpleObservation
这是 Micrometer Observation 默认实现类,承担整个观测生命周期管理、作用域(Scope)栈、Handler 回调调度,也是链路追踪上下文传递最关键的实现。
java
class SimpleObservation implements Observation { ... } // package-private
4.1 核心成员
核心成员变量:
handlers:Deque 双端队列,保存所有通过 supportsContext 匹配成功的处理器
context:观测上下文,存放标签、异常、父观测、自定义数据
convention:观测命名与标签策略
filters:观测结束前执行的过滤器
java
final ObservationRegistry registry;
private final Context context; // 观测上下文(tags、error、parentObservation)
private ObservationConvention convention; // 命名、自动填充KV策略
private final Deque<ObservationHandler> handlers; // 生命周期回调处理器(Tracing、Metrics)
private final Collection<ObservationFilter> filters; // stop阶段上下文过滤
final Map<Thread, Scope> lastScope = new ConcurrentHashMap<>(); // 线程 -> 当前Scope
4.2 构造函数
SimpleObservation 提供两组构造方法,对应两种实例创建模式。
构造执行时机:Observation.createNotStarted() 内部,满足启用条件后 new SimpleObservation(...)。
相关说明:
构造阶段属于实例创建阶段(前置阶段,不属于观测生命周期)。
构造阶段不会触发任何 Handler 回调、不会启动观测;调用 start() 才正式进入生命周期。
4.2.1 构造函数 1:基于名称构建
调用 Observation.createNotStarted(name, registry) 最终进入此构造。
执行流程
- 赋值
registry、context;把传入名称设置到 Context; - 遍历注册中心内所有全局
ObservationConvention,找到第一个supportsContext(context)=true的策略; - 遍历所有
ObservationHandler,执行handler.supportsContext(context),筛选有效处理器存入Deque; - 加载全部
ObservationFilter; - 此时观测未启动,不会执行 onStart。
java
SimpleObservation(@Nullable String name, ObservationRegistry registry, Context context) {
this.registry = registry;
this.context = context;
// 将观测名称写入上下文
this.context.setName(name);
// 从 Registry 全局配置匹配可用 ObservationConvention
this.convention = getConventionFromConfig(registry, context);
// 筛选所有支持当前 Context 的 ObservationHandler,存入队列
this.handlers = getHandlersFromConfig(registry, context);
// 加载全局过滤器
this.filters = registry.observationConfig().getObservationFilters();
}
4.2.2 构造函数2:基于 ObservationConvention 构建
执行流程
- 赋值注册中心、上下文;筛选匹配的 Handler、加载 Filter;
- 强制校验传入 convention 是否适配当前 Context;不匹配直接抛异常;
和构造1区别:不再从全局配置搜寻 Convention,直接使用传入自定义 Convention。
- 观测名称不在构造阶段设置 ,延后在
start()方法中由convention.getName()填充。
调用携带 customConvention 参数的 createNotStarted() 重载方法。
java
SimpleObservation(ObservationConvention<? extends Context> convention, ObservationRegistry registry,
Context context) {
this.registry = registry;
this.context = context;
this.handlers = getHandlersFromConfig(registry, context);
this.filters = registry.observationConfig().getObservationFilters();
// 校验 convention 是否支持当前上下文,不支持直接抛出异常
if (convention.supportsContext(context)) {
this.convention = convention;
}
else {
throw new IllegalStateException(
"Convention [" + convention + "] doesn't support context [" + context + "]");
}
}
4.2.3 内部辅助静态方法
getConventionFromConfig:遍历注册中心全局 Convention,返回第一个匹配上下文的策略;无匹配返回 null。
java
@Nullable
private static ObservationConvention getConventionFromConfig(ObservationRegistry registry, Context context) {
for (ObservationConvention<?> convention : registry.observationConfig().getObservationConventions()) {
if (convention.supportsContext(context)) {
return convention;
}
}
return null;
}
getHandlersFromConfig遍历所有注册的处理器,通过 supportsContext 过滤,存入双端队列。
队列顺序决定:
onStart/onScopeOpened正序执行;onStop/onScopeClosed通过descendingIterator()逆序执行。
java
private static Deque<ObservationHandler> getHandlersFromConfig(ObservationRegistry registry, Context context) {
Collection<ObservationHandler<?>> handlers = registry.observationConfig().getObservationHandlers();
Deque<ObservationHandler> deque = new ArrayDeque<>(handlers.size());
for (ObservationHandler handler : handlers) {
if (handler.supportsContext(context)) {
deque.add(handler);
}
}
return deque;
}
4.3 生命周期核心方法
4.3.1 start()
关键结论
Convention在start()执行第一次标签填充;- Handler 正序执行 onStart;
start()内部不会创建 Scope ;Scope需要主动调用openScope()。
java
@Override
public Observation start() {
if (this.convention != null) {
// 1. 从 Convention 读取标签写入上下文
this.context.addLowCardinalityKeyValues(convention.getLowCardinalityKeyValues(context));
this.context.addHighCardinalityKeyValues(convention.getHighCardinalityKeyValues(context));
// 2. Convention 可以覆盖观测名称
String newName = convention.getName();
if (StringUtils.isNotBlank(newName)) {
this.context.setName(newName);
}
}
// 3. 正序触发 onStart
notifyOnObservationStarted();
return this;
}
void notifyOnObservationStarted() {
for (ObservationHandler handler : this.handlers) {
handler.onStart(this.context);
}
}
4.3.2 openScope()
- 创建
SimpleScope时自动记录上一级 Scope(previousObservationScope),形成链表栈; - 触发
onScopeOpened,写入 ThreadLocal / MDC; openScope()仅仅生成 Scope,不会自动 close。
java
@Override
public Scope openScope() {
// 创建 SimpleScope
Scope scope = new SimpleScope(this.registry, this);
// 正序触发 onScopeOpened
notifyOnScopeOpened();
lastScope.put(Thread.currentThread(), scope);
return scope;
}
void notifyOnScopeOpened() {
for (ObservationHandler handler : this.handlers) {
handler.onScopeOpened(this.context);
}
}
4.3.3 event()
正序执行 onEvent,仅能在 start() 之后、stop() 之前有效。
java
@Override
public Observation event(Event event) {
notifyOnEvent(event);
return this;
}
void notifyOnEvent(Event event) {
for (ObservationHandler handler : this.handlers) {
handler.onEvent(event, this.context);
}
}
4.3.4 error()
- 将异常存入
Context; - 触发
onError; - ⚠️ 不会停止观测,不会调用 stop()。
java
@Override
public Observation error(Throwable error) {
this.context.setError(error);
notifyOnError();
return this;
}
void notifyOnError() {
for (ObservationHandler handler : this.handlers) {
handler.onError(this.context);
}
}
4.3.5 stop()
java
@Override
public void stop() {
if (this.convention != null) {
// 1. stop 阶段再次执行 Convention(可以填充运行时数据)
this.context.addLowCardinalityKeyValues(convention.getLowCardinalityKeyValues(context));
this.context.addHighCardinalityKeyValues(convention.getHighCardinalityKeyValues(context));
String newContextualName = convention.getContextualName(context);
if (StringUtils.isNotBlank(newContextualName)) {
this.context.setContextualName(newContextualName);
}
}
// 2. 依次执行 ObservationFilter,可以修改上下文
Context modifiedContext = this.context;
for (ObservationFilter filter : this.filters) {
modifiedContext = filter.map(modifiedContext);
}
// 3. 逆序执行 onStop
notifyOnObservationStopped(modifiedContext);
}
void notifyOnObservationStopped(Context context) {
this.handlers.descendingIterator().forEachRemaining(handler -> handler.onStop(context));
}