Springmvc整合prometheus+grafana

写在前面

springmvc老项目了…真蛋疼
我们的项目使用的是springmvc4.x,时间序列数据库使用的是prometheus,仪表板使用的是grafana。
网上prometheus for spring boot的资料一大把,grafana dashboard for spring boot的资料也有很多模板可以套用。可怜springmvc没人在乎…想使用现有的micrometer-registry-prometheus去暴露服务指标,并直接在grafana的模板仪表盘中直接套用springboot的模式,不得不看一下micrometer-registry-prometheus的源码才行。
因此,本教程会先讲解下部分源码,再将prometheus for springmvc的配置告诉大家。

本案例环境

micrometer-registry-prometheus:1.1.0
jdk 1.8
springmvc 4.x
tomcat 8.x

核心包功能解读

官方源码github:https://github.com/micrometer-metrics/micrometer
进入micrometer-core进行查看,这个重点讲几个核心的类

  1. 注册器MeterRegistry
    MeterRegistry是所有注册表的基类(抽象类),所有的注册器都应该继承自它
public abstract class MeterRegistry {
    protected final Clock clock;
    private final Object meterMapLock = new Object();
    private volatile MeterFilter[] filters = new MeterFilter[0];
    private final List<Consumer<Meter>> meterAddedListeners = new CopyOnWriteArrayList<>();
    private final List<Consumer<Meter>> meterRemovedListeners = new CopyOnWriteArrayList<>();
    private final Config config = new Config();
    private final More more = new More();
    //...
}

比如prometheus的注册类为

package io.micrometer.prometheus;
public class PrometheusMeterRegistry extends MeterRegistry {
    private final CollectorRegistry registry;
    private final ConcurrentMap<String, MicrometerCollector> collectorMap;
    private final PrometheusConfig prometheusConfig;
    //...
}
  1. 绑定容器内部测量的接口MeterBinder
public interface MeterBinder {
    void bindTo(@NonNull MeterRegistry registry);
}

MeterBinder可以将内部测量数据绑定到registry上,比如jvm的gc指标JvmGcMetrics

public class JvmGcMetrics implements MeterBinder {
    public void bindTo(MeterRegistry registry) {
        AtomicLong maxDataSize = new AtomicLong(0L);
        Gauge.builder("jvm.gc.max.data.size", maxDataSize, AtomicLong::get).tags(this.tags).description("Max size of old generation memory pool").baseUnit("bytes").register(registry);
        // ...
    }
}
  1. 将监控指标MeterBinder绑定到注册器registry
public void initRegistry() {
    PrometheusMeterRegistry registry = new PrometheusMeterRegistry();

    JvmGcMetrics jvmGcMetrics = new JvmGcMetrics();
    jvmGcMetrics.bindTo(registry);
}

  1. 类继承关系图
    Springmvc整合prometheus+grafana_第1张图片

  2. MeterRegistry常见的实现类
    Springmvc整合prometheus+grafana_第2张图片

  3. 输出指标数据

String response = MeterRegistry.scrape();

将response返回到前端,展示如下
Springmvc整合prometheus+grafana_第3张图片

Springmvc集成prometheus,并使用默认提供的指标

Springmvc整合prometheus+grafana_第4张图片

这样高大上的仪表盘模板,在springboot下很容器实现,无论是官方教程还是各大论坛都有介绍。

但是,关于springmvc的介绍缺少的可怜,你甚至在grafana的仪表盘模板找不到相关介绍。因此的,这个章节将告诉大家,springmvc如何将数据指标暴露出去。

上面介绍过了MeterRegisry的原理,那么接下来的代码请大家细读一下

pom.xml管理依赖

<dependency>
    <groupId>io.micrometergroupId>
    <artifactId>micrometer-registry-prometheusartifactId>
    <version>1.1.0version>
dependency>

web.xml配置指标暴露servlet


<servlet>
    <servlet-name>prometheusservlet-name>
    <servlet-class>com.epoch.wan37.servlet.PrometheusMetricsServletservlet-class>
servlet>
<servlet-mapping>
    <servlet-name>prometheusservlet-name>
    <url-pattern>/prometheusurl-pattern>
servlet-mapping>

配置servlet

package com.epoch.wan37.servlet;

import com.netflix.hystrix.HystrixMetrics;
import io.micrometer.core.instrument.Clock;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MockClock;
import io.micrometer.core.instrument.binder.MeterBinder;
import io.micrometer.core.instrument.binder.cache.*;
import io.micrometer.core.instrument.binder.db.DatabaseTableMetrics;
import io.micrometer.core.instrument.binder.db.PostgreSQLDatabaseMetrics;
import io.micrometer.core.instrument.binder.jetty.JettyServerThreadPoolMetrics;
import io.micrometer.core.instrument.binder.jetty.JettyStatisticsMetrics;
import io.micrometer.core.instrument.binder.jpa.HibernateMetrics;
import io.micrometer.core.instrument.binder.jvm.*;
import io.micrometer.core.instrument.binder.kafka.KafkaConsumerMetrics;
import io.micrometer.core.instrument.binder.logging.Log4j2Metrics;
import io.micrometer.core.instrument.binder.logging.LogbackMetrics;
import io.micrometer.core.instrument.binder.system.FileDescriptorMetrics;
import io.micrometer.core.instrument.binder.system.ProcessorMetrics;
import io.micrometer.core.instrument.binder.system.UptimeMetrics;
import io.micrometer.core.instrument.binder.tomcat.TomcatMetrics;
import io.micrometer.prometheus.PrometheusConfig;
import io.micrometer.prometheus.PrometheusMeterRegistry;
import io.micrometer.prometheus.PrometheusRenameFilter;
import io.prometheus.client.CollectorRegistry;
import io.prometheus.client.exporter.common.TextFormat;
import org.apache.catalina.Manager;
import org.apache.catalina.session.StandardManager;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

/**
 * @desc 描述
 * @auther winnie
 * @date 2021/8/20
 */
@Configuration
public class PrometheusMetricsServlet extends HttpServlet {
    @Value("${spring.application.name}")
    private String appName;

    private PrometheusMeterRegistry registry;
    private Set<MeterBinder> meterBinderSet = new HashSet<>();
    /**
     * 初始化指标注册器
     */
    @PostConstruct
    public void initRegistry() {
        PrometheusConfig prometheusConfig = PrometheusConfig.DEFAULT;
        CollectorRegistry defaultRegistry = CollectorRegistry.defaultRegistry;
        Clock clock = new MockClock();
        registry = new PrometheusMeterRegistry(prometheusConfig,defaultRegistry,clock);
        // 配置app名称
        registry.config().commonTags("application",appName);

        // 初始化监控指标
        initMetrics();

        // 指标绑定注册器
        meterBinderSet.forEach(meterBinder -> meterBinder.bindTo(registry));
    }

    /**
     * 初始化指标,按照项目需要进行配置,以下配置都是io.prometheus默认提供
     */
    private void initMetrics() {
        // jvm指标
        JvmGcMetrics jvmGcMetrics = new JvmGcMetrics();
        meterBinderSet.add(jvmGcMetrics);
        JvmThreadMetrics jvmThreadMetrics = new JvmThreadMetrics();
        meterBinderSet.add(jvmThreadMetrics);
        JvmMemoryMetrics jvmMemoryMetrics = new JvmMemoryMetrics();
        meterBinderSet.add(jvmMemoryMetrics);
        ClassLoaderMetrics classLoaderMetrics = new ClassLoaderMetrics();
        meterBinderSet.add(classLoaderMetrics);
//        DiskSpaceMetrics diskSpaceMetrics = new DiskSpaceMetrics();
//        ExecutorServiceMetrics executorServiceMetrics = new ExecutorServiceMetrics();
        // 缓存指标
//        CacheMeterBinder cacheMeterBinder = new CacheMeterBinder();
//        CaffeineCacheMetrics caffeineCacheMetrics = new CaffeineCacheMetrics();
//        GuavaCacheMetrics guavaCacheMetrics = new GuavaCacheMetrics();
//        HazelcastCacheMetrics hazelcastCacheMetrics = new HazelcastCacheMetrics();
//        JCacheMetrics jCacheMetrics = new JCacheMetrics();
        // DB指标
//        DatabaseTableMetrics databaseTableMetrics = new DatabaseTableMetrics();
//        PostgreSQLDatabaseMetrics postgreSQLDatabaseMetrics = new PostgreSQLDatabaseMetrics();
        // 系统指标
        FileDescriptorMetrics fileDescriptorMetrics = new FileDescriptorMetrics();
        meterBinderSet.add(fileDescriptorMetrics);
        ProcessorMetrics processorMetrics = new ProcessorMetrics();
        meterBinderSet.add(processorMetrics);
        UptimeMetrics uptimeMetrics = new UptimeMetrics();
        meterBinderSet.add(uptimeMetrics);
        // logging指标
        Log4j2Metrics log4j2Metrics = new Log4j2Metrics();
        meterBinderSet.add(log4j2Metrics);
//        LogbackMetrics logbackMetrics = new LogbackMetrics();
        // jetty指标
//        JettyServerThreadPoolMetrics jettyServerThreadPoolMetrics = new JettyServerThreadPoolMetrics();
//        JettyStatisticsMetrics jettyStatisticsMetrics = new JettyStatisticsMetrics();
        // tomcat指标
        Manager standardManager = new StandardManager();
        TomcatMetrics tomcatMetrics = new TomcatMetrics(standardManager, Collections.EMPTY_LIST);
        meterBinderSet.add(tomcatMetrics);
        // kafka指标
//        KafkaConsumerMetrics kafkaConsumerMetrics = new KafkaConsumerMetrics();
        // jpa指标
//        HibernateMetrics hibernateMetrics = new HibernateMetrics();
        // hystrix指标
//        HystrixMetrics hystrixMetrics = new HystrixMetrics();
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        PrintWriter writer = resp.getWriter();
        try {
            String response = registry.scrape();
            writer.write(response);
            writer.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            writer.close();
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}

其中,${spring.application.name}:为你的应用名称

启动tomcat容器并测试

${TOMCAT_HOME}/bin/startup.sh

在浏览器访问

http://${yourHostname}:${port}/${ContextPath}/prometheus

若出现以下信息表示我们的服务指标已经暴露出去
Springmvc整合prometheus+grafana_第5张图片

接下来的操作很简单,就是我们暴露的指标api给prometheus监听
prometheus.yml

scrape_configs:
  - job_name: fssc
  metrics_path: '/fssc/prometheus'
  static_configs:
    - targets: ['10.16.16.202:8081']

job_name:prometheus任务名称
ip、端口替换成你们自个的服务,prometheus会定时去访问10.16.16.202:8081/fssc/prometheus获取指标数据,进行持久化,并通过grafana将数据呈现给大家。

重启prometheus。

配置grafana仪表盘

官方推荐:https://grafana.com/grafana/dashboards/4701

  1. 下载json文件
    Springmvc整合prometheus+grafana_第6张图片

  2. 导入到grafana中,并上传json文件
    Springmvc整合prometheus+grafana_第7张图片

恭喜你,你已经完成了(部分)Springmvc整合prometheus的过程
Springmvc整合prometheus+grafana_第8张图片

写在最后

本案例你会看到部分指标数据没有对接上,后续有时间会尽可能补充。

你可能感兴趣的:(prometheus)