自定義加載器中 prometheus 自定義 metric


背景:此前以javaagent的方式集成了prometheus jvm客戶端,jmx-exporter,現需要在此基礎上加幾個自定義參數:

 

Counter newcounter = Counter.build()
                            .name(key)
                            .help(key + "-help")
                            .register();

 

運行后,prometheus取不到這個key的數據,深入調查。

 

 

jmx-exporter這個工程寫了premain方法:

 

 

 

進行了一些Exporter的注冊,特別是jvm的一些指標,接下去看下注冊的代碼:

 最終由CollectorRegistery 靜態成員變量 defaultRegistry來注冊,也就是說一個類加載器所有exporter的注冊都統一進行

javaagent由appclassloader加載,其它所有jar包由Saturn Job classloader加載,這個類加載器父加載器為null,則與appclassloader相互之間類是不可見的。

故javaagent和主業務指標不能共用一個httpserver對prometheus提供metric

 

此前的register代碼雖然也注冊了,但與jvm參數等所在不同的類加載器,兩者注冊到了兩個注冊中心,且這個新的未以http的形式發布給prometheus,用jvm的那個exporter由於兩者類加載器隔離自然是跟蹤不到這些自定義key的。

 

解決:

1 模仿jmx-exporter,新開一個httpserver:

new HTTPServer(socket, CollectorRegistry.defaultRegistry, true);

 

 

public class PromController {

    private static final Logger LOGGER = LoggerFactory.getLogger(PromController.class);

    private static final ConcurrentHashMap<String, Counter> mapCounter = new ConcurrentHashMap<>();

    //線程池
    private static final ExecutorService POOL = new ThreadPoolExecutor(
            2, 4, 0L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(20),
            new RejectedExecutionHandler() {
                @Override
                public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                    LOGGER.warn("放棄線程");
                }
            });

    private static HTTPServer server = null;
    static {
        int cc = 0;
        int port = 9892;
        while (true) {
            if(cc > 10) {
                LOGGER.error("放棄監聽prom:{}", port);
                server = null;
                break;
            }

            InetSocketAddress socket = new InetSocketAddress("0.0.0.0", port);
            try {
                server = new HTTPServer(socket, CollectorRegistry.defaultRegistry, true);
                LOGGER.info("成功監聽prom:{}", port);
                break;
            } catch (IOException e) {
                LOGGER.error("{} {}", e.getMessage(), ++cc);
                port += 10;
            }

        }

    }
    public static void main(String []args) throws InterruptedException {
        while (true) {
            putPromCounter("xxx");
            Thread.sleep(1000);
        }
    }

    public static void putPromCounter(final String key) {

        if(server == null)
            return;

        POOL.submit(new Runnable() {
            @Override
            public void run() {
//                try {
//                    Class<?> cCollectorRegistry = Thread.currentThread().getContextClassLoader().loadClass("io.prometheus.jmx.shaded.io.prometheus.client.CollectorRegistry");
//                    Class<?> cCounter = Thread.currentThread().getContextClassLoader().loadClass("io.prometheus.jmx.shaded.io.prometheus.client.Counter");
//                    Class<?> cCounterBuilder = Thread.currentThread().getContextClassLoader().loadClass("io.prometheus.jmx.shaded.io.prometheus.client.Counter$Builder");
//                    LOGGER.info("CollectorRegistry: {}", cCollectorRegistry.getProtectionDomain().getCodeSource().getLocation());
//                    LOGGER.info("Counter: {}", cCounter.getProtectionDomain().getCodeSource().getLocation());
//                    LOGGER.info("CounterBuilder: {}", cCounterBuilder.getProtectionDomain().getCodeSource().getLocation());
//                } catch (ClassNotFoundException e) {
//                    LOGGER.info("no class ");
//                }

                Counter counter = mapCounter.get(key);

                if(counter == null) {

                    LOGGER.info("new prom counter {}", key);
                    Counter newcounter = Counter.build()
                            .name(key)
                            .help(key + "-help")
                            .register();
                    mapCounter.putIfAbsent(key, newcounter);
                    counter = mapCounter.get(key);

                }

                counter.inc();
            }
        });
    }
}

 

2 prometheus服務端加入對此服務器的拉取

 

 84   - job_name: 'jmx-executor-sym'
 85     scrape_interval: 10s
 86     static_configs:
 87     - targets: ['192.168.57.234:8892']
 88       labels:
 89         instance: executor-sym

 

 

 

當然,也可以直接使用prom的client maven:

基於Grafana和Prometheus的監視系統(3):java客戶端使用

https://www.jianshu.com/p/60c6d6cb4c49

 

 

附屬一個jmx-exporter源碼分析:https://blog.csdn.net/qqqq0199181/article/details/83792364


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM