近期因需要分析、评估某项目本周、上周等时段的接口质量(99分位耗时、超时率、错误率、接口返回状态占比率等指标),经调研发现-项目各接口信息监控已被接入grafana,在确认了grafana上各看板信息有以上性能指标后,程序实现定时从grafana看板中抓取接口指标信息。
如下图所示(接口返回状态占比率):
前提:需要使用浏览器F12开发者模式或filddler等工具获取查询条件,如下图:
获取的查询条件信息赋值给下面代码 String queryConditionGateway = 查询条件
以下为具体的代码实现,供参考(敏感信息已模糊处理):
1、主类
package statistical;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.zhilian.statistics.utils.HttpGetPost;
import com.zhilian.statistics.utils.MyHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.ParseException;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
/**
* @Author: jiajun
* @Date: 2022/3/3 22:23
*/
public class StatisticsSolrPositionRecommend {
private static Logger logger = LoggerFactory.getLogger(StatisticsSolrPositionRecommend.class);
HttpGetPost httpGetPost = new HttpGetPost();//
String index = "https://grafana.xxxx.com/api/datasources/proxy/1/api/v1/query_range?query=";//grafana查询前缀
public StatisticsSolrPositionRecommend() throws ParseException { }
/**
* 获取json串中所有状态值的当前值
* @param jsonArray
* @return
*/
public float currentValue(JSONArray jsonArray){
float currentValue = 0f;//当前值
float param = 0f;//临时变量,存放状态值
//float maxValue = 0f;
if (jsonArray != null && jsonArray.size() >= 1) {
for (int m = 0; m < jsonArray.size(); m++) {
param = Float.parseFloat(jsonArray.getJSONArray(m).get(1).toString());//获取状态名称的值
if (param > currentValue) {//过滤 0 NaN等无效数据
currentValue = param;//累计值
}
}
}
return currentValue;//获取状态名称的当前值
}
/**
* @param query 查询条件
* @param startTime 开始时间
* @param endTime 结束时间
* @return 返回一个hashMap,包含:状态类型,平均值
* @throws Exception
*/
public MyHashMap<String, Float> gatewayDataSource(String query,String startTime,String endTime) throws Exception {
String queryCondition = index + query + "&start=" + startTime + "&end=" + endTime + "&step=1";//
JSONObject jsonObject = null;
String SatusName = null;//状态名称
MyHashMap<String, Float> hmGatewayAvg = new MyHashMap<>();//存放状态名称,当前状态值
MyHashMap<String, Float> hmGatewaySatus = new MyHashMap<>();//存放状态名称,占比率
JSONArray jsonArray = null;
jsonObject = (JSONObject) httpGetPost.doGet(queryCondition, "");//根据查询条件进行http请求
try {
jsonArray = jsonObject.getJSONObject("data").getJSONArray("result");//获取返回结果json
} catch (Exception e) {
logger.error("搜索推荐C推荐性能指标获取失败!");
}
//float avgValue = 0f;//存放状态名称的平均值
float currentValue = 0f;//存放状态名称的当前值
float sumValue = 0f;//存放所有状态名称值的和
for (int m = 0; m < jsonArray.size(); m++) {//
JSONArray jsonArrayValues = jsonArray.getJSONObject(m).getJSONArray("values");
SatusName = jsonArray.getJSONObject(m).getJSONObject("metric").getString("status");//获取状态名称
//avgValue = avgVlue(jsonArrayValues);//获取状态名称的平均值
currentValue = currentValue(jsonArrayValues);//获取状态名称的当前值
hmGatewayAvg.put(SatusName, String.valueOf(currentValue));//把单个状态名称,单个状态当前值放入hashmap中
sumValue+= currentValue;//累加所有状态值的和
}
float finalSumValue = sumValue;
hmGatewayAvg.forEach((key, v) -> {
float Percent = (Float.parseFloat(v)/finalSumValue);//用每个状态的值除以所有状态累加值,获得状态占比率
hmGatewaySatus.put(key,String.valueOf(Percent));//把单个状态名称,单个状态Percent值放入hashmap中
});
return hmGatewaySatus;
}
public static void main(String[] args) throws Exception {
StatisticsSolrPositionRecommend statisticsSolr = new StatisticsSolrPositionRecommend();
long current = System.currentTimeMillis();//当前时间毫秒数
//查询开始时间:当天9点,结束时间:当天10点
/*long nine = current / (1000 * 3600 * 24) * (1000 * 3600 * 24) - TimeZone.getDefault().getRawOffset() + 9 * 60 * 60 * 1000;//今天9点零分零秒的毫秒数
long ten = nine + 1 * 60 * 60 * 1000 ;//今天10点的毫秒数
String startTime = Long.toString((nine / 1000));
String endTime = Long.toString((ten / 1000));*/
String startTime = Long.toString((current / 1000));//当前时间
String endTime = Long.toString((current / 1000 ));//当前时间
//gateway 接口状态占比率
//String queryConditionGateway = "sum(rate(aggregator_request_seconds_count{phase=\"total\",environment=~\"(docker-a|docker-b)\", app_name=~\"java-s-xxxx-gateway\",method=~\"position\\\\.xxxx\\\\.xxxx\",scenario=~\"c\",path=~\"/position-recommend/xxxx/xxxx\"\"}[1m] ) >0) by(status)";
String queryConditionGateway = "sum(rate(aggregator_request_seconds_count{phase=\"total\",environment=~\"(docker-a|docker-b)\", app_name=~\"java-s-xxxx-gateway\",method=~\"position\\\\.xxxx\\\\.xxxx\",scenario=~\"c\",path=~\"/position-recommend/xxxx/xxxx\"}[1m] ) >0) by(status)";
String query = java.net.URLEncoder.encode(queryConditionGateway, "UTF-8");
MyHashMap<String, Float> hmGatewayAvg = statisticsSolr.gatewayDataSource(query,startTime,endTime);
//测试:打印hashmap信息
hmGatewayAvg.forEach((key, v) -> {
logger.info("状态名称{}------占比率{}%",key.toString(),Float.parseFloat(v)*100);
});
}
}
工具类1 HttpGetPost :
package com.zhilian.statistics.utils;
import com.alibaba.fastjson.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.text.ParseException;
/**
* @Author: jiajun.du
* @Date: 2021/11/23 15:53
*/
public class HttpGetPost {
static Logger logger = LoggerFactory.getLogger(HttpGetPost.class);
/**
* get请求
* @return
* @throws Exception
*/
public static PoolingHttpClientConnectionManager setHttpThread(){
PoolingHttpClientConnectionManager cManager = new PoolingHttpClientConnectionManager();
cManager.setMaxTotal(50);//设置最大连接数
cManager.setDefaultMaxPerRoute(20);//设置每个主机地址的并发数
return cManager;
}
public static JSONObject doGet(String url, String param) throws Exception{
CloseableHttpClient httpClient = null;
CloseableHttpResponse httpResponse =null;
String strResult = "";
try {
//httpClient = HttpClients.createDefault();//创建一个httpClient实例
httpClient = HttpClients.custom().setConnectionManager(setHttpThread()).build();
org.apache.http.client.methods.HttpGet httpGet =new org.apache.http.client.methods.HttpGet(url+param);//创建httpGet远程连接实例
// 设置请求头信息
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(60000).//连接主机服务器时间
setConnectionRequestTimeout(60000).//请求超时时间
setSocketTimeout(60000).//数据读取超时时间
build();
httpGet.setConfig(requestConfig);//为httpGet实例设置配置信息
httpResponse = httpClient.execute(httpGet);//通过get请求得到返回对象
//发送请求成功并得到响应
if(httpResponse.getStatusLine().getStatusCode()==200){
strResult = EntityUtils.toString(httpResponse.getEntity());
JSONObject resultJsonObject = JSONObject.parseObject(strResult);//获取请求返回结果
return resultJsonObject;
}else{
logger.error("请求{}失败,\n状态码为{}",url,httpResponse.getStatusLine().getStatusCode());
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException i){
i.printStackTrace();
logger.error("IOException异常:{}",i.getMessage());
} finally {
if(httpResponse!=null){
try {
httpResponse.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(httpClient!=null){
try {
httpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
/**
* 发送post请求
* @param url 路径
* @param jsonObject 参数(json类型)
* @param encoding 编码格式
* @return
* @throws ParseException
* @throws IOException
*/
public static JSONObject doPost(String url, JSONObject jsonObject,String encoding) throws ParseException, IOException{
JSONObject object = null;
String body = "";
//创建httpclient对象
CloseableHttpClient client = HttpClients.custom().setConnectionManager(setHttpThread()).build();
//创建post方式请求对象
HttpPost httpPost = new HttpPost(url);
StringEntity s = new StringEntity(jsonObject.toString(), "utf-8"); //装填参数
//s.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
//设置参数到请求对象中
httpPost.setEntity(s);
System.out.println("请求地址:"+url);
//设置header信息
//指定报文头【Content-type】、【User-Agent】
httpPost.setHeader("Content-Type", "application/json");
httpPost.setHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
httpPost.setHeader("Connection","keep-alive");
//执行请求操作,并拿到结果(同步阻塞)
CloseableHttpResponse response = client.execute(httpPost);
//获取结果实体
HttpEntity entity = response.getEntity();
if (entity != null) {
//按指定编码转换结果实体为String类型
body = EntityUtils.toString(entity, encoding);
object = JSONObject.parseObject(body);
}
EntityUtils.consume(entity);
//释放链接
response.close();
return object;
}
}
工具类2 重写HashMap
package com.zhilian.statistics.utils;
import java.util.*;
/**
* 重写hashMap,实现遇到相同key时,value值自动累加功能
* @param <K>
*/
public class MyHashMap<K, F extends Float> extends HashMap<K,String> {
//传递一个新的 key、value值
@Override
public String put(K key, String value) {
// 定义一个新的value,接收后面put的新的value值
String NewVaule = value;
//containsKey 判断这个 key 是否已经存在?
if (containsKey(key)) {
// 获得旧的value 值
String oldValue = get(key);
//NewVaule = String.valueOf(Float.parseFloat(oldValue)+ Float.parseFloat(NewVaule));//将旧值 和 后面put 的新值拼接起来
NewVaule = (Float.parseFloat(oldValue) > Float.parseFloat(NewVaule)) ? oldValue : NewVaule;//将旧值 和 后面put 的新值比较,取最大值
}
// 返回newvalue
return super.put(key, NewVaule);
}
/*自定义get() 模糊匹配
*/
public List<Float> likeGet(String key) {
List<Float> list = null;
list = new ArrayList<Float>();
K[] a = null;
Set<K> set = this.keySet();
Iterator<K> it = set.iterator();
K elem = null;
while (it.hasNext()) {
elem = it.next();
if (elem.toString().contains(key)) {
list.add(Float.valueOf(this.get(elem)));
}
}
return list;
}
}
打印获取信息:
16:10:40.721 [main] INFO statistical.StatisticsSolrPositionRecommend - 状态名称filterEmptyResultError------占比率0.3211751%
16:10:40.723 [main] INFO statistical.StatisticsSolrPositionRecommend - 状态名称quExeptionError------占比率0.8130153%
16:10:40.723 [main] INFO statistical.StatisticsSolrPositionRecommend - 状态名称solrExceptionError------占比率0.010039162%
16:10:40.723 [main] INFO statistical.StatisticsSolrPositionRecommend - 状态名称solrEmptyResultError------占比率1.2546575%
16:10:40.724 [main] INFO statistical.StatisticsSolrPositionRecommend - 状态名称solrTimeoutError------占比率0.0100376%
16:10:40.724 [main] INFO statistical.StatisticsSolrPositionRecommend - 状态名称success------占比率96.466934%
16:10:40.724 [main] INFO statistical.StatisticsSolrPositionRecommend - 状态名称quInterruptError------占比率1.1241422%