springboot2项目集成prometheus说明

springboot2项目集成prometheus说明

1、pom文件引入相关依赖


  org.springframework.boot
  spring-boot-starter-actuator


    io.prometheus
    simpleclient
    0.6.0


    io.prometheus
    simpleclient_common
    0.6.0


    io.prometheus
    simpleclient_hotspot
    0.6.0

2、application.properties添加暴露采集点信息

management.metrics.distribution.percentiles-histogram.http=true
management.endpoints.web.base-path=/actuator
management.endpoints.web.exposure.include=prometheus,metrics
management.metrics.export.prometheus.enabled=true
management.metrics.export.prometheus.descriptions=true
management.metrics.export.prometheus.step=1m
management.metrics.web.server.auto-time-requests=true

3、创建Configuration类来注入需要metrics对象

    @Configuration
    public class PrometheusBeanConfig {
        /**
         * http请求总数量Counter
         * @return Counter对象
         */
        @Bean
        public io.prometheus.client.Counter appHttpRequestTotalCountCollector(){
            return io.prometheus.client.Counter.build()
                    .name("app_request_total")
                    .labelNames("appId","businessType","method","returnCode")
                    .help("init app_request_total").create()
                    .register();
        }
        @Bean
        public io.prometheus.client.Histogram requestsLatencySeconds(){
            return io.prometheus.client.Histogram.build()
                    .name("requests_latency_seconds")
                    .labelNames("appId","businessType","method")
                    .help("init requests_latency_seconds")
                    .create()
                    .register();
        }
    
        /**
         * 密码资产接口指标
         * @return Gauge对象
         */
        @Bean
        public io.prometheus.client.Gauge cipherAssetsInventoryGaugeCollector(){
            return io.prometheus.client.Gauge.build()
                    .name("cipher_assets_inventory")
                    .labelNames("type")
                    .help("init cipher_assets_inventory")
                    .create()
                    .register();
        }
    
    }

4、创建拦截器或者aop进行metric埋点,根据具体需要自行选择埋点方式(埋点部分)

   @Autowired
   private Gauge gauge;

   @Autowired
   private Counter counter;

   @Autowired
   private Histogram histogram;

   private Histogram.Timer histogramRequestTimer;
   @Before("execution(public * com.infosec.cssp.nettsa.controller.NetTsaController.*(..))")
   public void doBefore(JoinPoint joinPoint) {
       Object args[] = joinPoint.getArgs();
       JSONObject requestJson = (JSONObject) args[1];
       HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
       String appId = request.getHeader("appId");
       String method = requestJson.getJSONObject(FieldNameConstant.FIELD_MSG_HEADER).getString(FieldNameConstant.FIELD_BUSINESS_TYPE);
       // http响应时间埋点
       histogramRequestTimer = histogram.labels(appId, BUSSINESS_TYPE, method).startTimer();

   }
   @AfterReturning(pointcut = "execution(public * com.infosec.cssp.nettsa.controller.NetTsaController.*(..))",returning = "result")
   public void doAfterReturning(JoinPoint joinPoint, Object result){
       Object args[] = joinPoint.getArgs();
       String requestParam = args[1].toString();
       JSONObject requestJson = JSONObject.parseObject(requestParam);
       JSONObject responseJson = (JSONObject) JSON.toJSON(result);
       HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
       String appId = request.getHeader("appId");
       rmp.setAppId(appId);
       //TODO appName需要从接口中取
       rmp.setAppName(AppType.getName(appId));
       String returnCode = responseJson.getJSONObject(Constants.HEAD).getString(Constants.CODE);
       String method = requestJson.getJSONObject(FieldNameConstant.FIELD_MSG_HEADER)
               .getString(FieldNameConstant.FIELD_BUSINESS_TYPE);
       String success = "0";
       String error = "-1";
       if (success.contentEquals(returnCode) && method != null && CommonConstant.GENERATE_TIME_STAMP.equals(method)) {
           gauge.labels(BUSSINESS_TYPE).inc();
       }

       // http请求量counter埋点
       counter.labels(appId, BUSSINESS_TYPE, method, success.equals(returnCode) ? returnCode : error).inc();
       histogramRequestTimer.observeDuration();
   }

注:这种方法经过压测时发现会导致得到的平均响应时间出现问题,因为并发导致,所以改为Around方式,且需要调用Histogram的time方法(解决多线程问题),比如

 //写histogram类型指标信息
 String finalMethodName = methodName;
 Object result = histogram.labels(appId, CommonConstant.BUSINESS_TYPE, methodName).time(new Callable<Object>() {
     @Override
     public Object call() {
         try {
             //注意,如果调用joinPoint.proceed()方法,则修改的参数值不会生效,必须调用joinPoint.proceed(Object[] args),
             // 此时才真的去调业务方法,调用顺序为:around->before->method->after
             return joinPoint.proceed(args);
         } catch (Throwable throwable) {
             logger.error("调用方法{}出错,{}", finalMethodName, throwable);
             return new ResultDto(errorCode, "调用方法" + finalMethodName + "出错:" + throwable.getMessage(), null);
         }
     }
 });

5、自定义采集请求url,供prometheus服务调用(采集部分)

@RestController
@CrossOrigin
@RequestMapping("monitor")
public class MonitorController {
     @RequestMapping(value = "/prometheus",produces = {"application/json;charset=UTF-8"})
    public void exportMetrics(HttpServletResponse response) {
        StringWriter writer = new StringWriter();
        try {
            TextFormat.write004(writer, CollectorRegistry.defaultRegistry.metricFamilySamples());
        } catch (IOException var3) {
            throw new RuntimeException(var3);
        }
        String response2 = writer.toString();
        try (OutputStream os = response.getOutputStream()) {
            os.write(response2.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

6、验证是否埋点成功

  • 启动项目
  • 确定prometheus服务成功连接到项目
    可以到prometheus管理界面的Status菜单的Targets下看当期项目的状态是UP还是DOWN
    如果是DOWN,则说明项目提供的请求url不正确。
  • 访问项目某个接口
  • 到prometheus提供的操作界面中访问埋点数据
    比如埋点指标为:app_request_total,在prometheus管理界面的Graph菜单下输入该指标后点击Execute,
    查看返回数据.(注意:不同指标,prometheus会生成不同指标名称)

你可能感兴趣的:(菜鸟每天进步一点点)