前言
前一段時間使用SpringBoot建立了一個webhook項目,因爲近期項目中也使用了很多SpringBoot相關的項目,趁着週末,配置一下使用prometheus監控微服務Springboot。html
項目配置
引入座標
<!-- 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@EnableSpringBootMetricsCollectorpublic 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
@Configurationclass 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(計數):java
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(統計請求時間):web
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
主要是爲了測試攔截器的效果spring
@RestControllerpublic 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)); } }
以上都配置完成後啓動項目便可。app
配置Prometheus
vi prometheus.ymldom
- job_name: webhook metrics_path: '/prometheus' static_configs: - targets: ['localhost:8080'] labels: instance: webhook
保存後從新啓動Prometheus便可。ide
訪問http://ip/targets 服務State 爲up說明配置成功,查閱不少教程都說須要配置 spring.metrics.servo.enabled=false,不然在prometheus的控制檯的targets頁籤裏,會一直顯示此endpoint爲down狀態,然貌似並無配置也是ok的。wordpress
訪問http://ip/graph 測試一下效果spring-boot
配置Grafana
如圖所示:微服務
參考連接
https://blog.52itstyle.com/archives/1984/
https://blog.52itstyle.com/archives/2084/
https://raymondhlee.wordpress.com/2016/09/24/monitoring-spring-boot-applications-with-prometheus/