Skip to content

Commit

Permalink
Add JVM metrics
Browse files Browse the repository at this point in the history
Signed-off-by: Fabian Stäber <[email protected]>
  • Loading branch information
fstab committed Sep 7, 2023
1 parent f9a42e6 commit b06dcb8
Show file tree
Hide file tree
Showing 38 changed files with 2,627 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@
<artifactId>prometheus-metrics-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>prometheus-metrics-instrumentation-jvm</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>prometheus-metrics-exporter-servlet-jakarta</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.prometheus.metrics.examples.otel_exemplars.greeting;

import io.prometheus.metrics.exporter.servlet.jakarta.PrometheusMetricsServlet;
import io.prometheus.metrics.instrumentation.jvm.JvmMetrics;
import org.apache.catalina.Context;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.startup.Tomcat;
Expand All @@ -14,6 +15,8 @@ public class Main {

public static void main(String[] args) throws LifecycleException {

JvmMetrics.newBuilder().register();

Tomcat tomcat = new Tomcat();
tomcat.setPort(8081);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@
<artifactId>prometheus-metrics-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>prometheus-metrics-instrumentation-jvm</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>prometheus-metrics-exporter-servlet-jakarta</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.prometheus.metrics.examples.otel_exemplars.app;

import io.prometheus.metrics.exporter.servlet.jakarta.PrometheusMetricsServlet;
import io.prometheus.metrics.instrumentation.jvm.JvmMetrics;
import org.apache.catalina.Context;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.startup.Tomcat;
Expand All @@ -14,6 +15,8 @@ public class Main {

public static void main(String[] args) throws LifecycleException {

JvmMetrics.newBuilder().register();

Tomcat tomcat = new Tomcat();
tomcat.setPort(8080);

Expand Down
5 changes: 5 additions & 0 deletions examples/example-exporter-httpserver/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@
<artifactId>prometheus-metrics-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>prometheus-metrics-instrumentation-jvm</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>prometheus-metrics-exporter-httpserver</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import io.prometheus.metrics.core.metrics.Counter;
import io.prometheus.metrics.exporter.httpserver.HTTPServer;
import io.prometheus.metrics.instrumentation.jvm.JvmMetrics;
import io.prometheus.metrics.model.snapshots.Unit;

import java.io.IOException;
Expand All @@ -13,6 +14,14 @@ public class Main {

public static void main(String[] args) throws IOException, InterruptedException {

JvmMetrics.newBuilder().register();

// Note: uptime_seconds_total is not a great example:
// The built-in JvmMetrics have an out-of-the-box metric named process_start_time_seconds
// with the start timestamp in seconds, so if you want to know the uptime you can simply
// run the Prometheus query
// time() - process_start_time_seconds
// rather than creating a custom uptime metric.
Counter counter = Counter.newBuilder()
.withName("uptime_seconds_total")
.withHelp("total number of seconds since this application was started")
Expand Down
5 changes: 5 additions & 0 deletions examples/example-exporter-opentelemetry/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@
<artifactId>prometheus-metrics-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>prometheus-metrics-instrumentation-jvm</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>prometheus-metrics-exporter-opentelemetry</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import io.prometheus.metrics.core.metrics.Counter;
import io.prometheus.metrics.exporter.opentelemetry.OpenTelemetryExporter;
import io.prometheus.metrics.instrumentation.jvm.JvmMetrics;
import io.prometheus.metrics.model.snapshots.Unit;

/**
Expand All @@ -11,6 +12,17 @@ public class Main {

public static void main(String[] args) throws Exception {

// Note: Some JVM metrics are also defined as OpenTelemetry's semantic conventions.
// We have plans to implement a configuration option for JvmMetrics to use OpenTelemetry
// naming conventions rather than the Prometheus names.
JvmMetrics.newBuilder().register();

// Note: uptime_seconds_total is not a great example:
// The built-in JvmMetrics have an out-of-the-box metric named process_start_time_seconds
// with the start timestamp in seconds, so if you want to know the uptime you can simply
// run the Prometheus query
// time() - process_start_time_seconds
// rather than creating a custom uptime metric.
Counter counter = Counter.newBuilder()
.withName("uptime_seconds_total")
.withHelp("total number of seconds since this application was started")
Expand Down
5 changes: 5 additions & 0 deletions examples/example-exporter-servlet-tomcat/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@
<artifactId>prometheus-metrics-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>prometheus-metrics-instrumentation-jvm</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>prometheus-metrics-exporter-servlet-jakarta</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ public class HelloWorldServlet extends HttpServlet {

private final Random random = new Random(0);

// Note: The requests_total counter is not a great example, because the
// request_duration_seconds histogram below also has a count with the number of requests.
private final Counter counter = Counter.newBuilder()
.withName("requests_total")
.withHelp("total number of requests")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.prometheus.metrics.examples.tomcat_servlet;

import io.prometheus.metrics.exporter.servlet.jakarta.PrometheusMetricsServlet;
import io.prometheus.metrics.instrumentation.jvm.JvmMetrics;
import org.apache.catalina.Context;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.startup.Tomcat;
Expand All @@ -17,6 +18,8 @@ public class Main {

public static void main(String[] args) throws LifecycleException, IOException {

JvmMetrics.newBuilder().register();

Tomcat tomcat = new Tomcat();
Path tmpDir = Files.createTempDirectory("prometheus-tomcat-servlet-example-");
tomcat.setBaseDir(tmpDir.toFile().getAbsolutePath());
Expand Down
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
<module>prometheus-metrics-exporter-servlet-jakarta</module>
<module>prometheus-metrics-exporter-httpserver</module>
<module>prometheus-metrics-exporter-opentelemetry</module>
<module>prometheus-metrics-instrumentation-jvm</module>
<!-- <module>prometheus-metrics-shaded-dependencies</module> -->
<module>examples</module>
<module>integration-tests</module>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,17 @@ public D withLabelValues(String... labelValues) {
return data.computeIfAbsent(Arrays.asList(labelValues), l -> newDataPoint());
}

/**
* Remove the data point with the given label values.
* See <a href="https://prometheus.io/docs/instrumenting/writing_clientlibs/#labels">https://prometheus.io/docs/instrumenting/writing_clientlibs/#labels</a>.
*/
public void remove(String... labelValues) {
data.remove(Arrays.asList(labelValues));
}

// TODO: Write a clear() method that resets the metric (removes all data points),
// see https://prometheus.io/docs/instrumenting/writing_clientlibs/#labels

protected abstract T newDataPoint();

protected T getNoLabels() {
Expand Down
73 changes: 73 additions & 0 deletions prometheus-metrics-instrumentation-jvm/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>io.prometheus</groupId>
<artifactId>client_java</artifactId>
<version>1.0.0-alpha-4-SNAPSHOT</version>
</parent>

<artifactId>prometheus-metrics-instrumentation-jvm</artifactId>
<packaging>bundle</packaging>

<name>Prometheus Metrics Instrumentation - JVM</name>
<description>
Instrumentation library for JVM metrics
</description>

<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>

<developers>
<developer>
<id>brian-brazil</id>
<name>Brian Brazil</name>
<email>[email protected]</email>
</developer>
<developer>
<id>fstab</id>
<name>Fabian Stäber</name>
<email>[email protected]</email>
</developer>
</developers>

<dependencies>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>prometheus-metrics-core</artifactId>
<version>${project.version}</version>
</dependency>

<!-- test dependencies -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>4.11.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>prometheus-metrics-exporter-httpserver</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>prometheus-metrics-exposition-formats</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package io.prometheus.metrics.instrumentation.jvm;

import io.prometheus.metrics.config.PrometheusProperties;
import io.prometheus.metrics.core.metrics.GaugeWithCallback;
import io.prometheus.metrics.model.registry.PrometheusRegistry;
import io.prometheus.metrics.model.snapshots.Unit;

import java.lang.management.BufferPoolMXBean;
import java.lang.management.ManagementFactory;
import java.util.List;

/**
* JVM Buffer Pool metrics. The {@link JvmBufferPoolMetrics} are registered as part of the {@link JvmMetrics} like this:
* <pre>{@code
* JvmMetrics.newBuilder().register();
* }</pre>
* However, if you want only the {@link JvmBufferPoolMetrics} you can also register them directly:
* <pre>{@code
* JvmBufferPoolMetrics.newBuilder().register();
* }</pre>
* Example metrics being exported:
* <pre>
* # HELP jvm_buffer_pool_capacity_bytes Bytes capacity of a given JVM buffer pool.
* # TYPE jvm_buffer_pool_capacity_bytes gauge
* jvm_buffer_pool_capacity_bytes{pool="direct"} 8192.0
* jvm_buffer_pool_capacity_bytes{pool="mapped"} 0.0
* # HELP jvm_buffer_pool_used_buffers Used buffers of a given JVM buffer pool.
* # TYPE jvm_buffer_pool_used_buffers gauge
* jvm_buffer_pool_used_buffers{pool="direct"} 1.0
* jvm_buffer_pool_used_buffers{pool="mapped"} 0.0
* # HELP jvm_buffer_pool_used_bytes Used bytes of a given JVM buffer pool.
* # TYPE jvm_buffer_pool_used_bytes gauge
* jvm_buffer_pool_used_bytes{pool="direct"} 8192.0
* jvm_buffer_pool_used_bytes{pool="mapped"} 0.0
* </pre>
*/
public class JvmBufferPoolMetrics {

private static final String JVM_BUFFER_POOL_USED_BYTES = "jvm_buffer_pool_used_bytes";
private static final String JVM_BUFFER_POOL_CAPACITY_BYTES = "jvm_buffer_pool_capacity_bytes";
private static final String JVM_BUFFER_POOL_USED_BUFFERS = "jvm_buffer_pool_used_buffers";

private final PrometheusProperties config;
private final List<BufferPoolMXBean> bufferPoolBeans;

private JvmBufferPoolMetrics(List<BufferPoolMXBean> bufferPoolBeans, PrometheusProperties config) {
this.config = config;
this.bufferPoolBeans = bufferPoolBeans;
}

private void register(PrometheusRegistry registry) {

GaugeWithCallback.newBuilder(config)
.withName(JVM_BUFFER_POOL_USED_BYTES)
.withHelp("Used bytes of a given JVM buffer pool.")
.withUnit(Unit.BYTES)
.withLabelNames("pool")
.withCallback(callback -> {
for (BufferPoolMXBean pool : bufferPoolBeans) {
callback.call(pool.getMemoryUsed(), pool.getName());
}
})
.register(registry);

GaugeWithCallback.newBuilder(config)
.withName(JVM_BUFFER_POOL_CAPACITY_BYTES)
.withHelp("Bytes capacity of a given JVM buffer pool.")
.withUnit(Unit.BYTES)
.withLabelNames("pool")
.withCallback(callback -> {
for (BufferPoolMXBean pool : bufferPoolBeans) {
callback.call(pool.getTotalCapacity(), pool.getName());
}
})
.register(registry);

GaugeWithCallback.newBuilder(config)
.withName(JVM_BUFFER_POOL_USED_BUFFERS)
.withHelp("Used buffers of a given JVM buffer pool.")
.withLabelNames("pool")
.withCallback(callback -> {
for (BufferPoolMXBean pool : bufferPoolBeans) {
callback.call(pool.getCount(), pool.getName());
}
})
.register(registry);
}

public static Builder newBuilder() {
return new Builder(PrometheusProperties.get());
}

public static Builder newBuilder(PrometheusProperties config) {
return new Builder(config);
}

public static class Builder {

private final PrometheusProperties config;
private List<BufferPoolMXBean> bufferPoolBeans;

private Builder(PrometheusProperties config) {
this.config = config;
}

/**
* Package private. For testing only.
*/
Builder withBufferPoolBeans(List<BufferPoolMXBean> bufferPoolBeans) {
this.bufferPoolBeans = bufferPoolBeans;
return this;
}

public void register() {
register(PrometheusRegistry.defaultRegistry);
}

public void register(PrometheusRegistry registry) {
List<BufferPoolMXBean> bufferPoolBeans = this.bufferPoolBeans;
if (bufferPoolBeans == null) {
bufferPoolBeans = ManagementFactory.getPlatformMXBeans(BufferPoolMXBean.class);
}
new JvmBufferPoolMetrics(bufferPoolBeans, config).register(registry);
}
}
}
Loading

0 comments on commit b06dcb8

Please sign in to comment.