Harshit Gupta
Harshit Gupta

Reputation: 126

How to redirect Prometheus Metrics to the default spring boot server

I am trying to expose a custom Gauge metric from my Spring Boot Application. I am using Micrometer with the Prometheus registry to do so. I have set up the PrometheusRegistry and configs as per - Micrometer Samples - Github but it creates one more HTTP server for exposing the Prometheus metrics. I need to redirect or expose all the metrics to the Spring boot's default context path - /actuator/prometheus instead of a new context path on a new port. I have implemented the following code so far -

PrometheusRegistry.java -

package com.xyz.abc.prometheus;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.time.Duration;

import com.sun.net.httpserver.HttpServer;

import io.micrometer.core.lang.Nullable;
import io.micrometer.prometheus.PrometheusConfig;
import io.micrometer.prometheus.PrometheusMeterRegistry;

public class PrometheusRegistry {

    public static PrometheusMeterRegistry prometheus() {
        PrometheusMeterRegistry prometheusRegistry = new PrometheusMeterRegistry(new PrometheusConfig() {
            @Override
            public Duration step() {
                return Duration.ofSeconds(10);
            }

            @Override
            @Nullable
            public String get(String k) {
                return null;
            }
        });

        try {
            HttpServer server = HttpServer.create(new InetSocketAddress(8081), 0);
            server.createContext("/sample-data/prometheus", httpExchange -> {
                String response = prometheusRegistry.scrape();
                httpExchange.sendResponseHeaders(200, response.length());
                OutputStream os = httpExchange.getResponseBody();
                os.write(response.getBytes());
                os.close();
            });

            new Thread(server::start).run();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        return prometheusRegistry;
    }
    
}

MicrometerConfig.java -

package com.xyz.abc.prometheus;

import io.micrometer.core.instrument.MeterRegistry;


public class MicrometerConfig {

    public static MeterRegistry carMonitoringSystem() {
        // Pick a monitoring system here to use in your samples.
        return PrometheusRegistry.prometheus();
    }
}

Code snippet where I am creating a custom Gauge metric. As of now, it's a simple REST API to test - (Please read the comments in between)

@SuppressWarnings({ "unchecked", "rawtypes" })
@RequestMapping(value = "/sampleApi", method= RequestMethod.GET)
@ResponseBody
//This Timed annotation is working fine and this metrics comes in /actuator/prometheus by default
@Timed(value = "car.healthcheck", description = "Time taken to return healthcheck")
public ResponseEntity healthCheck(){
    MeterRegistry registry = MicrometerConfig.carMonitoringSystem();
    AtomicLong n = new AtomicLong();
    //Starting from here none of the Gauge metrics shows up in /actuator/prometheus path instead it goes to /sample-data/prometheus on port 8081 as configured.
    registry.gauge("car.gauge.one", Tags.of("k", "v"), n);
    registry.gauge("car.gauge.two", Tags.of("k", "v1"), n, n2 -> n2.get() - 1);
    registry.gauge("car.help.gauge", 89);
    
    //This thing never works! This gauge metrics never shows up in any URI configured
    Gauge.builder("car.gauge.test", cpu)
         .description("car.device.cpu")
         .tags("customer", "demo")
         .register(registry);
    return new ResponseEntity("Car is working fine.", HttpStatus.OK);
}

I need all the metrics to show up inside - /actuator/prometheus instead of a new HTTP Server getting created. I know that I am explicitly creating a new HTTP Server so metrics are popping up there. Please let me know how to avoid creating a new HTTP Server and redirect all the prometheus metrics to the default path - /actuator/prometheus. Also if I use Gauge.builder to define a custom gauge metrics, it never works. Please explain how I can make that work also. Let me know where I am doing wrong. Thank you.

Upvotes: 0

Views: 1245

Answers (1)

checketts
checketts

Reputation: 14963

Every time you call MicrometerConfig.carMonitoringSystem(); it is creating a new prometheus registry (and trying to start a new server)

You need to inject the MeterRegistry in your class that is creating the gauge and use the injected MeterRegistry that way.

Upvotes: 0

Related Questions