Java获取Prometheus监控服务列表

Java获取Prometheus监控服务列表

一. 准备工作

1. 有可以被Prometheus监控的服务

没有的话可以参考以下链接本地搭建:SpringBoot应用接入Prometheus+Grafana

2. 选择我们调用远程服务的方式

可以选择RestTemplate 作为远程调用工具,RestTemplate 内部默认用的是 jdk 自带的
HttpURLConnection 发送请求的,性能上面并不是太突出。可以将其替换为 httpclient 或者 okhttp。

二. 实战

1. 引入依赖

   <dependency>
            <groupId>org.apache.httpcomponentsgroupId>
            <artifactId>httpclientartifactId>
   dependency>

2. 编写http请求工具

package com.alibaba.bizworks.om.finops.domain.util;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.Header;
import org.apache.http.client.HttpClient;
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.converter.StringHttpMessageConverter;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;

/**
 * RestTemplate 远程调用工具类
 * @author gf
 * @date 2022/10/24
 */
@Slf4j
public class RestTemplateUtils {

    /**
     * 读取时间,自定义默认8s,0表示没有超时时间
     */
    public static final int READ_TIMEOUT = 1000*8;

    /**
     * 连接时间,自定义默认8s,0表示没有超时时间
     */
    public static final int CONNEC_TIMEOUT = 1000*8;

    /**
     * 重试次数,自定义默认1
     */
    public static final int RETRY_COUNT = 1;


    /**
     * http 请求 GET
     *
     * @param url           地址
     * @param params        参数
     * @return String 类型
     */
    public static String getHttp(String url, JSONObject params) {
        String result = getHttp(url, params, READ_TIMEOUT, CONNEC_TIMEOUT, RETRY_COUNT);
        return result;
    }
    /**
     * http 请求 GET
     *
     * @param url           地址
     * @param params        参数
     * @param connecTimeout 连接时间
     * @param readTimeout   读取时间
     * @param retryCount    重试机制
     * @return String 类型
     */
    public static String getHttp(String url, JSONObject params, int connecTimeout, int readTimeout, int retryCount) {
        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
        requestFactory.setConnectTimeout(connecTimeout);
        requestFactory.setReadTimeout(readTimeout);
        RestTemplate restTemplate = new RestTemplate(requestFactory);
        restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8)); // 设置编码集
        restTemplate.setErrorHandler(new DefaultResponseErrorHandler()); // 异常处理
        url = expandURL(url, params);
        String result = null; // 返回值类型;
        for (int i = 1; i <= retryCount; i++) {
            try {
                log.info("【GET/HTTP请求信息】,请求地址:{},请求参数:{}", url, params);
                result = restTemplate.getForObject(url, String.class, params);
                log.info("【GET/HTTP请求信息】,请求地址:{},请求参数:{},返回结果:{}", url, params,result);
                return result;
            } catch (Exception e) {
                log.error("【GET/HTTP请求信息】异常,重试count:{},请求地址:{},请求参数:{},异常信息:{}", i, url, params,e);
                e.printStackTrace();
            }
        }
        return result;
    }

    /**
     * https 请求 GET
     *
     * @param url           地址
     * @param params        参数
     * @return String 类型
     */
    public static String getHttps(String url, JSONObject params) {
        String result = getHttps(url, params, READ_TIMEOUT, CONNEC_TIMEOUT, RETRY_COUNT);
        return result;
    }

    /**
     * https 请求 GET
     *
     * @param url           地址
     * @param params        参数
     * @param connecTimeout 连接时间
     * @param readTimeout   读取时间
     * @param retryCount    重试机制
     * @return String 类型
     */
    public static String getHttps(String url, JSONObject params, int connecTimeout, int readTimeout, int retryCount) {
        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
        requestFactory.setConnectTimeout(connecTimeout);
        requestFactory.setReadTimeout(readTimeout);
        RestTemplate restTemplate = restTemplate();
        RestTemplateUtils.clientHttpRequestFactory();
        restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8)); // 设置编码集
        restTemplate.setErrorHandler(new DefaultResponseErrorHandler()); //error处理
        restTemplate.setRequestFactory(clientHttpRequestFactory()); // 绕过https
        url = expandURL(url, params);
        String result = null; // 返回值类型;
        for (int i = 1; i <= retryCount; i++) {

            try {
                log.info("【GET/HTTPS请求信息】,请求地址:{},请求参数:{}", url, params);
                result = restTemplate.getForObject(url, String.class, params);
                log.info("【GET/HTTPS请求信息】,请求地址:{},请求参数:{},返回结果:{}", url, params,result);
                return result;
            } catch (Exception e) {
                log.error("【GET/HTTPS请求信息】异常,重试count:{},请求地址:{},请求参数:{},异常信息:{}", i, url, params,e);
                e.printStackTrace();
            }
        }
        return result;
    }
    /**
     * @Title: URL拼接
     * @MethodName:  expandURL
     * @param url
     * @param jsonObject
     * @Return java.lang.String
     * @Exception
     * @Description:
     */
    private static String expandURL(String url,JSONObject jsonObject) {

        StringBuilder sb = new StringBuilder(url);
        sb.append("?");
        Set<String> keys = jsonObject.keySet();
        for (String key : keys) {
            sb.append(key).append("=").append(jsonObject.getString(key)).append("&");
        }
        return sb.deleteCharAt(sb.length() - 1).toString();
    }

    /**
     * 获取RestTemplate实例对象,可自由调用其方法
     * @return RestTemplate实例对象
     */
    public static 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("http", PlainConnectionSocketFactory.getSocketFactory())
                    .register("https", sslConnectionSocketFactory).build();

            //使用Httpclient连接池的方式配置(推荐),同时支持netty,okHttp以及其他http框架
            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);
            return httpClientBuilder.build();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static ClientHttpRequestFactory clientHttpRequestFactory() {
        HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient());
        // 连接超时(毫秒),这里设置10秒
        clientHttpRequestFactory.setConnectTimeout(10 * 1000);
        // 数据读取超时时间(毫秒),这里设置60秒
        clientHttpRequestFactory.setReadTimeout(60 * 1000);
        // 从连接池获取请求连接的超时时间(毫秒),不宜过长,必须设置,比如连接不够用时,时间过长将是灾难性的
        clientHttpRequestFactory.setConnectionRequestTimeout(10 * 1000);
        return clientHttpRequestFactory;
    }

    public static RestTemplate restTemplate(){
        //创建RestTemplate的时候,指定ClientHttpRequestFactory
        return new RestTemplate(clientHttpRequestFactory());
    }


}

3. 编写响应体

从浏览器中找到peomrtheus它获取服务列表的请求地址

Java获取Prometheus监控服务列表_第1张图片

然后根据这个地址在postman发get请求拿到它的响应体结构
Java获取Prometheus监控服务列表_第2张图片

{
    "status": "success",
    "data": {
        "activeTargets": [
            {
                "discoveredLabels": {
                    "__address__": "localhost:9091",
                    "__metrics_path__": "/actuator/prometheus",
                    "__scheme__": "http",
                    "__scrape_interval__": "15s",
                    "__scrape_timeout__": "10s",
                    "job": "prometheus"
                },
                "labels": {
                    "instance": "localhost:9091",
                    "job": "prometheus"
                },
                "scrapePool": "prometheus",
                "scrapeUrl": "http://localhost:9091/actuator/prometheus",
                "globalUrl": "http://ISS490002001977:9091/actuator/prometheus",
                "lastError": "",
                "lastScrape": "2022-10-24T13:30:13.8493399+08:00",
                "lastScrapeDuration": 0.0385651,
                "health": "up",
                "scrapeInterval": "15s",
                "scrapeTimeout": "10s"
            }
        ],
        "droppedTargets": []
    }
}

接下来我们就可以根据这个结果来封装相应体了

@Data
public class PromResponceInfo {
    /**
     * 状态
     * 成功-- success
     */
    private String status;

    /**
     * prometheus指标属性和值
     */
    private PromDataInfo data;


}

@Data
public class PromDataInfo {

    /**
     * prometheus监控服务指表参数
     */
    private List droppedTargets;
    private List<PromResultInfo> activeTargets;

}

@Data
public class PromResultInfo {


    /**
     * prometheus指标属性
     */
    private PromMetricInfo labels;

    /**
     * prometheus指标值
     */

    private String globalUrl;

    private String health;

    private String lastScrape;

    private String lastScrapeDuration;

    private String scrapeInterval;

    private String scrapePool;

    private String scrapeTimeout;

    private String scrapeUrl;

}```

```java
@Data
public class PromMetricInfo {

    /**
     * prometheus实例名称
     */
    private String instance;

    /**
     * prometheus任务名称
     */
    private String job;

  /**
     * 有其他指标可以继续继续优化实体
     */
}

4. 编写接口方法

/**
 * @author gf
 * @date 2022/10/9
 */
@Slf4j
@RestController
@RequestMapping("/api/monitor")
public class MonitorController {

    @GetMapping("/list")
    public SingleResponse<List<PromResultInfo>> getMonitorList(){
        RestTemplate restTemplate = RestTemplateUtils.restTemplate();

        String url = "http://localhost:9090/api/v1/targets?state=active";
        PromResponceInfo prom = restTemplate.getForObject(url, PromResponceInfo.class);

        List<PromResultInfo> activeTargets = prom.getData().getActiveTargets();

        return SingleResponse.buildSuccess(activeTargets);
    }
}

5. 测试结果

Java获取Prometheus监控服务列表_第3张图片

我们可以在本地打印日志查看返回结信息,我是在本地编写了一个页面来查看返回响应结果的,本次Demo仅供大家参考

你可能感兴趣的:(Prometheus,prometheus,java,1024程序员节)