
文章目录1. 概述2. MeterFilter 接口2.1 默认方法2.1.1 accept2.1.2 map2.1.3 configure2.2 静态工厂方法2.2.1 准入控制类2.2.2 Meter.Id 标签转换类2.2.3 分布统计配置类2.2.4 自定义扩展入口2.3 OnlyOnceLoggingDenyMeterFilter3. 案例演示3.1 注册过滤器3.2 允许或拒绝计量器注册3.3 链式组合3.4 指标转换3.5 配置分布统计3.6 条件生效4. 执行流程梳理1. 概述可以为每个度量注册表配置计量器过滤器从而精细管控计量器的注册时机、注册方式以及计量器所输出的统计指标类型。计量器过滤器具备三大核心能力拒绝/允许计量器完成注册转换计量器 ID例如修改指标名称、新增/移除标签、修改描述或基础单位为特定类型计量器配置分布统计信息2. MeterFilter 接口MeterFilter是Micrometer度量体系中计量器过滤器顶层接口。当应用向MeterRegistry创建计量器Meter时所有新建指标都会按照注册顺序依次经过全部MeterFilter提供三大核心能力准入控制允许/拒绝计量器注册被拒绝时注册表返回无操作NOOP计量器采集数据直接丢弃。ID 转换修改计量器标识名称、标签、描述、单位。分布统计配置为Timer/DistributionSummary自定义直方图、百分位、SLO等分布统计参数。2.1 默认方法接口全部方法均为default方法使用者按需重写无需实现全部方法。2.1.1 acceptdefault MeterFilterReply accept(Meter.Id id)准入过滤器控制计量器是否允许注册。返回值含义DENY拒绝注册ACCEPT直接放行跳过后续所有过滤器NEUTRAL交由后续过滤器继续判断2.1.2 mapdefault Meter.Id map(Meter.Id id)ID转换器修改计量器名称、标签集合返回原始 / 修改后的Meter.Id。重要约束实现不能依赖请求上下文等动态变量动态标签应在埋点层实现不要在此处处理2.1.3 configuredefault DistributionStatisticConfig configure(Meter.Id id, DistributionStatisticConfig config)分布统计配置器。仅Timer、DistributionSummary会触发用于修改直方图区间、最大 / 最小值预期、百分位配置推荐构造新配置后merge()保留原有配置。2.2 静态工厂方法接口提供大量static工厂方法快速生成常用过滤器按功能划分为4大类2.2.1 准入控制类负责控制指标是否注册底层重写accept()accept()放行所有计量器accept(PredicateMeter.Id)放行匹配断言的计量器acceptNameStartsWith(String prefix)放行名称前缀匹配的计量器deny()拒绝所有计量器deny(PredicateMeter.Id)拒绝匹配断言的计量器denyNameStartsWith(String prefix)拒绝名称前缀匹配的计量器常用禁用jvm、tomcat内置指标denyUnless(PredicateMeter.Id)白名单专用拒绝所有不匹配断言的计量器maximumAllowableMetrics(int maximumTimeSeries)全局时序数量上限防止无限创建指标引发基数爆炸maximumAllowableTags(...)限制指定指标前缀下单个标签Key允许的标签值数量超限后执行传入的过滤器策略forMeters(Predicate, MeterFilter delegate)条件包装器断言匹配时才执行代理过滤器实现「过滤器只作用于部分指标」2.2.2 Meter.Id 标签转换类用于治理标签基数、统一标签规范监控优化高频使用commonTags(IterableTag)为所有指标追加公共标签应用名、环境、区域等ignoreTags(String... tagKeys)移除指定Key的标签解决标签基数过高问题renameTag(String prefix, String fromTagKey, String toTagKey)重命名指定前缀指标内的标签KeyreplaceTagValues(String tagKey, Function, String... exceptions)标签值映射聚合降低标签基数支持配置例外值不转换2.2.3 分布统计配置类专门调整直方图桶区间影响百分位、直方图输出maxExpected(String prefix, Duration)Timer最大预期值maxExpected(String prefix, double)DistributionSummary最大预期值minExpected(String prefix, Duration)Timer最小预期值minExpected(String prefix, double)DistributionSummary最小预期值2.2.4 自定义扩展入口开发者直接new MeterFilter(){}匿名实现同时重写accept/map/configure实现复杂组合逻辑。2.3 OnlyOnceLoggingDenyMeterFilterMicrometer内置专用拒绝过滤器标签基数保护组件配套实现类。核心功能永久拒绝指标注册accept()方法固定返回MeterFilterReply.DENY被匹配的指标会变成NOOP计量器采集数据直接丢弃。警告日志只输出一次使用AtomicBoolean做开关全局仅打印一条警告日志后续触发不再输出避免日志风暴。3. 案例演示3.1 注册过滤器可通过代码方式向注册表注册MeterFilter实现类// 获取度量注册表配置对象注册多个计量器过滤器过滤器按配置顺序依次执行registry.config()// 过滤器1移除所有计量器中key为too.much.information的标签用于降低标签基数.meterFilter(MeterFilter.ignoreTags(too.much.information))// 过滤器2拒绝注册名称以jvm开头的所有计量器禁用JVM相关内置监控指标.meterFilter(MeterFilter.denyNameStartsWith(jvm));3.2 允许或拒绝计量器注册MeterFilterReply包含三种返回状态DENY拒绝禁止该计量器注册。当向注册表注册计量器过滤器返回DENY时注册表会返回一个无操作NOOP版本的计量器如NoopCounter、NoopTimer。业务代码依旧可以调用该NOOP计量器但所有写入的数据会被直接丢弃性能损耗极低。NEUTRAL中立若无前置过滤器返回DENY计量器正常执行注册流程。ACCEPT允许一旦过滤器返回ACCEPT计量器直接完成注册不再执行后续所有过滤器的accept判断逻辑。允许/拒绝过滤器的完整写法示例/** * 自定义计量器准入过滤器 * 规则拦截名称包含 test 的计量器其余指标交由后续过滤器继续判断 */newMeterFilter(){/** * 计量器注册准入判断 * param id 待注册计量器标识 * return DENY拒绝注册NEUTRAL中立交给后续过滤器处理ACCEPT直接放行跳过后续过滤器 */OverridepublicMeterFilterReplyaccept(Meter.Idid){// 指标名称包含 test则拒绝注册该计量器if(id.getName().contains(test)){returnMeterFilterReply.DENY;}// 不匹配当前规则返回中立流转至下一个过滤器继续校验returnMeterFilterReply.NEUTRAL;}}deny(PredicateMeter.Id)拦截匹配断言条件的计量器maximumAllowableMetrics(int)当注册表内计量器数量达到阈值后拒绝新增计量器maximumAllowableTags(String meterNamePrefix, String tagKey, int maximumTagValues, MeterFilter onMaxReached)限制匹配指标序列下单个标签所能产生的标签值最大数量对于监控成本较高的监控系统指标白名单是非常常见的场景可以使用下述静态方法实现denyUnless(PredicateMeter.Id)拦截所有不匹配断言的计量器仅放行匹配项实现白名单3.3 链式组合过滤器严格按照注册表上配置的顺序执行可以多层叠加放行、拦截过滤器实现复杂规则registry.config().meterFilter(MeterFilter.acceptNameStartsWith(http)).meterFilter(MeterFilter.deny());以上通过两层过滤器实现白名单效果该注册表中仅允许http开头的指标注册。3.4 指标转换转换过滤器示例/** * 自定义计量器ID转换过滤器 * 规则对名称以 test 开头的计量器进行名称前缀追加并新增固定标签 */newMeterFilter(){/** * 转换计量器标识信息名称、标签等 * param id 原始计量器标识 * return 转换后的 Meter.Id无需转换则返回原始id */OverridepublicMeter.Idmap(Meter.Idid){// 匹配名称前缀 test 的指标修改指标名并增加标签if(id.getName().startsWith(test)){// 指标名称增加 extra. 前缀附加 extra.tagvalue 标签returnid.withName(extra.id.getName()).withTag(extra.tag,value);}// 不满足条件直接返回原始计量器标识不做任何变更returnid;}}该过滤器会为名称以test开头的计量器条件性增加名称前缀与额外标签。MeterFilter在计量器注册阶段执行Meter创建时仅执行一次而不是每次指标记录时执行。一旦计量器注册完成Meter.Id固定不变无法动态修改标签。MeterFilter#map()的实现应当保持静态无状态Meter.Id是MeterFilter生命周期内唯一合法可变输入map内部逻辑仅允许依赖该入参。允许依赖应用启动后不再变更的常量例如固定实例ID、主机名、环境标识等。禁止依赖请求上下文、ThreadLocal、单次请求动态数据来生成标签。动态标签场景不能使用MeterFilter需要在埋点 / 观测逻辑内部实现。3.5 配置分布统计Timer与DistributionSummary除基础指标计数、总和、最大值之外还支持可选的分布统计配置可通过过滤器自定义包含预计算百分位、SLO服务等级目标、直方图。newMeterFilter(){OverridepublicDistributionStatisticConfigconfigure(Meter.Idid,DistributionStatisticConfigconfig){if(id.getName().startsWith(prefix)){returnDistributionStatisticConfig.builder().percentiles(0.9,0.95).build().merge(config);}returnconfig;}};最佳实践仅构建需要修改的DistributionStatisticConfig再与入参配置执行合并。这样能够保留注册表默认配置同时支持多个过滤器链式配置分布统计例如所有HTTP指标统一开启100ms SLO仅少数核心接口开启百分位直方图。MeterFilter提供便捷方法maxExpected(Duration/long)设置Timer/Summary百分位直方图桶的上限minExpected(Duration/long)设置Timer/Summary百分位直方图桶的下限Spring Boot支持基于配置文件按指标名称前缀配置SLO、百分位、百分位直方图。3.6 条件生效forMeters(PredicateMeter.Id predicate, MeterFilter delegate)计量器匹配断言时才启用代理过滤器不匹配则跳过当前过滤器逻辑。示例/** * 条件过滤器示例仅对名称前缀匹配的指标生效标签过滤规则 * forMeters断言匹配成功才执行代理过滤器不匹配则跳过该过滤器 */registry.config()// 仅对名称以 prefix 开头的计量器执行移除 extra 标签的逻辑.meterFilter(MeterFilter.forMeters(startsWith(prefix),MeterFilter.ignoreTags(extra)));/** * 构建断言匹配名称以指定前缀开头的 Meter.Id * param prefix 指标名称前缀 * return 计量器匹配断言 */PredicateMeter.IdstartsWith(Stringprefix){returnid-id.getName().startsWith(prefix);}业务常要求过滤器只对部分计量器生效例如指定名称前缀的指标。4. 执行流程梳理创建Meter→ 依次执行所有过滤器map()修改Meter.Id遍历所有过滤器执行accept(id)任一过滤器返回ACCEPT→ 直接注册终止后续过滤器任一过滤器返回DENY→ 返回NOOP计量器全部返回NEUTRAL→ 正常注册若成功注册Timer/DistributionSummary依次执行过滤器configure()合并分布统计配置其他类型计量器Counter、Gauge等不会调用configure()。