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
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
@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();
}
}
@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);
}
}
});
@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();
}
}
}
Status
菜单的Targets
下看当期项目的状态是UP
还是DOWN
DOWN
,则说明项目提供的请求url不正确。app_request_total
,在prometheus管理界面的Graph
菜单下输入该指标后点击Execute
,