Reputation: 101
I'm fresh new to Micrometer/Prometheus world.
I need to use it to get some metrics for existing spring application. No spring boot just plain spring java.
And I'm having a lot of trouble registering e.g. MeterRegistry in order to implement Counters or Timers on some endpoints that I want to have metrics for as well as exposing it to prometheus for scraping.
Can you give me some advice on this topic?
Thank you.
I've tried to register a bean of MeterRegistry but I can't seem to do that for PrometheusMeterRegestry nor PrometheuConfig.
Also just exposing localhost:8080/metrics endpoint from spring doesn't seem to provide anything to Prometheus server.
I would like to be able to scrape some simple metrics from my application, like how many times are some endpoints called and how much time does it take for some endpoints to finish the job or some data processing.
Upvotes: 10
Views: 16864
Reputation: 115
I got this going using the following spring bean definition
<bean id="prometheusMeterRegistry" class="io.micrometer.prometheus.PrometheusMeterRegistry">
<constructor-arg>
<util:constant static-field="io.micrometer.prometheus.PrometheusConfig.DEFAULT" />
</constructor-arg>
</bean>
And then created another bean to use it as a REST resource that exposes the metrics for prometheus on /metrics endpoint.
<bean id="metricResource" class="com.example.service.metrics.MetricsResource" init-method="init" />
The Rest class is
package com.example.service.metrics;
import java.io.File;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics;
import io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics;
import io.micrometer.core.instrument.binder.system.ProcessorMetrics;
import io.micrometer.core.instrument.binder.system.UptimeMetrics;
import io.micrometer.prometheus.PrometheusMeterRegistry;
@Path("/")
public class MetricsResource {
@Inject
private PrometheusMeterRegistry _registry;
@GET
public Response getMetrics() {
return Response.ok(_registry.scrape()).build();
}
public void init() {
new JvmThreadMetrics().bindTo(_registry);
new JvmMemoryMetrics().bindTo(_registry);
new io.micrometer.core.instrument.binder.system.DiskSpaceMetrics(new File("/")).bindTo(_registry);
new ProcessorMetrics().bindTo(_registry); // metrics related to the CPU stats
new UptimeMetrics().bindTo(_registry);
}
}
And then in the web.xml I added the following:
<servlet>
<servlet-name>MetricsServices</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.example.service.metrics</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>MetricsServices</servlet-name>
<url-pattern>/metrics</url-pattern>
</servlet-mapping>
I hope this helps you get the metrics when you access https://localhost:<your_port>//metrics
Upvotes: 0
Reputation: 1366
Add below dependency in your pom.xml:
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
<version>1.2.0</version>
</dependency>
Here is a simple test class :
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.DistributionSummary;
import io.micrometer.core.instrument.Meter;
import io.micrometer.core.instrument.Tags;
import io.micrometer.prometheus.PrometheusConfig;
import io.micrometer.prometheus.PrometheusMeterRegistry;
import org.junit.jupiter.api.Test;
public class MicrometerTest {
private PrometheusMeterRegistry registry = new PrometheusMeterRegistry(PrometheusConfig.DEFAULT);
@Test
public void test() {}
// @Test
public void test_metrics() {
Counter.builder("http_requests_total").description("Http Request Total").tags("method", "GET", "handler",
"/employee", "status", "200").register(registry).increment();
Counter.builder("http_requests_total").description("Http Request Total").tags("method", "GET", "handler",
"/employee", "status", "200").register(registry).increment();
DistributionSummary.builder("http_response_time_milliseconds").description("Request completed time in milliseconds")
.tags("method", "GET", "handler", "/employee", "status", "200")
.publishPercentiles(.5,.95,.99)
.register(registry).record(40d);
DistributionSummary.builder("http_response_time_milliseconds").description("Request completed time in milliseconds")
.tags("method", "GET", "handler", "/employee", "status", "200")
.publishPercentiles(.5,.95,.99)
.register(registry).record(50d);
registry.counter("http_requests_total2", "method", "GET", "status", "200").increment();
registry.counter("http_requests_total2", "method", "Post", "status", "200").increment();
registry.counter("http_requests_total2", "method", "GET", "status", "200").increment();
registry.newCounter(new Meter.Id("query time", Tags.of("select query", "country"), null, "query desc", Meter.Type.COUNTER));
System.out.println(registry.scrape());
}
}
If you want to expose it via servlet, add another dependency :
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
Sample servlet to expose metrics:
import com.aeris.amp.metrics.util.MeterRegistry;
import io.micrometer.core.instrument.binder.jvm.DiskSpaceMetrics;
import io.micrometer.core.instrument.binder.jvm.JvmGcMetrics;
import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics;
import io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics;
import io.micrometer.core.instrument.binder.system.ProcessorMetrics;
import io.micrometer.core.instrument.binder.system.UptimeMetrics;
import io.micrometer.prometheus.PrometheusConfig;
import io.micrometer.prometheus.PrometheusMeterRegistry;
import io.prometheus.client.exporter.common.TextFormat;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.Writer;
@WebServlet("/metrics")
public class MetricsServlet extends HttpServlet {
public static PrometheusMeterRegistry registry = new PrometheusMeterRegistry(PrometheusConfig.DEFAULT);
public void init() {
new JvmThreadMetrics().bindTo(registry);
new JvmGcMetrics().bindTo(registry);
new JvmMemoryMetrics().bindTo(registry);
new DiskSpaceMetrics(new File("/")).bindTo(registry);
new ProcessorMetrics().bindTo(registry); // metrics related to the CPU stats
new UptimeMetrics().bindTo(registry);
}
@Override
protected void doGet(final HttpServletRequest req, final HttpServletResponse resp)
throws IOException {
resp.setStatus(HttpServletResponse.SC_OK);
resp.setContentType(TextFormat.CONTENT_TYPE_004);
Writer writer = resp.getWriter();
try {
registry.scrape(writer);
writer.flush();
} finally {
writer.close();
}
}
public static String getMetricsString() {
if (registry == null)
registry = MeterRegistry.registry;
return registry.scrape();
}
}
Upvotes: 18
Reputation: 14943
Without Spring Boot you would register a PrometheusMeterRegistry
and then just use the underlying Prometheus client to create your own controller endpoint named /metrics
and write out to the HttpServletResponse
using the TextFormat
livrary. Here is a usage example
You mentioned having trouble creating the PrometheusMeterRegistry
. You should include those details, since that will be needed.
Upvotes: 0