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进行查看,这个重点讲几个核心的类
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;
//...
}
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);
// ...
}
}
public void initRegistry() {
PrometheusMeterRegistry registry = new PrometheusMeterRegistry();
JvmGcMetrics jvmGcMetrics = new JvmGcMetrics();
jvmGcMetrics.bindTo(registry);
}
String response = MeterRegistry.scrape();
这样高大上的仪表盘模板,在springboot下很容器实现,无论是官方教程还是各大论坛都有介绍。
但是,关于springmvc的介绍缺少的可怜,你甚至在grafana的仪表盘模板找不到相关介绍。因此的,这个章节将告诉大家,springmvc如何将数据指标暴露出去。
上面介绍过了MeterRegisry的原理,那么接下来的代码请大家细读一下
<dependency>
<groupId>io.micrometergroupId>
<artifactId>micrometer-registry-prometheusartifactId>
<version>1.1.0version>
dependency>
<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>
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_HOME}/bin/startup.sh
在浏览器访问
http://${yourHostname}:${port}/${ContextPath}/prometheus
接下来的操作很简单,就是我们暴露的指标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。
官方推荐:https://grafana.com/grafana/dashboards/4701
恭喜你,你已经完成了(部分)Springmvc整合prometheus的过程
本案例你会看到部分指标数据没有对接上,后续有时间会尽可能补充。