前言
前一段时间使用SpringBoot创建了一个webhook项目,由于近期项目中也使用了不少SpringBoot相关的项目,趁着周末,配置一下使用prometheus监控微服务Springboot。
项目配置
引入坐标
<!-- Exposition spring_boot -->
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient_spring_boot</artifactId>
<version>0.1.0</version>
</dependency>
<!-- Hotspot JVM metrics -->
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient_hotspot</artifactId>
<version>0.1.0</version>
</dependency>
<!-- Exposition servlet -->
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient_servlet</artifactId>
<version>0.1.0</version>
</dependency>
配置Application
@SpringBootApplication
@EnablePrometheusEndpoint
@EnableSpringBootMetricsCollector
public class Application {
private static final Logger logger = LoggerFactory.getLogger(Application.class);
public static void main(String[] args) throws InterruptedException {
SpringApplication.run(Application.class, args);
logger.info("项目启动 ");
}
}
配置MonitoringConfig
@Configuration
class MonitoringConfig {
@Bean
SpringBootMetricsCollector springBootMetricsCollector(Collection<PublicMetrics> publicMetrics) {
SpringBootMetricsCollector springBootMetricsCollector = new SpringBootMetricsCollector(publicMetrics);
springBootMetricsCollector.register();
return springBootMetricsCollector;
}
@Bean
ServletRegistrationBean servletRegistrationBean() {
DefaultExports.initialize();
return new ServletRegistrationBean(new MetricsServlet(), "/prometheus");
}
}
配置Interceptor
RequestCounterInterceptor(计数):
public class RequestCounterInterceptor extends HandlerInterceptorAdapter {
// @formatter:off
// Note (1)
private static final Counter requestTotal = Counter.build()
.name("http_requests_total")
.labelNames("method", "handler", "status")
.help("Http Request Total").register();
// @formatter:on
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e)
throws Exception {
// Update counters
String handlerLabel = handler.toString();
// get short form of handler method name
if (handler instanceof HandlerMethod) {
Method method = ((HandlerMethod) handler).getMethod();
handlerLabel = method.getDeclaringClass().getSimpleName() + "." + method.getName();
}
// Note (2)
requestTotal.labels(request.getMethod(), handlerLabel, Integer.toString(response.getStatus())).inc();
}
}
RequestTimingInterceptor(统计请求时间):
package com.itstyle.webhook.interceptor;
import java.lang.reflect.Method;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import io.prometheus.client.Summary;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
public class RequestTimingInterceptor extends HandlerInterceptorAdapter {
private static final String REQ_PARAM_TIMING = "timing";
// @formatter:off
// Note (1)
private static final Summary responseTimeInMs = Summary
.build()
.name("http_response_time_milliseconds")
.labelNames("method", "handler", "status")
.help("Request completed time in milliseconds")
.register();
// @formatter:on
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// Note (2)
request.setAttribute(REQ_PARAM_TIMING, System.currentTimeMillis());
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception {
Long timingAttr = (Long) request.getAttribute(REQ_PARAM_TIMING);
long completedTime = System.currentTimeMillis() - timingAttr;
String handlerLabel = handler.toString();
// get short form of handler method name
if (handler instanceof HandlerMethod) {
Method method = ((HandlerMethod) handler).getMethod();
handlerLabel = method.getDeclaringClass().getSimpleName() + "." + method.getName();
}
// Note (3)
responseTimeInMs.labels(request.getMethod(), handlerLabel,
Integer.toString(response.getStatus())).observe(completedTime);
}
}
配置Controller
主要是为了测试拦截器的效果
@RestController
public class HomeController {
private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
@RequestMapping("/endpointA")
public void handlerA() throws InterruptedException {
logger.info("/endpointA");
Thread.sleep(RandomUtils.nextLong(0, 100));
}
@RequestMapping("/endpointB")
public void handlerB() throws InterruptedException {
logger.info("/endpointB");
Thread.sleep(RandomUtils.nextLong(0, 100));
}
}
以上都配置完成后启动项目即可。
配置Prometheus
vi prometheus.yml
- job_name: webhook
metrics_path: '/prometheus'
static_configs:
- targets: ['localhost:8080']
labels:
instance: webhook
保存后重新启动Prometheus即可。
访问http://ip/targets 服务State 为up说明配置成功,查阅很多教程都说需要配置 spring.metrics.servo.enabled=false,否则在prometheus的控制台的targets页签里,会一直显示此endpoint为down状态,然貌似并没有配置也是ok的。
访问http://ip/graph 测试一下效果
配置Grafana
如图所示:
参考链接
https://blog.52itstyle.vip/archives/1984/
https://blog.52itstyle.vip/archives/2084/
https://raymondhlee.wordpress.com/2016/09/24/monitoring-spring-boot-applications-with-prometheus/