import{_ as e,V as o,W as c,X as n,Y as s,Z as t,a1 as l,a0 as p,F as i}from"./framework-23f3cf9b.js";const u="/tutorial/imgs/211109/00.jpg",r={},k=n("p",null,"之前介绍了一篇SpringBoot集成Prometheus实现数据上报的博文，在前面一篇博文中，更多的是一个SpringBoot应用如何最小成本的接入Prometheus，并结合Grafana配置一个完整的应用监控大盘",-1),d=n("p",null,"有看过前文的小伙伴可能知晓，SpringBoot接入Prometheus之后，基本上不用做额外的开发，就已经实现了我们关心的JVM情况、GC情况、HTTP调用请求等信息，然而在实际的业务开发过程中，我们总会遇到一些需要手动上报的场景，那么我们可以怎么处理呢？",-1),m=n("p",null,"本文的核心知识点：",-1),v=n("ul",null,[n("li",null,"通过一个实例演示SpringBoot应用，如何实现自定义的数据上报")],-1),g={href:"https://spring.hhui.top/spring-blog/2021/04/19/210419-SpringBoot%E6%95%B4%E5%90%88Prometheus%E5%AE%9E%E7%8E%B0%E5%BA%94%E7%94%A8%E7%9B%91%E6%8E%A7/",target:"_blank",rel:"noopener noreferrer"},b=p(`<h2 id="i-项目环境搭建" tabindex="-1"><a class="header-anchor" href="#i-项目环境搭建" aria-hidden="true">#</a> I. 项目环境搭建</h2><p>本文演示的项目主要为SpringBoot2.2.1版本，更高的版本使用姿势没有太大的区别，至于1.x版本的不确保可行（因为我并没有测试）</p><h3 id="_1-依赖" tabindex="-1"><a class="header-anchor" href="#_1-依赖" aria-hidden="true">#</a> 1.依赖</h3><p>pom依赖，主要是下面几个包</p><div class="language-xml line-numbers-mode" data-ext="xml"><pre class="language-xml"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependencies</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.springframework.boot<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>spring-boot-starter-actuator<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>

    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.springframework.boot<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>spring-boot-starter-web<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>

    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>io.micrometer<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>micrometer-registry-prometheus<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependencies</span><span class="token punctuation">&gt;</span></span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="_2-配置信息" tabindex="-1"><a class="header-anchor" href="#_2-配置信息" aria-hidden="true">#</a> 2. 配置信息</h3><p>其次是配置文件，注册下Prometheus的相关信息</p><div class="language-yaml line-numbers-mode" data-ext="yml"><pre class="language-yaml"><code><span class="token key atrule">spring</span><span class="token punctuation">:</span>
  <span class="token key atrule">application</span><span class="token punctuation">:</span>
    <span class="token key atrule">name</span><span class="token punctuation">:</span> prometheus<span class="token punctuation">-</span>example
<span class="token key atrule">management</span><span class="token punctuation">:</span>
  <span class="token key atrule">endpoints</span><span class="token punctuation">:</span>
    <span class="token key atrule">web</span><span class="token punctuation">:</span>
      <span class="token key atrule">exposure</span><span class="token punctuation">:</span>
        <span class="token key atrule">include</span><span class="token punctuation">:</span> <span class="token string">&quot;*&quot;</span>
  <span class="token key atrule">metrics</span><span class="token punctuation">:</span>
    <span class="token key atrule">tags</span><span class="token punctuation">:</span>
      <span class="token key atrule">application</span><span class="token punctuation">:</span> $<span class="token punctuation">{</span>spring.application.name<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>上面配置中，有两个关键信息，前面博文也有介绍，这里简单说明</p><ul><li><code>management.endpoints.web.exposure.include</code> 这里指定所有的web接口都会上报</li><li><code>metrics.tags.application</code> 这个应用所有上报的metrics 都会带上application这个标签</li></ul><p>配置完毕之后，会提供一个 <code>/actuator/prometheus</code>的端点，供prometheus来拉取Metrics信息</p><h2 id="ii-自定义上报" tabindex="-1"><a class="header-anchor" href="#ii-自定义上报" aria-hidden="true">#</a> II. 自定义上报</h2><p>假设我们现在想自己上报http请求的相关信息，当前计划采集下面几个信息</p><ul><li>总的请求数：采用<code>Counter</code></li><li>当前正在处理的请求数：采用<code>Gauge</code></li><li>请求耗时直方图: <code>Histogram</code></li></ul><h3 id="_1-prometheus-metric封装" tabindex="-1"><a class="header-anchor" href="#_1-prometheus-metric封装" aria-hidden="true">#</a> 1. Prometheus Metric封装</h3><p>基于上面的分析，我们这里实现了三种常见的Metric信息上报，这里提供一个统一的封装类，用于获取对应的Metric类型</p><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>git<span class="token punctuation">.</span>hui<span class="token punctuation">.</span>boot<span class="token punctuation">.</span>prometheus<span class="token punctuation">.</span>interceptor</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token import"><span class="token namespace">io<span class="token punctuation">.</span>prometheus<span class="token punctuation">.</span>client<span class="token punctuation">.</span></span><span class="token class-name">CollectorRegistry</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">io<span class="token punctuation">.</span>prometheus<span class="token punctuation">.</span>client<span class="token punctuation">.</span></span><span class="token class-name">Counter</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">io<span class="token punctuation">.</span>prometheus<span class="token punctuation">.</span>client<span class="token punctuation">.</span></span><span class="token class-name">Gauge</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">io<span class="token punctuation">.</span>prometheus<span class="token punctuation">.</span>client<span class="token punctuation">.</span></span><span class="token class-name">Histogram</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>beans<span class="token punctuation">.</span></span><span class="token class-name">BeansException</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>context<span class="token punctuation">.</span></span><span class="token class-name">ApplicationContext</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>context<span class="token punctuation">.</span></span><span class="token class-name">ApplicationContextAware</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>stereotype<span class="token punctuation">.</span></span><span class="token class-name">Component</span></span><span class="token punctuation">;</span>

<span class="token doc-comment comment">/**
 * <span class="token keyword">@author</span> yihui
 * <span class="token keyword">@date</span> 2021/11/09
 */</span>
<span class="token annotation punctuation">@Component</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">PrometheusComponent</span> <span class="token keyword">implements</span> <span class="token class-name">ApplicationContextAware</span> <span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token class-name">PrometheusComponent</span> instance<span class="token punctuation">;</span>


    <span class="token doc-comment comment">/**
     * 请求总数
     */</span>
    <span class="token keyword">private</span> <span class="token class-name">Counter</span> reqCounter<span class="token punctuation">;</span>

    <span class="token doc-comment comment">/**
     * 正在请求的http数量
     */</span>
    <span class="token keyword">private</span> <span class="token class-name">Gauge</span> duringReqGauge<span class="token punctuation">;</span>

    <span class="token doc-comment comment">/**
     * 直方图，请求分布情况
     */</span>
    <span class="token keyword">private</span> <span class="token class-name">Histogram</span> reqLatencyHistogram<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setApplicationContext</span><span class="token punctuation">(</span><span class="token class-name">ApplicationContext</span> applicationContext<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">BeansException</span> <span class="token punctuation">{</span>
        instance <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">;</span>
        <span class="token class-name">CollectorRegistry</span> collectorRegistry <span class="token operator">=</span> applicationContext<span class="token punctuation">.</span><span class="token function">getBean</span><span class="token punctuation">(</span><span class="token class-name">CollectorRegistry</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 这里指定SpringBoot容器的CollectorRegistry，如果使用默认的会导致无法收集</span>
        reqCounter <span class="token operator">=</span> <span class="token class-name">Counter</span><span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string">&quot;demo_rest_req_total&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">labelNames</span><span class="token punctuation">(</span><span class="token string">&quot;path&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;method&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;code&quot;</span><span class="token punctuation">)</span>
                <span class="token punctuation">.</span><span class="token function">help</span><span class="token punctuation">(</span><span class="token string">&quot;总的请求计数&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">register</span><span class="token punctuation">(</span>collectorRegistry<span class="token punctuation">)</span><span class="token punctuation">;</span>
        duringReqGauge <span class="token operator">=</span> <span class="token class-name">Gauge</span><span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
                <span class="token punctuation">.</span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string">&quot;demo_rest_inprogress_req&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">labelNames</span><span class="token punctuation">(</span><span class="token string">&quot;path&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;method&quot;</span><span class="token punctuation">)</span>
                <span class="token punctuation">.</span><span class="token function">help</span><span class="token punctuation">(</span><span class="token string">&quot;正在处理的请求数&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">register</span><span class="token punctuation">(</span>collectorRegistry<span class="token punctuation">)</span><span class="token punctuation">;</span>
        reqLatencyHistogram <span class="token operator">=</span> <span class="token class-name">Histogram</span><span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">labelNames</span><span class="token punctuation">(</span><span class="token string">&quot;path&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;method&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;code&quot;</span><span class="token punctuation">)</span>
                <span class="token punctuation">.</span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string">&quot;demo_rest_requests_latency_seconds_histogram&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">help</span><span class="token punctuation">(</span><span class="token string">&quot;请求耗时分布&quot;</span><span class="token punctuation">)</span>
                <span class="token punctuation">.</span><span class="token function">register</span><span class="token punctuation">(</span>collectorRegistry<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">PrometheusComponent</span> <span class="token function">getInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> instance<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token class-name">Counter</span> <span class="token function">counter</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> reqCounter<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token class-name">Gauge</span> <span class="token function">gauge</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> duringReqGauge<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token class-name">Histogram</span> <span class="token function">histogram</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> reqLatencyHistogram<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>注意上面的<code>setApplicationContext()</code>的方法实现逻辑，其中在创建<code>Counter/Gauge/Histogram</code>时，使用的是<code>simpleclient</code>包中提供的最基础的用法，并不是<code>micrometer</code>的封装方式，后面一篇博文会介绍到两种的差异性</p><p>上面实现的特点在于，创建Metric时，就已经定义好了label标签，这里定义了</p><ul><li>path: 请求url路径</li><li>method: http方法, get/post</li><li>code: 状态码，表示请求成功还是异常</li></ul><h3 id="_2-拦截器实现自定义信息采集上报" tabindex="-1"><a class="header-anchor" href="#_2-拦截器实现自定义信息采集上报" aria-hidden="true">#</a> 2. 拦截器实现自定义信息采集上报</h3><p>接下来我们实现一个自定义的拦截器，拦截所有的http请求，然后上报关键信息</p><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">PrometheusInterceptor</span> <span class="token keyword">extends</span> <span class="token class-name">HandlerInterceptorAdapter</span> <span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token class-name">ThreadLocal</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Histogram<span class="token punctuation">.</span>Timer</span><span class="token punctuation">&gt;</span></span> timerThreadLocal <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ThreadLocal</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">preHandle</span><span class="token punctuation">(</span><span class="token class-name">HttpServletRequest</span> request<span class="token punctuation">,</span> <span class="token class-name">HttpServletResponse</span> response<span class="token punctuation">,</span> <span class="token class-name">Object</span> handler<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Exception</span> <span class="token punctuation">{</span>
        <span class="token comment">// 正在处理的请求量</span>
        <span class="token class-name">PrometheusComponent</span><span class="token punctuation">.</span><span class="token function">getInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">gauge</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">labels</span><span class="token punctuation">(</span>request<span class="token punctuation">.</span><span class="token function">getRequestURI</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> request<span class="token punctuation">.</span><span class="token function">getMethod</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">inc</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        timerThreadLocal<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token class-name">PrometheusComponent</span><span class="token punctuation">.</span><span class="token function">getInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">histogram</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
                <span class="token punctuation">.</span><span class="token function">labels</span><span class="token punctuation">(</span>request<span class="token punctuation">.</span><span class="token function">getRequestURI</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> request<span class="token punctuation">.</span><span class="token function">getMethod</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token class-name">String</span><span class="token punctuation">.</span><span class="token function">valueOf</span><span class="token punctuation">(</span>response<span class="token punctuation">.</span><span class="token function">getStatus</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
                <span class="token punctuation">.</span><span class="token function">startTimer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">preHandle</span><span class="token punctuation">(</span>request<span class="token punctuation">,</span> response<span class="token punctuation">,</span> handler<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">afterCompletion</span><span class="token punctuation">(</span><span class="token class-name">HttpServletRequest</span> request<span class="token punctuation">,</span> <span class="token class-name">HttpServletResponse</span> response<span class="token punctuation">,</span> <span class="token class-name">Object</span> handler<span class="token punctuation">,</span> <span class="token class-name">Exception</span> ex<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Exception</span> <span class="token punctuation">{</span>
        <span class="token class-name">String</span> uri <span class="token operator">=</span> request<span class="token punctuation">.</span><span class="token function">getRequestURI</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">String</span> method <span class="token operator">=</span> request<span class="token punctuation">.</span><span class="token function">getMethod</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">int</span> status <span class="token operator">=</span> response<span class="token punctuation">.</span><span class="token function">getStatus</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// count 请求计数，标签分别为 请求路径，请求方法，response http code</span>
        <span class="token comment">// 请求应用总量:  sum(demo_rest_req_total)</span>
        <span class="token comment">// 每秒http请求量: sum(rate(demo_rest_req_total[1m])</span>
        <span class="token comment">// 请求topk的url:  topk(10, sum(demo_rest_req_total) by (path))</span>
        <span class="token class-name">PrometheusComponent</span><span class="token punctuation">.</span><span class="token function">getInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">counter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">labels</span><span class="token punctuation">(</span>uri<span class="token punctuation">,</span> method<span class="token punctuation">,</span> <span class="token class-name">String</span><span class="token punctuation">.</span><span class="token function">valueOf</span><span class="token punctuation">(</span>status<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">inc</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// 请求完毕，计数器-1</span>
        <span class="token class-name">PrometheusComponent</span><span class="token punctuation">.</span><span class="token function">getInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">gauge</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">labels</span><span class="token punctuation">(</span>uri<span class="token punctuation">,</span> method<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">dec</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// 直方图统计</span>
        <span class="token class-name">Histogram<span class="token punctuation">.</span>Timer</span> timer <span class="token operator">=</span> timerThreadLocal<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>timer <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            timer<span class="token punctuation">.</span><span class="token function">observeDuration</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            timerThreadLocal<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">afterCompletion</span><span class="token punctuation">(</span>request<span class="token punctuation">,</span> response<span class="token punctuation">,</span> handler<span class="token punctuation">,</span> ex<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div>`,23),h={href:"https://spring.hhui.top/spring-blog/2021/08/04/210804-SpringBoot%E7%B3%BB%E5%88%97Web%E7%AF%87%E4%B9%8B%E6%8B%A6%E6%88%AA%E5%99%A8Interceptor%E4%BD%BF%E7%94%A8%E5%A7%BF%E5%8A%BF%E4%BB%8B%E7%BB%8D/",target:"_blank",rel:"noopener noreferrer"},f=p(`<p>这里我们主要关心的就两点</p><ul><li>执行之前（<code>preHandle</code>）： gauge计数+1，开始计时</li><li>执行之后 (<code>afterCompletion</code>)： guage计数-1，counter计数+1，计时收集</li></ul><h3 id="_3-测试" tabindex="-1"><a class="header-anchor" href="#_3-测试" aria-hidden="true">#</a> 3. 测试</h3><p>最后我们需要注册上面的拦截器，并写个demo进行测试一下</p><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token annotation punctuation">@RestController</span>
<span class="token annotation punctuation">@SpringBootApplication</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Application</span> <span class="token keyword">implements</span> <span class="token class-name">WebMvcConfigurer</span> <span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token class-name">Random</span> random <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Random</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">addInterceptors</span><span class="token punctuation">(</span><span class="token class-name">InterceptorRegistry</span> registry<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        registry<span class="token punctuation">.</span><span class="token function">addInterceptor</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">PrometheusInterceptor</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">addPathPatterns</span><span class="token punctuation">(</span><span class="token string">&quot;/**&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token annotation punctuation">@GetMapping</span><span class="token punctuation">(</span>path <span class="token operator">=</span> <span class="token string">&quot;hello&quot;</span><span class="token punctuation">)</span>
    <span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">hello</span><span class="token punctuation">(</span><span class="token class-name">String</span> name<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">int</span> sleep <span class="token operator">=</span> random<span class="token punctuation">.</span><span class="token function">nextInt</span><span class="token punctuation">(</span><span class="token number">200</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">try</span> <span class="token punctuation">{</span>
            <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span>sleep<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">InterruptedException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">return</span> <span class="token string">&quot;hello sleep: &quot;</span> <span class="token operator">+</span> sleep <span class="token operator">+</span> <span class="token string">&quot; for &quot;</span> <span class="token operator">+</span> name<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">SpringApplication</span><span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token class-name">Application</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token annotation punctuation">@Bean</span>
    <span class="token class-name">MeterRegistryCustomizer</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">MeterRegistry</span><span class="token punctuation">&gt;</span></span> <span class="token function">configurer</span><span class="token punctuation">(</span><span class="token annotation punctuation">@Value</span><span class="token punctuation">(</span><span class="token string">&quot;\${spring.application.name}&quot;</span><span class="token punctuation">)</span> <span class="token class-name">String</span> applicationName<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token punctuation">(</span>registry<span class="token punctuation">)</span> <span class="token operator">-&gt;</span> registry<span class="token punctuation">.</span><span class="token function">config</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">commonTags</span><span class="token punctuation">(</span><span class="token string">&quot;application&quot;</span><span class="token punctuation">,</span> applicationName<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>应用启动之后，访问几次hello的http接口，然后在查看一下metric信息，看是否有我们刚才上报的数据</p><figure><img src="`+u+'" alt="" tabindex="0" loading="lazy"><figcaption></figcaption></figure><h3 id="_4-小结" tabindex="-1"><a class="header-anchor" href="#_4-小结" aria-hidden="true">#</a> 4. 小结</h3><p>这一篇博文算是上一篇的补全，若我们希望自定义上报一些信息，可以使用上面这种方式来支持</p><p>当然，上报并不代表结束，接下来配置大盘等信息也非常的关键，特别是直方图如何配置Grafana？怎么查看请求的耗时分布情况，就由下文来介绍了</p><h2 id="iii-不能错过的源码和相关知识点" tabindex="-1"><a class="header-anchor" href="#iii-不能错过的源码和相关知识点" aria-hidden="true">#</a> III. 不能错过的源码和相关知识点</h2><h3 id="_0-项目" tabindex="-1"><a class="header-anchor" href="#_0-项目" aria-hidden="true">#</a> 0. 项目</h3>',12),y={href:"https://github.com/liuyueyi/spring-boot-demo",target:"_blank",rel:"noopener noreferrer"},_={href:"https://github.com/liuyueyi/spring-boot-demo/tree/master/spring-boot/",target:"_blank",rel:"noopener noreferrer"},w=n("h3",{id:"_1-微信公众号-一灰灰blog",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#_1-微信公众号-一灰灰blog","aria-hidden":"true"},"#"),s(" 1. 微信公众号: 一灰灰Blog")],-1),q=n("p",null,"尽信书则不如，以上内容，纯属一家之言，因个人能力有限，难免有疏漏和错误之处，如发现bug或者有更好的建议，欢迎批评指正，不吝感激",-1),x=n("p",null,"下面一灰灰的个人博客，记录所有学习和工作中的博文，欢迎大家前去逛逛",-1),B={href:"https://blog.hhui.top",target:"_blank",rel:"noopener noreferrer"},C={href:"http://spring.hhui.top",target:"_blank",rel:"noopener noreferrer"},I=n("figure",null,[n("img",{src:"https://spring.hhui.top/spring-blog/imgs/info/info.png",alt:"一灰灰blog",tabindex:"0",loading:"lazy"}),n("figcaption",null,"一灰灰blog")],-1);function E(S,R){const a=i("ExternalLinkIcon");return o(),c("div",null,[k,d,m,v,n("p",null,[s("上篇博文: "),n("a",g,[s("SpringBoot整合Prometheus实现应用监控"),t(a)])]),l(" more "),b,n("p",null,[s("对于拦截器的知识点这里不进行展开，有兴趣的小伙伴可以查看 "),n("a",h,[s("SpringBoot系列Web篇之拦截器Interceptor使用姿势介绍"),t(a)])]),f,n("ul",null,[n("li",null,[s("工程："),n("a",y,[s("https://github.com/liuyueyi/spring-boot-demo"),t(a)])]),n("li",null,[s("源码："),n("a",_,[s("https://github.com/liuyueyi/spring-boot-demo/tree/master/spring-boot/"),t(a)])])]),w,q,x,n("ul",null,[n("li",null,[s("一灰灰Blog个人博客 "),n("a",B,[s("https://blog.hhui.top"),t(a)])]),n("li",null,[s("一灰灰Blog-Spring专题博客 "),n("a",C,[s("http://spring.hhui.top"),t(a)])])]),I])}const P=e(r,[["render",E],["__file","211109-SpringBoot之Prometheus自定义埋点上报.html.vue"]]);export{P as default};
