Java获取Prometheus监控指标数据

Java获取Prometheus监控指标数据

一. 准备工作

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

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

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

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

二. 实战

1. 引入依赖
   <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
   </dependency>
2. 编写http请求工具
package com.alibaba.bizworks.om.account.prometheus;
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它获取服务指标的请求地址

在这里插入图片描述

然后根据这个地址在postman发get请求拿到它的响应体结构

在这里插入图片描述

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

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

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


}

这里只关注后面的resultType 和result参数

@Data
public class PromDataInfo {

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

    /**
     * prometheus监控样本指标参数
     */
    private String resultType;
    private List<PromMetric> result;

}
@Data
public class PromMetric {

    /**
     * metric name和描述当前样本特征的labelsets
     */
    private PromMetricInfo metric;

    /**
     * 一个float64的浮点型数据表示当前样本的值。
     */
    private String[] value;

}
@Data
public class PromMetricInfo {

    /**
     * prometheus指标名称
     */
    private String __name__;

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

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


    private String application;
    private String exception;

    private String method;
    private String outcome;
    private String status;
    private String url;
}
/**
 * prometheus服务指标参数
 * @author gf
 * @date 2022/10/19
 */
@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;

}

到这里我们响应体的结构就写好了,还有一个指标参数,我这里写了一个类,后面需要查询指标或者一些聚合函数(PromQL)

package com.alibaba.bizworks.om.account.prometheus;

import lombok.Data;

/**
 * @Title: prometheus常量信息
 * @author gf
 * @date 2022/10/19
 */
@Data
public class PromConstants {
    /**
     * prometheus-查询SUCCESS
     */
    public static final String SUCCESS = "success";

    /**prometheus-查询参数*/
    public static final String QUERY = "query";

    /**系统CPU使用率*/
    public static final String SYSTEM_CPU_USAGE= "system_cpu_usage";
    /**Java虚拟机可用的处理器数量*/
    public static final String SYSTEM_CPU_COUNT= "system_cpu_count";
    /**JVM的CPU利用率*/
    public static final String PROCESS_CPU_COUNT= "process_cpu_usage";

    /**
     *  tomcat相关参数
     */
    /**tomcat_当前活跃会话数*/
    public static final String TOMCAT_SESSIONS_ACTIVE_CURRENT_SESSIONS = "tomcat_sessions_active_current_sessions";

    /**
     *  jvm 相关参数
     */

    /**Java虚拟机的正常运行时间*/
    public static final String PROCESS_UPTIME_SECONDS = "process_uptime_seconds";

    /**可供Java虚拟机使用的已提交的内存量*/
    public static final String JVM_MEMORT_COMMITTED_BYTES = "jvm_memory_committed_bytes";

    /**自Java虚拟机启动或重置峰值以来的活动线程峰值*/
    public static final String JVM_THREADS_PEAK_THREADS= "jvm_threads_peak_threads";

    /**在一个GC之后到下一个GC之前增加年轻代内存池的大小*/
    public static final String JVM_GC_MEMORT_ALLOCATED_BYTES_TOTAL= "jvm_gc_memory_allocated_bytes_total";

    /**进程的开始时间*/
    public static final String PROCESS_START_TIME_SECONDS= "process_start_time_seconds";

    /**最大内存*/
    public static final String JVM_MEMORT_MAX_BYTES= "jvm_memory_max_bytes";

    /**已使用内存*/
    public static final String JVM_MEMORT_USED_BYTES= "jvm_memory_used_bytes";

    /**请求次数*/
    public static final String HTTP_SERVER_REQUEST_SECONDS_COUNT= "http_server_requests_seconds_count";

    /**请求n次花费的时间*/
    public static final String HTTP_SERVER_REQUEST_SECONDS_SUM= "http_server_requests_seconds_sum";

    /**最长一次花了多长时间*/
    public static final String HTTP_SERVER_REQUEST_SECONDS_MAX= "http_server_requests_seconds_max";

    /**日志总数*/
    public static final String LOGBACK_EVENTS_TOTAL = "logback_events_total";

}

4. 编写接口测试

参数说明:

  • promURL:请求url
  • promQL:指标参数
@Slf4j
public class TestController {

    public static PromDataInfo getDateInfo(String promURL, String promQL) {

        log.info("请求地址:{},请求QL:{}", promURL, promQL);
        JSONObject param = new JSONObject();
        param.put(PromConstants.QUERY, promQL);
        String http = null;
        try {
            http = RestTemplateUtils.getHttp(promURL, param);
        } catch (Exception e) {
            log.error("请求地址:{},请求QL:{},异常信息:{}", promURL, promQL, e);
        }
        PromResponceInfo responceInfo = JSON.parseObject(http, PromResponceInfo.class);
        log.info("请求地址:{},请求QL:{},返回信息:{}", promURL, promQL, responceInfo);
        if (Objects.isNull(responceInfo)) {
            return null;
        }
        String status = responceInfo.getStatus();
        if (StringUtils.isBlank(status)
                || !PromConstants.SUCCESS.equals(status)
        ) {
            return null;
        }
        PromDataInfo data = responceInfo.getData();

        return data;
    }

    public static void main(String[] args) {
        PromDataInfo dateInfo= getDateInfo("http://localhost:9090/api/v1/query", PromConstants.HTTP_SERVER_REQUEST_SECONDS_COUNT);
        System.out.println(dateInfo);

    }
}
5. 测试结果

我们可以debug查看获取到的信息
在这里插入图片描述

  • 10
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
要使用Java解析Prometheus指标,你可以使用Prometheus Java客户端库。这个库提供了一些功能,可以帮助你解析和处理Prometheus指标。 首先,你需要将以下依赖项添加到你的项目中: ```xml <dependency> <groupId>io.prometheus</groupId> <artifactId>simpleclient</artifactId> <version>0.10.0</version> </dependency> <dependency> <groupId>io.prometheus</groupId> <artifactId>simpleclient_common</artifactId> <version>0.10.0</version> </dependency> ``` 然后,你可以使用以下代码来解析和处理Prometheus指标: ```java import io.prometheus.client.CollectorRegistry; import io.prometheus.client.Gauge; import io.prometheus.client.exporter.HTTPResponse; import io.prometheus.client.exporter.TextFormat; import java.io.IOException; import java.io.StringWriter; import java.util.Collections; import java.util.Enumeration; public class PrometheusParser { public static void main(String[] args) throws IOException { // 创建一个CollectorRegistry对象 CollectorRegistry registry = new CollectorRegistry(); // 从Prometheus服务器获取指标数据 HTTPResponse response = HTTPResponse.request("http://prometheus_server:port/metrics").execute(); // 将响应内容读取为字符串 String metricsData = response.getBody(); // 使用TextFormat解析指标数据 TextFormat.Parser parser = new TextFormat.Parser(); Enumeration<String> lines = Collections.enumeration(Collections.singleton(metricsData)); parser.collect(lines, registry); // 获取指定名称的指标 Gauge myMetric = (Gauge) registry.getSampleValue("my_metric", new String[]{"label1", "label2"}); if (myMetric != null) { // 处理指标值 double value = myMetric.get(); System.out.println("Metric value: " + value); } } } ``` 以上代码在`main`方法中演示了如何解析和处理Prometheus指标。你需要将`http://prometheus_server:port/metrics`替换为你的Prometheus服务器的地址和端口。然后,你可以使用`registry.getSampleValue`方法获取指定名称的指标,并对其进行处理。 这只是一个简单的示例,你可以根据你的需求进行进一步的处理和操作。希望对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值