需求

公司最近需要进行监控的调整,于是需要用到Prometheus。
Prometheus自带了node_exporter,可是需求往往是多变的,所以在多变的需求下,便萌生了自己写一个Exporter的想法
说干就干

一般Java自定义Exporter

首先翻阅Prometheus的中文文档
很容易就能找到自定义Exporter的章节
找到了这一章节后,剩下的就简单了,跟着文档中的步骤走就行了呗
一、导包
项目用的是maven对依赖进行管理
在pom.xml中加入:

		<dependency>
            <groupId>io.prometheus</groupId>
            <artifactId>simpleclient</artifactId>
            <version>0.11.0</version>
        </dependency>

        <dependency>
            <groupId>io.prometheus</groupId>
            <artifactId>simpleclient_httpserver</artifactId>
            <version>0.11.0</version>
        </dependency>
         

接下来需要进行Exporter核心的功能:对监控数据样本的采集,这一步骤需要继承Collector类并实现父类的collect()方法:

public class YourCustomCollector extends Collector {
    public List<MetricFamilySamples> collect() {
        List<MetricFamilySamples> mfs = new ArrayList<MetricFamilySamples>();

        String metricName = "my_guage_1";

        // Your code to get metrics

        MetricFamilySamples.Sample sample = new MetricFamilySamples.Sample(metricName, Arrays.asList("l1"), Arrays.asList("v1"), 4);
        MetricFamilySamples.Sample sample2 = new MetricFamilySamples.Sample(metricName, Arrays.asList("l1", "l2"), Arrays.asList("v1", "v2"), 3);

        MetricFamilySamples samples = new MetricFamilySamples(metricName, Type.GAUGE, "help", Arrays.asList(sample, sample2));

        mfs.add(samples);
        return mfs;
    }
}

然后调用Collector的register()方法将其注册
再在main方法中启动一个HTTP Server实例:

public class CustomExporter {
    public static void main(String[] args) throws IOException {
        HTTPServer server = new HTTPServer(1234);
    }
}

接下来便可以访问http://127.0.0.1:1234/metrics来获取Prometheus的数据了

SpringBoot实现自定义Exporter

第一阶段目标,在Prometheus中文文档的帮助下轻松完成,接下来便是第二阶段目标:
为了能够自定义Exporter的路径,用SpringBoot再自定义一个Exporter
SpringBoot项目,说到底启动一个Server
故如上一阶段中最后一步,便可以省略。
既然需要自定义路径,那自然是在controller层利用RequestMapping()注解来承载需要更改的路径
为了能在controller中显示Prometheus类型的格式,首先最简单的方法便是直接在方法中定义一串字符,但这种方式回带来一个问题:在Prometheus中打开时回出现错误:以非法字符‘<’开始
这个错误是由于RequestMapping收到的响应是html格式的,为此,将响应类型改为plain格式即可解决该问题,解决方法:在方法开始加入:

 response.setContentType("text/plain; version=0.0.4; charset=utf-8");

即可。
别忘了,此时得到的数据是最开始的时候直接输入的字符串,这还是有问题的,不能按照自己的需求更改需要的数据,也没有真实数据。
为了解决该问题。查看上一阶段中register()方法源码,探究其做了什么能让一个List<MetricFamilySamples>类型的数据转换为response能接受的Prometheus类型的数据
可以很快查找到,数据转换是在TextFormat类中的静态方法write004()内完成的,但是write004()方法需要的是枚举类型而不是List
在service层,根据一阶段中的collector方法,编写返回类型为枚举的方法:

 public Enumeration<Collector.MetricFamilySamples> collect(List<String> metricsNames) {


        List<Collector.MetricFamilySamples> mfs = new ArrayList<>();

        if(metricsNames == null) {
            metricsNames.add("a");
            metricsNames.add("b");
        }

        for(String metricName : metricsNames) {

            Collector.MetricFamilySamples.Sample sample2 = new Collector.MetricFamilySamples.Sample(metricName,
                    Arrays.asList("a_k"), Arrays.asList("a_v"),
                    new Random().nextInt(15), System.currentTimeMillis());
			Collector.MetricFamilySamples samples;
			            Collector.MetricFamilySamples.Sample sample3 = new Collector.MetricFamilySamples.Sample(metricName,
                    Arrays.asList("b_k"), Arrays.asList("b_v"),
                    new Random().nextInt(20), System.currentTimeMillis());
            samples = new Collector.MetricFamilySamples(metricName, Collector.Type.GAUGE, "help", Arrays.asList(sample2,sample3));



            System.out.println(samples);
            mfs.add(samples);

        }
        return Collections.enumeration(mfs);
    }
    

在controller层代码为:

@RequestMapping("/metricsTrue")
    public void metricsTrue(HttpServletResponse response, @RequestParam(value = "metrics", required = false)List<String> metricsNames) throws IOException {
        response.setContentType("text/plain; version=0.0.4; charset=utf-8");
        List<String> metricsNames = new ArrayList<>();
        metricsNames.add("a");
        TextFormat.write004(response.getWriter(), new ExportServer().collect(metricsNames));
    }
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐