Micrometer 系列【25】Spring Boot Actuator | Spring MVC、Spring WebFlux 指标

文章目录

  • [1. Spring MVC 指标](#1. Spring MVC 指标)
    • [1.1 查看指标](#1.1 查看指标)
      • [1.1.1 http.server.requests](#1.1.1 http.server.requests)
      • [1.1.2 http.server.requests](#1.1.2 http.server.requests)
    • [2.2 自定义指标名称](#2.2 自定义指标名称)
    • [2.3 追加自定义标签](#2.3 追加自定义标签)
      • [2.3.1 方式 1:追加标签](#2.3.1 方式 1:追加标签)
      • [2.3.2 方式 2:完全替换全部标签](#2.3.2 方式 2:完全替换全部标签)
    • [2.4 把已捕获异常埋入指标标签](#2.4 把已捕获异常埋入指标标签)
    • [2.5 自定义过滤:跳过部分请求不采集指标](#2.5 自定义过滤:跳过部分请求不采集指标)
  • [2. Spring WebFlux 指标](#2. Spring WebFlux 指标)

1. Spring MVC 指标

自动配置会对所有由 Spring MVC 控制器、函数式处理器处理的请求做指标埋点。默认生成指标名称为 http.server.requests。

1.1 查看指标

/actuator/metrics 包含两个指标名:

java 复制代码
    "http.server.requests",
    "http.server.requests.active",

1.1.1 http.server.requests

基于 Micrometer Observation 生成的 HTTP 请求计时器指标,baseUnit 单位为 seconds(秒)。

返回示例:

json 复制代码
{
  "availableTags": [
    {
      "tag": "exception",
      "values": [
        "none"
      ]
    },
    {
      "tag": "method",
      "values": [
        "GET"
      ]
    },
    {
      "tag": "error",
      "values": [
        "none"
      ]
    },
    {
      "tag": "uri",
      "values": [
        "/actuator/metrics/{requiredMetricName}",
        "/actuator/metrics",
        "/actuator/prometheus",
        "/api/redis/{key}"
      ]
    },
    {
      "tag": "outcome",
      "values": [
        "SUCCESS"
      ]
    },
    {
      "tag": "status",
      "values": [
        "200"
      ]
    }
  ],
  "baseUnit": "seconds",
  "measurements": [
    {
      "statistic": "COUNT",
      "value": 117
    },
    {
      "statistic": "TOTAL_TIME",
      "value": 2.992938
    },
    {
      "statistic": "MAX",
      "value": 0.0297637
    }
  ],
  "name": "http.server.requests"
}

整体字段概览:

字段 说明
name 指标名称:http.server.requests,服务端HTTP请求计时器
baseUnit 基础单位:seconds 秒
availableTags 该指标可用标签集合,代表会出现在 Prometheus 里的标签维度以及采样到的枚举值示例
measurements 度量统计值:COUNT总请求数、TOTAL_TIME总耗时、MAX最大耗时

availableTags 标签解读:

tag标签 示例values 含义
exception none 请求抛出的异常类名;none=无异常抛出
method GET HTTP 请求方法:GET/POST/PUT/DELETE...
error none 错误标识;none=业务无错误;发生异常时为异常类名
uri /actuator/metrics/{requiredMetricName} /actuator/metrics /actuator/prometheus /api/redis/{key} 模板化URI,不是真实路径变量值,路径中的变量被大括号占位,防止标签爆炸
outcome SUCCESS 请求结果枚举:SUCCESS/CLIENT_ERROR/SERVER_ERROR/REDIRECTION,由HTTP状态码推导
status 200 HTTP响应状态码字符串,如 200、404、500

⚠️注意:values 只是当前采样看到的取值,不是全部枚举全集,是实例已经采集到的值。

measurements 度量数据:

statistic统计类型 value值 释义
COUNT 117 总请求次数:一共117次http请求
TOTAL_TIME 2.992938 全部请求累加总耗时,单位秒:117次请求合计耗时约2.99秒
MAX 0.0297637 这一批采样窗口内最大单次请求耗时,约29.76毫秒

/metrics端点返回的是内存中快照;导出到 Prometheus 后会拆分为 3个指标:

  • http_server_requests_seconds_count 请求计数
  • http_server_requests_seconds_sum 总耗时
  • http_server_requests_seconds_max 最大耗时

1.1.2 http.server.requests

活跃请求计时器指标 ,用于观测正在处理中尚未完成的 HTTP 请求 ,和普通 http.server.requests(已完成请求)是一对指标。

访问 /actuator/metrics/http.server.requests.active 获取该快照,baseUnit: seconds 单位为秒。

字段总览:

字段 说明
name http.server.requests.active,服务端活跃HTTP请求指标,跟踪运行中未结束请求
baseUnit seconds,时间单位:秒
availableTags 可用标签集合,values为当前实例已经采集到的样本值
measurements 度量统计:ACTIVE_TASKS活跃并发数、DURATION累计耗时、MAX最大处理时长

availableTags 标签解读:

tag标签 示例values 含义
exception none 活跃请求发生异常;活跃阶段一般不会产生异常,几乎总是none
method GET HTTP请求方法
uri UNKNOWN 无法解析控制器映射模板时标记为UNKNOWN ;常见原因:404无匹配接口、过滤器提前拦截、静态资源、未走到控制器路由解析逻辑,会打uri=UNKNOWN标签,防止高基数标签爆炸
outcome SUCCESS 请求处理结果;活跃请求该标签意义有限,最终结果要等请求结束看http.server.requests
status 200 HTTP响应码;活跃请求此时响应码还未完全确定,参考价值低

values 仅代表当前已经观测到的值,不是全部枚举集合。
⚠️重点:uri=UNKNOWN ,请求还没匹配到控制器模板就已经结束/被拦截,拿不到模板URI,就会标记为UNKNOWN。比如 404、filter 直接 response 返回、静态资源、网关层提前终止请求。

measurements 统计值解读:

statistic统计类型 value 释义
ACTIVE_TASKS 1 当前并发活跃请求数:此刻有1个HTTP请求正在处理中,还未返回响应
DURATION 0.0024552 所有已完成的活跃任务的累计总耗时(秒)
MAX 0.002476 观测周期内,活跃请求曾经出现过的最大处理耗时,约2.476毫秒

和普通 http.server.requests 的核心区别:

指标 用途 统计的请求 主要统计项
http.server.requests 已完成请求统计 请求处理完毕(成功/异常) COUNT、TOTAL_TIME、MAX;用于QPS、延迟、错误率
http.server.requests.active 活跃并发观测 正在运行、还没结束的请求 ACTIVE_TASKS(并发数)、DURATION、MAX;用于观测瞬时并发、慢请求堆积

导出到 Prometheus 会生成下面几组时序:

text 复制代码
http_server_requests_active_seconds_active_tasks  1
http_server_requests_active_seconds_duration_sum 0.0024552
http_server_requests_active_seconds_max 0.002476

2.2 自定义指标名称

你可以通过配置 management.observations.http.server.requests.name 属性来自定义该指标名称。

示例:

yml 复制代码
management:
  observations:
    http:
      server:
        requests:
          name: myapp.http.server.requests

配置完成后:

  1. 原 http.server.requests → 变为 myapp.http.server.requests
  2. 原 http.server.requests.active → 自动变为 myapp.http.server.requests.active
  3. Actuator 端点访问地址随之变化:
    • /actuator/metrics/myapp.http.server.requests
    • /actuator/metrics/myapp.http.server.requests.active

Prometheus 导出的指标名也同步变更:

text 复制代码
myapp_http_server_requests_seconds_count
myapp_http_server_requests_seconds_sum
myapp_http_server_requests_seconds_max

myapp_http_server_requests_active_seconds_active_tasks

2.3 追加自定义标签

2.3.1 方式 1:追加标签

想要在默认标签基础上追加自定义标签,可以注册一个 @Bean,继承 org.springframework.http.server.observation 包下的 DefaultServerRequestObservationConvention。

代码示例:

java 复制代码
@Component
public class CustomAddTagServerObservationConvention extends DefaultServerRequestObservationConvention {

    @Override
    public Iterable<KeyValue> getLowCardinalityKeyValues(ServerRequestObservationContext context) {
        // 拿到默认全部标签
        Iterable<KeyValue> defaultKeyValues = super.getLowCardinalityKeyValues(context);

        Observation.ObservationView observation = context.getObservation();

        return () -> {
            var defaultIterator = defaultKeyValues.iterator();
            return new java.util.Iterator<>() {
                private boolean customTagAdded = false;

                @Override
                public boolean hasNext() {
                    return defaultIterator.hasNext() || !customTagAdded;
                }

                @Override
                public KeyValue next() {
                    if (defaultIterator.hasNext()) {
                        return defaultIterator.next();
                    }
                    if (!customTagAdded) {
                        customTagAdded = true;
                        // 追加自定义低基数标签,业务维度,例如环境、app、traceEnv
                        return KeyValue.of("app_env", "prod");
                    }
                    throw new java.util.NoSuchElementException();
                }
            };
        };
    }
}

效果:http.server.requests 指标标签 = 默认全套标签 + app_env=prod。

2.3.2 方式 2:完全替换全部标签

想要完全替换默认标签,可以注册一个实现 ServerRequestObservationConvention 接口的 @Bean。

代码示例:

java 复制代码
@Component
public class FullReplaceServerObservationConvention implements ServerRequestObservationConvention {

    @Override
    public String getName() {
        // 指标名称,优先级低于配置 management.observations.http.server.requests.name
        return "http.server.requests";
    }

    @Override
    public Iterable<KeyValue> getLowCardinalityKeyValues(ServerRequestObservationContext context) {
        // 完全自己构造标签集合,没有父类默认标签!
        return java.util.List.of(
                KeyValue.of("http_method", context.getCarrier().getMethod()),
                KeyValue.of("http_status", String.valueOf(context.getResponse().getStatus())),
                KeyValue.of("biz_app", "demo‑service")
        );
    }

    @Override
    public Iterable<KeyValue> getHighCardinalityKeyValues(ServerRequestObservationContext context) {
        // 高基数标签(一般放traceId,不做metrics聚合)
        return java.util.List.of();
    }
}

2.4 把已捕获异常埋入指标标签

部分场景中,Web 控制器内部已经 try‑catch 捕获并处理掉的异常,不会自动填充到 http.server.requests 的 exception 指标标签上。

应用可以手动开启该行为:把捕获到的异常存入 请求属性(request attribute) ,Observation 过滤器就会读取该属性,把异常写入指标标签。

需要设置请求属性:ServerRequestObservationContext.CURRENT_EXCEPTION_ATTRIBUTE

代码示例:

java 复制代码
@RestController
public class DemoController {

    @GetMapping("/demo")
    public String demo(HttpServletRequest request) {
        try {
            throw new RuntimeException("业务自定义异常");
        } catch (RuntimeException e) {
            // 关键:将捕获处理过的异常放入request属性,observation过滤器读取此属性
            request.setAttribute(ServerRequestObservationContext.CURRENT_EXCEPTION_ATTRIBUTE, e);
            return "业务降级返回";
        }
    }
}

2.5 自定义过滤:跳过部分请求不采集指标

默认采集全部 HTTP 请求。如果需要自定义请求过滤逻辑(跳过某些请求不采集指标),注册一个 FilterRegistrationBean<ServerHttpObservationFilter> 类型的 @Bean。

ServerHttpObservationFilter 是生成 http.server.requests 的核心过滤器。

通过 FilterRegistrationBean 可以设置:过滤匹配模式、排除路径、顺序。

代码示例:

java 复制代码
@Configuration
public class ObservationFilterConfig {

    @Bean
    public FilterRegistrationBean<ServerHttpObservationFilter> observationFilterRegistration(ServerHttpObservationFilter filter) {
        FilterRegistrationBean<ServerHttpObservationFilter> registration = new FilterRegistrationBean<>();
        registration.setFilter(filter);
        // 只匹配 /api/**,其余路径不采集指标;也可以 setUrlPatterns、addUrlPatterns
        registration.addUrlPatterns("/api/*");
        // 设置过滤器顺序
        registration.setOrder(1);
        return registration;
    }
}

⚠️注意:不是实现 FilterRegistrationBean,是构造 FilterRegistrationBean<ServerHttpObservationFilter> 的Bean,设置它的注册参数。不要自己 new 新 Filter 。

上面是白名单;如果要做黑名单(排除某些路径),上面这种 URL pattern 方式能力有限。

更灵活方案:自定义 ServerRequestObservationConvention,或者自定义ObservationPredicate,在 Observation 层面跳过观测。

java 复制代码
@Configuration
public class ObsPredicateConfig {
    @Bean
    public ObservationPredicate observationPredicate() {
        return (name, context) -> {
            // http.server.requests 并且路径以 /actuator 开头,则不生成观测
            if ("http.server.requests".equals(name) && context instanceof org.springframework.http.server.observation.ServerRequestObservationContext ctx) {
                String path = ctx.getCarrier().getRequestURI();
                return !path.startsWith("/actuator");
            }
            return true;
        };
    }
}

ObservationPredicate:全局开关,返回 false 代表不创建该Observation,完全不产生指标 ,比 Filter 粒度更精准。


2. Spring WebFlux 指标

和 Spring MVC 指标基本一致,就不赘述了!!!

自动配置会对所有由 Spring WebFlux 控制器、函数式处理器处理的请求做指标埋点。默认生成指标名称为 http.server.requests。你可以通过配置 management.observations.http.server.requests.name 属性来自定义该指标名称。

想要在默认标签基础上追加自定义标签,可以注册一个 @Bean,继承 org.springframework.http.server.reactive.observation 包下的 DefaultServerRequestObservationConvention。

想要完全替换默认标签,可以注册一个实现 ServerRequestObservationConvention 接口的 @Bean。

部分场景下,控制器与函数式处理器内部捕获处理过的异常,不会作为请求指标的标签被记录。应用可选择开启该能力:将已处理的异常设置为请求属性,即可把异常记录进指标。

相关推荐
EatFan1 小时前
Spring Boot 4 落地观察:从 yudao-cloud、matecloud、JPower 看国产脚手架的升级路线与迁移清单
java·spring boot·后端·spring cloud·微服务·后端开发·jdk 21
Maiko Star2 小时前
* LangChain 提示词模板详解:ChatPromptTemplate 的使用与高级特性
java·人工智能·langchain
现任明教教主~3 小时前
Thinkphp站群蜘蛛池SaaS系统YanyvSEO含多用户/积分/六大引擎计费/易支付对接
java·开发语言·spring
一条破秋裤4 小时前
Linux 线程创建:pthread_create 与基本回收
java·linux·运维
布吉岛的石头4 小时前
Java 程序员第 49 阶段5:BERT 预训练目标 MLM+NSP 的工程含义
java·人工智能·深度学习·bert·transformer
摇滚侠5 小时前
《On Java 中文版 基础卷》阅读笔记 对象无处不在 03
java·笔记·python
二十雨辰5 小时前
[学成在线]-01项目背景
java
弈栈录6 小时前
Java AI 应用的异步化与高并发设计
java·后端·架构
落魄实习生7 小时前
Agent Scope Java 2.x 系列【2】 ReActAgent
java·开发语言
艸肅7 小时前
Ubuntu 安装 JDK (含手动安装)
java·ubuntu·jdk