0、写在前面
1> 使用RestTemplate作为远程调用工具调用prometheus原生api获取数据
2> prometheus原生api文档地址如下:https://prometheus.io/docs/prometheus/latest/querying/api/
3> 通过访问prometheus原生api,查看原生api返回的数据格式,定义对应的实体类格式
4> 下面所列功能代码,仅为部分调用api结果,仅供参考,如若需要调用其他api,可自行编写对应方法
1、远程调用类
1.1、pom依赖
<dependency> <groupId>org.apache.httpcomponents.client5</groupId> <artifactId>httpclient5</artifactId> <version>5.2.1</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.12.0</version> </dependency> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>31.1-jre</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.83</version> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.7.16</version> </dependency>
1.2、RestTemplate工具类
import com.alibaba.fastjson.JSONObject; import com.google.common.base.Joiner; import com.google.common.base.Throwables; import javax.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.hc.client5.http.classic.HttpClient; import org.apache.http.Header; import org.apache.http.client.config.RequestConfig; import org.apache.http.config.Registry; import org.apache.http.config.RegistryBuilder; import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.socket.PlainConnectionSocketFactory; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.impl.client.DefaultHttpRequestRetryHandler; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.ssl.SSLContextBuilder; import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.http.client.SimpleClientHttpRequestFactory; import org.springframework.http.client.support.BasicAuthenticationInterceptor; import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.stereotype.Component; import org.springframework.web.client.DefaultResponseErrorHandler; import org.springframework.web.client.RestTemplate; import org.springframework.web.util.UriComponentsBuilder; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; import java.net.URI; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Set; /** * RestTemplate工具类 * * @author 星空流年 * @date 2023/7/10 */ @Slf4j @Component @SuppressWarnings("all") public class RestTemplateUtils { /** * http 请求 GET * * @param url 地址 * @param params 参数 * @return Http连接 */ public String getHttp(String url, JSONObject params) { return getRestConnection(url, params, "http"); } /** * https 请求 GET * * @param url 地址 * @param params 参数 * @return Https连接 */ public String getHttps(String url, JSONObject params) { return getRestConnection(url, params, "https"); } /** * 获取远程连接 * * @param url 请求地址 * @param params JSON对象 * @param connectionFlag 请求标志 * @return 远程连接 */ private String getRestConnection(String url, JSONObject params, String connectionFlag) { String restConnection = null; if (StringUtils.equals("http", connectionFlag)) { restConnection = getRestHttpConnection(url, params, 10000, 60000, 3); } if (StringUtils.equals("https", connectionFlag)) { restConnection = getRestHttpsConnection(url, params, 10000, 60000, 3); } return restConnection; } /** * http 请求 GET * * @param url 地址 * @param params 参数 * @param connectTimeout 连接时间 * @param readTimeout 读取时间 * @param retryCount 重试机制 * @return 请求字符串 */ public String getRestHttpConnection(String url, JSONObject params, int connectTimeout, int readTimeout, int retryCount) { SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory(); requestFactory.setConnectTimeout(connectTimeout); requestFactory.setReadTimeout(readTimeout); RestTemplate restTemplate = new RestTemplate(requestFactory); // 设置编码集 restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8)); // 异常处理 restTemplate.setErrorHandler(new DefaultResponseErrorHandler()); // 获取URI URI uri = getUriByUrl(url, params); // 重试机制 for (int i = 1; i <= retryCount; i++) { try { // 此处设置值为认证的用户名和密码信息, 请注意修改 restTemplate.getInterceptors().add(new BasicAuthenticationInterceptor("username", "password"); return restTemplate.getForEntity(uri, String.class).getBody(); } catch (Exception e) { log.error("[GET/HTTP请求信息]异常, 重试次数:{}, 请求地址:{}, 请求参数:{}, 异常信息:{}", i, url, params, Throwables.getStackTraceAsString(e)); } } return null; } /** * https 请求 GET * * @param url 地址 * @param params 参数 * @param connectTimeout 连接时间 * @param readTimeout 读取时间 * @param retryCount 重试机制 * @return 请求字符串 */ public String getRestHttpsConnection(String url, JSONObject params, int connectTimeout, int readTimeout, int retryCount) { SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory(); requestFactory.setConnectTimeout(connectTimeout); requestFactory.setReadTimeout(readTimeout); RestTemplate restTemplate = restTemplate(); clientHttpRequestFactory(); // 设置编码集 restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8)); // 异常处理 restTemplate.setErrorHandler(new DefaultResponseErrorHandler()); // 绕过https restTemplate.setRequestFactory(clientHttpRequestFactory()); // 获取URI URI uri = getUriByUrl(url, params); for (int i = 1; i <= retryCount; i++) { try { // 此处设置值为认证的用户名和密码信息, 请注意修改 restTemplate.getInterceptors().add(new BasicAuthenticationInterceptor("username", "password"); return restTemplate.getForEntity(uri, String.class).getBody(); } catch (Exception e) { log.error("[GET/HTTPS请求信息]异常, 重试次数:{}, 请求地址:{}, 请求参数:{}, 异常信息:{}", i, url, params, Throwables.getStackTraceAsString(e)); } } return null; } /** * 获取RestTemplate实例对象,可自由调用其方法 * * @return RestTemplate实例对象 */ public HttpClient httpClient() { HttpClientBuilder httpClientBuilder = HttpClientBuilder.create(); try { //设置信任SSL访问 SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (arg0, arg1) -> true).build(); httpClientBuilder.setSSLContext(sslContext); HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE; SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier); Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create() // 注册http和https请求 .register(RestConnectionConstants.HTTP_CONNECTION_FLAG, PlainConnectionSocketFactory.getSocketFactory()) .register(RestConnectionConstants.HTTPS_CONNECTION_FLAG, sslConnectionSocketFactory).build(); //使用Httpclient连接池的方式配置 PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); // 最大连接数 poolingHttpClientConnectionManager.setMaxTotal(1000); // 同路由并发数 poolingHttpClientConnectionManager.setDefaultMaxPerRoute(100); // 配置连接池 httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager); // 重试次数 httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(1, true)); // 设置默认请求头 List<Header> headers = new ArrayList<>(); httpClientBuilder.setDefaultHeaders(headers); // 设置请求连接超时时间 RequestConfig requestConfig = RequestConfig.custom() .setConnectionRequestTimeout(10000) .setConnectTimeout(10000) .setSocketTimeout(60000).build(); httpClientBuilder.setDefaultRequestConfig(requestConfig); return (HttpClient) httpClientBuilder.build(); } catch (Exception e) { throw new RestException(RestStatus.SYSTEM_ERROR, Throwables.getStackTraceAsString(e)); } } /** * 创建RestTemplate * * @return RestTemplate */ public RestTemplate restTemplate() { return new RestTemplate(clientHttpRequestFactory()); } /** * 创建ClientHttpRequestFactory * * @return ClientHttpRequestFactory */ private ClientHttpRequestFactory clientHttpRequestFactory() { return new HttpComponentsClientHttpRequestFactory(httpClient()); } /** * 通过URL获取URI * * @param url url * @param params 请求参数 * @return {@code URI} */ private URI getUriByUrl(String url, JSONObject params) { String query = "query"; if (!params.isEmpty()) { // 网关针对URL中特殊字符进行加密访问, 这里针对网关未处理特殊字符参数进行转义处理 if (params.containsKey(query)) { String replaceQuery = params.getString(query) .replace("=", "%3D").replace(" ", "%20") .replace("{", "%7B").replace("}", "%7D") .replace("\"", "%22").replace("/", "%2F") .replace("|", "%7C").replace("+", "%2B") .replace("[", "%5B").replace("]", "%5D") .replace("<", "%3C").replace(">", "%3E") .replace("\n", "%20"); params.put(query, replaceQuery); } else { params.keySet().forEach(key -> { String decode = URLDecoder.decode(params.getString(key), StandardCharsets.UTF_8); params.put(key, decode); }); } url = expandUrl(url, params); } UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url); if (params.containsKey(query)) { return builder.build(true).toUri(); } else { return builder.build().encode().toUri(); } } /** * URL拼接 * * @param url 请求URL * @param jsonObject JSON对象 * @return 拼接之后的URL */ private String expandUrl(String url, JSONObject jsonObject) { HashMap<String, Object> paramMap = new HashMap<>(16); StringBuilder stringBuilder = new StringBuilder(url); stringBuilder.append("?"); Set<String> keys = jsonObject.keySet(); keys.forEach(key -> paramMap.put(key, jsonObject.getString(key))); String joinStr = Joiner.on("&").withKeyValueSeparator("=").join(paramMap); return stringBuilder.append(joinStr).toString(); } }
2、即时查询获取数据
2.1、即时查询实体类
Prometheus查询结果实体类:PromQueryResult
import lombok.Data; import java.util.List; import java.util.Map; /** * Prometheus查询结果对象信息 * * @author 星空流年 * @date 2023/7/10 */ @Data public class PromQueryResult { /** * prometheus指标属性 */ private Map<String, Object> metric; /** * prometheus即时查询指标值 */ private List<String> value; }
Prometheus查询数据结果实体类:PromQueryData
import lombok.Data; import java.util.List; /** * Prometheus查询数据结果对象 * * @author 星空流年 * @date 2023/7/10 */ @Data public class PromQueryData { /** * prometheus结果类型 * vector--瞬时向量 * matrix--区间向量 * scalar--标量 * string--字符串 */ private String resultType; /** * prometheus指标属性和值 */ private List<PromQueryResult> result; }
Prometheus查询响应实体类:PromQueryResponse
import lombok.Data; /** * Prometheus查询响应对象 * * @author 星空流年 * @date 2023/7/10 */ @Data public class PromQueryResponse { /** * 状态 * 成功-- success */ private String status; /** * prometheus指标属性和值 */ private PromQueryData data; }
2.2、即时查询接口实现
即时查询接口类:PromQueryService
import xxx.entity.pojo.PromQueryData; /** * 指标查询接口类 * * @author 星空流年 * @date 2023/7/10 */ public interface PromQueryService { /** * Prometheus即时查询 * * @param query 查询 * @param time 时间戳, 单位: 秒 * @return {@code PromQueryData} */ PromQueryData getQueryDataInfo(String query, String time); }
即时查询接口实现类:PromQueryServiceImpl
import cn.hutool.core.date.DateUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.google.common.base.Throwables; import javax.annotation.Resource; import lombok.extern.slf4j.Slf4j; import xxx.entity.pojo.PromQueryData; import xxx.entity.pojo.PromQueryResponse; import xxx.service.PromQueryService; import xxx.util.RestTemplateUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import java.util.Objects; /** * 指标查询接口实现类 * * @author 星空流年 * @date 2023/7/10 */ @Slf4j @Service("promQueryService") public class PromQueryServiceImpl implements PromQueryService { @Resource private RestTemplateUtils restTemplateUtils; @Override public PromQueryData getQueryDataInfo(String query, String time) { if (StringUtils.isBlank(time)) { time = String.valueOf(DateUtil.currentSeconds()); } JSONObject param = new JSONObject(); param.put("query", query); param.put("time", time); // prometheus的URL连接地址, 根据需要修改 String url = "http://localhost:9090" + "/api/v1/query"; return (PromQueryData) getDataInfo(url, param); } /** * 获取查询结果数据 * * @param promUrl 调用的prometheus的URL * @param param 请求参数 * @return 查询结果对象 */ private Object getDataInfo(String promUrl, JSONObject param) { String http = getHttp(promUrl, param); PromQueryResponse responseInfo = JSON.parseObject(http, PromQueryResponse.class); log.info("即时查询请求地址: {}, 请求参数: {}", promUrl, param); if (Objects.isNull(responseInfo)) { return null; } String status = responseInfo.getStatus(); if (StringUtils.isBlank(status) || !StringUtils.equals("success", status)) { return null; } return responseInfo.getData(); } /** * 获取http连接 * * @param promUrl 连接URL * @param param 请求参数 * @return http连接 */ private String getHttp(String promUrl, JSONObject param) { String http = null; try { http = restTemplateUtils.getHttp(promUrl, param); } catch (Exception e) { log.error("请求地址: {}, 请求参数: {}, 异常信息: {}", promUrl, param, Throwables.getStackTraceAsString(e)); } return http; } }
3、范围查询获取数据
3.1、范围查询实体类
范围查询实体类:PromQueryRange
import lombok.Data; /** * Prometheus范围查询实体类 * * @author 星空流年 * @date 2023/7/10 */ @Data public class PromQueryRange { /** * 查询指标 */ private String query; /** * 区间范围查询开始时间 * 格式为:时分秒时间戳 */ private String start; /** * 区间范围查询结束时间 * 格式为:时分秒时间戳 */ private String end; /** * 时间区间步长, 即:时间间隔 */ private Integer step; }
Prometheus范围区间查询结果实体类:PromQueryRangeResult
import lombok.Data; import java.util.List; import java.util.Map; /** * Prometheus范围区间查询结果对象信息 * * @author 星空流年 * @date 2023/7/10 */ @Data public class PromQueryRangeResult { /** * prometheus指标属性 */ private Map<String, Object> metric; /** * prometheus范围查询指标值 */ private List<List<String>> values; }
Prometheus范围区间查询数据结果对象实体类:PromQueryRangeData
import lombok.Data; import java.util.List; /** * Prometheus范围区间查询数据结果对象 * * @author 星空流年 * @date 2023/7/10 */ @Data public class PromQueryRangeData { /** * prometheus结果类型 * vector--瞬时向量 * matrix--区间向量 * scalar--标量 * string--字符串 */ private String resultType; /** * prometheus指标属性和值 */ private List<PromQueryRangeResult> result; }
Prometheus范围区间查询响应对象实体类:PromQueryRangeResponse
import lombok.Data; /** * Prometheus范围区间查询响应对象 * * @author 星空流年 * @date 2023/7/10 */ @Data public class PromQueryRangeResponse { /** * 状态 * 成功-- success */ private String status; /** * prometheus范围查询指标属性和值 */ private PromQueryRangeData data; }
3.2、范围查询接口实现
范围查询接口类:PromQueryService
import xxx.entity.pojo.PromQueryRangeData; import xxx.entity.pojo.PromQueryRange; /** * 指标查询接口类 * * @author 星空流年 * @date 2023/7/10 */ public interface PromQueryService { /** * Prometheus范围区间查询 * * @param queryRangeDto 查询范围类 * @return {@code PromQueryRangeData} */ PromQueryRangeData getQueryRangeDataInfo(PromQueryRange queryRange); }
范围查询接口实现类:PromQueryServiceImpl
import cn.hutool.core.date.DateUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.google.common.base.Throwables; import javax.annotation.Resource; import lombok.extern.slf4j.Slf4j; import xxx.entity.pojo.PromQueryRange; import xxx.entity.pojo.PromQueryRangeData; import xxx.entity.pojo.PromQueryRangeResponse; import xxx.service.PromQueryService; import xxx.util.RestTemplateUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import java.util.Objects; /** * 指标查询接口实现类 * * @author 星空流年 * @date 2023/7/10 */ @Slf4j @Service("promQueryService") public class PromQueryServiceImpl implements PromQueryService { @Resource private RestTemplateUtils restTemplateUtils; @Override public PromQueryRangeData getQueryRangeDataInfo(PromQueryRange queryRange) { JSONObject param = new JSONObject(); handleQueryRangeParams(param, queryRange); // prometheus的URL连接地址, 根据需要修改 String url = "http://localhost:9090" + "/api/v1/query_range"; return (PromQueryRangeData) getDataInfo(url, param); } /** * 处理范围查询参数 * * @param param 参数 * @param queryRange PromQueryRange对象 */ private void handleQueryRangeParams(JSONObject param, PromQueryRange queryRange) { String start = queryRange.getStart(); if (StringUtils.isBlank(start)) { // 开始时间为空, 则设置默认值为当前时间 start = String.valueOf(DateUtil.currentSeconds()); } String end = queryRange.getEnd(); if (StringUtils.isBlank(end)) { // 结束时间为空, 则设置默认值为当前时间向后偏移1小时 end = String.valueOf(DateUtil.offsetHour(DateUtil.parse(start), 1).getTime()); } param.put("query", queryRange.getQuery()); param.put("start", start); param.put("end", end); param.put("step", queryRange.getStep()); } /** * 获取查询结果数据 * * @param promUrl 调用的prometheus的URL * @param param 请求参数 * @return 查询结果对象 */ private Object getDataInfo(String promUrl, JSONObject param) { String http = getHttp(promUrl, param); PromQueryRangeResponse rangeResponse = JSON.parseObject(http, PromQueryRangeResponse.class); log.info("范围区间查询请求地址: {}, 请求参数: {}", promUrl, param); if (Objects.isNull(rangeResponse)) { return null; } String status = rangeResponse.getStatus(); if (StringUtils.isBlank(status) || !StringUtils.equals("success", status)) { return null; } return rangeResponse.getData(); } /** * 获取http连接 * * @param promUrl 连接URL * @param param 请求参数 * @return http连接 */ private String getHttp(String promUrl, JSONObject param) { String http = null; try { http = restTemplateUtils.getHttp(promUrl, param); } catch (Exception e) { log.error("请求地址: {}, 请求参数: {}, 异常信息: {}", promUrl, param, Throwables.getStackTraceAsString(e)); } return http; } }
4、根据标签匹配器获取时序数据
4.1、时序数据实体类
import lombok.Data; import java.util.LinkedHashMap; import java.util.List; /** * Prometheus时序对象 * * @author 星空流年 * @date 2023/7/10 */ @Data public class PromSeries { /** * 状态 * 成功-- success */ private String status; /** * 时序数据列表 */ private List<LinkedHashMap<String, Object>> data; }
4.2、时序数据接口实现
根据标签匹配器获取时序数据接口类:PromQueryService
/** * 指标查询接口类 * * @author 星空流年 * @date 2023/7/10 */ public interface PromQueryService { /** * 获取时序数据 * * @param start 开始时间戳, 单位:秒 * @param end 结束时间戳, 单位:秒 * @param match 查询指标 * @return {@code List<LinkedHashMap<String, Object>>} */ List<LinkedHashMap<String, Object>> getSeriesList(String start, String end, String match); }
根据标签匹配器获取时序数据接口实现类:PromQueryServiceImpl
import cn.hutool.core.date.DateUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.google.common.base.Throwables; import javax.annotation.Resource; import lombok.extern.slf4j.Slf4j; import xxx.entity.pojo.PromQueryData; import xxx.entity.pojo.PromQueryResponse; import xxx.service.PromQueryService; import xxx.util.RestTemplateUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import java.util.Objects; /** * 指标查询接口实现类 * * @author 星空流年 * @date 2023/7/10 */ @Slf4j @Service("promQueryService") public class PromQueryServiceImpl implements PromQueryService { @Resource private RestTemplateUtils restTemplateUtils; @Override public List<LinkedHashMap<String, Object>> getSeriesList(String start, String end, String match, Integer datasource) { JSONObject param = new JSONObject(); param.put("start", start); param.put("end", end); param.put("match[]", match); // prometheus的URL连接地址, 根据需要修改 String url = "http://localhost:9090" + "/api/v1/series"; return getSeriesDataList(url, param); } /** * 获取时序数据列表 * * @param promUrl 时序URL * @param param 请求参数 * @return 时序数据列表 */ private List<LinkedHashMap<String, Object>> getSeriesDataList(String promUrl, JSONObject param) { String http = getHttp(promUrl, param); PromSeries promSeries = JSON.parseObject(http, PromSeries.class); if (Objects.nonNull(promSeries)) { String status = promSeries.getStatus(); if (StringUtils.isBlank(status) || !StringUtils.equals(PromConstants.SUCCESS, status)) { return Collections.emptyList(); } } else { return Collections.emptyList(); } return promSeries.getData(); } /** * 获取http连接 * * @param promUrl 连接URL * @param param 请求参数 * @return http连接 */ private String getHttp(String promUrl, JSONObject param) { String http = null; try { http = restTemplateUtils.getHttp(promUrl, param); } catch (Exception e) { log.error("请求地址: {}, 请求参数: {}, 异常信息: {}", promUrl, param, Throwables.getStackTraceAsString(e)); } return http; } }标签:http,Springboot,param,查询,return,Prometheus,Api,import,String From: https://www.cnblogs.com/cndarren/p/17545721.html