children = new ConcurrentHashMap<>();
+
+ /**
+ * Add or replace the cache with the given name.
+ *
+ * Any references any previous cache with this name is invalidated.
+ *
+ * @param cacheName The name of the cache, will be the metrics label value
+ * @param cache The cache being monitored
+ */
+ public void addCache(String cacheName, Cache cache) {
+ children.put(cacheName, cache);
+ }
+
+ /**
+ * Remove the cache with the given name.
+ *
+ * Any references to the cache are invalidated.
+ *
+ * @param cacheName cache to be removed
+ */
+ public Cache removeCache(String cacheName) {
+ return children.remove(cacheName);
+ }
+
+ /**
+ * Remove all caches.
+ *
+ * Any references to all caches are invalidated.
+ */
+ public void clear(){
+ children.clear();
+ }
+
+ @Override
+ public MetricSnapshots collect() {
+ final MetricSnapshots.Builder metricSnapshotsBuilder = MetricSnapshots.builder();
+ final List labelNames = Arrays.asList("cache");
+
+ final CounterSnapshot.Builder cacheHitTotal = CounterSnapshot.builder()
+ .name("guava_cache_hit")
+ .help("Cache hit totals");
+
+ final CounterSnapshot.Builder cacheMissTotal = CounterSnapshot.builder()
+ .name("guava_cache_miss")
+ .help("Cache miss totals");
+
+ final CounterSnapshot.Builder cacheRequestsTotal = CounterSnapshot.builder()
+ .name("guava_cache_requests")
+ .help("Cache request totals");
+
+ final CounterSnapshot.Builder cacheEvictionTotal = CounterSnapshot.builder()
+ .name("guava_cache_eviction")
+ .help("Cache eviction totals, doesn't include manually removed entries");
+
+ final CounterSnapshot.Builder cacheLoadFailure = CounterSnapshot.builder()
+ .name("guava_cache_load_failure")
+ .help("Cache load failures");
+
+ final CounterSnapshot.Builder cacheLoadTotal = CounterSnapshot.builder()
+ .name("guava_cache_loads")
+ .help("Cache loads: both success and failures");
+
+ final GaugeSnapshot.Builder cacheSize = GaugeSnapshot.builder()
+ .name("guava_cache_size")
+ .help("Cache size");
+
+ final SummarySnapshot.Builder cacheLoadSummary = SummarySnapshot.builder()
+ .name("guava_cache_load_duration_seconds")
+ .help("Cache load duration: both success and failures");
+
+ for (final Map.Entry c: children.entrySet()) {
+ final List cacheName = Arrays.asList(c.getKey());
+ final Labels labels = Labels.of(labelNames, cacheName);
+
+ final CacheStats stats = c.getValue().stats();
+
+ cacheHitTotal.dataPoint(
+ CounterSnapshot.CounterDataPointSnapshot.builder()
+ .labels(labels)
+ .value(stats.hitCount())
+ .build()
+ );
+
+ cacheMissTotal.dataPoint(
+ CounterSnapshot.CounterDataPointSnapshot.builder()
+ .labels(labels)
+ .value(stats.missCount())
+ .build()
+ );
+
+ cacheRequestsTotal.dataPoint(
+ CounterSnapshot.CounterDataPointSnapshot.builder()
+ .labels(labels)
+ .value(stats.requestCount())
+ .build()
+ );
+
+ cacheEvictionTotal.dataPoint(
+ CounterSnapshot.CounterDataPointSnapshot.builder()
+ .labels(labels)
+ .value(stats.evictionCount())
+ .build()
+ );
+
+ cacheSize.dataPoint(
+ GaugeSnapshot.GaugeDataPointSnapshot.builder()
+ .labels(labels)
+ .value(c.getValue().size())
+ .build()
+ );
+
+ if (c.getValue() instanceof LoadingCache) {
+ cacheLoadFailure.dataPoint(
+ CounterSnapshot.CounterDataPointSnapshot.builder()
+ .labels(labels)
+ .value(stats.loadExceptionCount())
+ .build()
+ );
+
+ cacheLoadTotal.dataPoint(
+ CounterSnapshot.CounterDataPointSnapshot.builder()
+ .labels(labels)
+ .value(stats.loadCount())
+ .build()
+ );
+
+ cacheLoadSummary.dataPoint(
+ SummarySnapshot.SummaryDataPointSnapshot.builder()
+ .labels(labels)
+ .count(stats.loadCount())
+ .sum(stats.totalLoadTime() / NANOSECONDS_PER_SECOND)
+ .build()
+ );
+ }
+ }
+
+ metricSnapshotsBuilder.metricSnapshot(cacheHitTotal.build());
+ metricSnapshotsBuilder.metricSnapshot(cacheMissTotal.build());
+ metricSnapshotsBuilder.metricSnapshot(cacheRequestsTotal.build());
+ metricSnapshotsBuilder.metricSnapshot(cacheEvictionTotal.build());
+ metricSnapshotsBuilder.metricSnapshot(cacheLoadFailure.build());
+ metricSnapshotsBuilder.metricSnapshot(cacheLoadTotal.build());
+ metricSnapshotsBuilder.metricSnapshot(cacheSize.build());
+ metricSnapshotsBuilder.metricSnapshot(cacheLoadSummary.build());
+
+ return metricSnapshotsBuilder.build();
+ }
+}
diff --git a/prometheus-metrics-instrumentation-guava/src/test/java/io/prometheus/metrics/instrumentation/guava/CacheMetricsCollectorTest.java b/prometheus-metrics-instrumentation-guava/src/test/java/io/prometheus/metrics/instrumentation/guava/CacheMetricsCollectorTest.java
new file mode 100644
index 000000000..41b3bba8d
--- /dev/null
+++ b/prometheus-metrics-instrumentation-guava/src/test/java/io/prometheus/metrics/instrumentation/guava/CacheMetricsCollectorTest.java
@@ -0,0 +1,142 @@
+package io.prometheus.metrics.instrumentation.guava;
+
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import io.prometheus.metrics.expositionformats.OpenMetricsTextFormatWriter;
+import io.prometheus.metrics.model.registry.PrometheusRegistry;
+import io.prometheus.metrics.model.snapshots.CounterSnapshot;
+import io.prometheus.metrics.model.snapshots.DataPointSnapshot;
+import io.prometheus.metrics.model.snapshots.Labels;
+import io.prometheus.metrics.model.snapshots.SummarySnapshot;
+import org.junit.Test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.charset.StandardCharsets;
+
+import static org.assertj.core.api.Java6Assertions.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class CacheMetricsCollectorTest {
+
+ @Test
+ public void cacheExposesMetricsForHitMissAndEviction() {
+ final Cache cache = CacheBuilder.newBuilder().maximumSize(2).recordStats().build();
+
+ final CacheMetricsCollector collector = new CacheMetricsCollector();
+ collector.addCache("users", cache);
+
+ final PrometheusRegistry registry = new PrometheusRegistry();
+ registry.register(collector);
+
+ cache.getIfPresent("user1");
+ cache.getIfPresent("user1");
+ cache.put("user1", "First User");
+ cache.getIfPresent("user1");
+
+ // Add to cache to trigger eviction.
+ cache.put("user2", "Second User");
+ cache.put("user3", "Third User");
+ cache.put("user4", "Fourth User");
+
+ assertCounterMetric(registry, "guava_cache_hit", "users", 1.0);
+ assertCounterMetric(registry, "guava_cache_miss", "users", 2.0);
+ assertCounterMetric(registry, "guava_cache_requests", "users", 3.0);
+ assertCounterMetric(registry, "guava_cache_eviction", "users", 2.0);
+
+ final String expected = "# TYPE guava_cache_eviction counter\n" +
+ "# HELP guava_cache_eviction Cache eviction totals, doesn't include manually removed entries\n" +
+ "guava_cache_eviction_total{cache=\"users\"} 2.0\n" +
+ "# TYPE guava_cache_hit counter\n" +
+ "# HELP guava_cache_hit Cache hit totals\n" +
+ "guava_cache_hit_total{cache=\"users\"} 1.0\n" +
+ "# TYPE guava_cache_miss counter\n" +
+ "# HELP guava_cache_miss Cache miss totals\n" +
+ "guava_cache_miss_total{cache=\"users\"} 2.0\n" +
+ "# TYPE guava_cache_requests counter\n" +
+ "# HELP guava_cache_requests Cache request totals\n" +
+ "guava_cache_requests_total{cache=\"users\"} 3.0\n" +
+ "# TYPE guava_cache_size gauge\n" +
+ "# HELP guava_cache_size Cache size\n" +
+ "guava_cache_size{cache=\"users\"} 2.0\n" +
+ "# EOF\n";
+
+ assertEquals(expected, convertToOpenMetricsFormat(registry));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void loadingCacheExposesMetricsForLoadsAndExceptions() throws Exception {
+ final CacheLoader loader = mock(CacheLoader.class);
+ when(loader.load(anyString()))
+ .thenReturn("First User")
+ .thenThrow(new RuntimeException("Seconds time fails"))
+ .thenReturn("Third User");
+
+ final LoadingCache cache = CacheBuilder.newBuilder().recordStats().build(loader);
+ final CacheMetricsCollector collector = new CacheMetricsCollector();
+ collector.addCache("loadingusers", cache);
+
+ final PrometheusRegistry registry = new PrometheusRegistry();
+ registry.register(collector);
+
+ cache.get("user1");
+ cache.get("user1");
+ try {
+ cache.get("user2");
+ } catch (Exception e) {
+ // ignoring.
+ }
+ cache.get("user3");
+
+ assertCounterMetric(registry, "guava_cache_hit", "loadingusers", 1.0);
+ assertCounterMetric(registry, "guava_cache_miss", "loadingusers", 3.0);
+
+ assertCounterMetric(registry, "guava_cache_load_failure", "loadingusers", 1.0);
+ assertCounterMetric(registry, "guava_cache_loads", "loadingusers", 3.0);
+
+ final SummarySnapshot.SummaryDataPointSnapshot loadDuration = (SummarySnapshot.SummaryDataPointSnapshot) getDataPointSnapshot(
+ registry,
+ "guava_cache_load_duration_seconds",
+ "loadingusers"
+ );
+
+ assertEquals(3, loadDuration.getCount());
+ assertThat(loadDuration.getSum()).isGreaterThan(0);
+ }
+
+ private void assertCounterMetric(PrometheusRegistry registry, String name, String cacheName, double value) {
+ final CounterSnapshot.CounterDataPointSnapshot dataPointSnapshot =
+ (CounterSnapshot.CounterDataPointSnapshot) getDataPointSnapshot(registry, name, cacheName);
+
+ assertEquals(value, dataPointSnapshot.getValue(), 0);
+ }
+
+ private DataPointSnapshot getDataPointSnapshot(PrometheusRegistry registry, String name, String cacheName)
+ {
+ final Labels labels = Labels.of(new String[]{"cache"}, new String[]{cacheName});
+
+ return registry.scrape(name::equals).stream()
+ .flatMap(metricSnapshot -> metricSnapshot.getDataPoints().stream())
+ .filter(dataPoint -> dataPoint.getLabels().equals(labels))
+ .findFirst()
+ .get();
+ }
+
+ private String convertToOpenMetricsFormat(PrometheusRegistry registry) {
+ final ByteArrayOutputStream out = new ByteArrayOutputStream();
+ final OpenMetricsTextFormatWriter writer = new OpenMetricsTextFormatWriter(true, true);
+ try {
+ writer.write(out, registry.scrape());
+ return out.toString(StandardCharsets.UTF_8.name());
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+}
diff --git a/simpleclient-archive/simpleclient_guava/version-rules.xml b/prometheus-metrics-instrumentation-guava/version-rules.xml
similarity index 100%
rename from simpleclient-archive/simpleclient_guava/version-rules.xml
rename to prometheus-metrics-instrumentation-guava/version-rules.xml
diff --git a/simpleclient-archive/simpleclient_guava/src/main/java/io/prometheus/client/guava/cache/CacheMetricsCollector.java b/simpleclient-archive/simpleclient_guava/src/main/java/io/prometheus/client/guava/cache/CacheMetricsCollector.java
deleted file mode 100644
index 5ed0276bb..000000000
--- a/simpleclient-archive/simpleclient_guava/src/main/java/io/prometheus/client/guava/cache/CacheMetricsCollector.java
+++ /dev/null
@@ -1,142 +0,0 @@
-package io.prometheus.client.guava.cache;
-
-import com.google.common.cache.Cache;
-import com.google.common.cache.CacheStats;
-import com.google.common.cache.LoadingCache;
-import io.prometheus.client.Collector;
-import io.prometheus.client.CounterMetricFamily;
-import io.prometheus.client.GaugeMetricFamily;
-import io.prometheus.client.SummaryMetricFamily;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-/**
- * Collect metrics from Guava's com.google.common.cache.Cache.
- *
- *
{@code
- *
- * // Note that `recordStats()` is required to gather non-zero statistics
- * Cache cache = CacheBuilder.newBuilder().recordStats().build();
- * CacheMetricsCollector cacheMetrics = new CacheMetricsCollector().register();
- * cacheMetrics.addCache("mycache", cache);
- *
- * }
- *
- * Exposed metrics are labeled with the provided cache name.
- *
- * With the example above, sample metric names would be:
- *
- * guava_cache_hit_total{cache="mycache"} 10.0
- * guava_cache_miss_total{cache="mycache"} 3.0
- * guava_cache_requests_total{cache="mycache"} 13.0
- * guava_cache_eviction_total{cache="mycache"} 1.0
- * guava_cache_size{cache="mycache"} 5.0
- *
- *
- * Additionally if the cache includes a loader, the following metrics would be provided:
- *
- * guava_cache_load_failure_total{cache="mycache"} 2.0
- * guava_cache_loads_total{cache="mycache"} 7.0
- * guava_cache_load_duration_seconds_count{cache="mycache"} 7.0
- * guava_cache_load_duration_seconds_sum{cache="mycache"} 0.0034
- *
- *
- */
-public class CacheMetricsCollector extends Collector {
-
- protected final ConcurrentMap children = new ConcurrentHashMap();
-
- /**
- * Add or replace the cache with the given name.
- *
- * Any references any previous cache with this name is invalidated.
- *
- * @param cacheName The name of the cache, will be the metrics label value
- * @param cache The cache being monitored
- */
- public void addCache(String cacheName, Cache cache) {
- children.put(cacheName, cache);
- }
-
- /**
- * Remove the cache with the given name.
- *
- * Any references to the cache are invalidated.
- *
- * @param cacheName cache to be removed
- */
- public Cache removeCache(String cacheName) {
- return children.remove(cacheName);
- }
-
- /**
- * Remove all caches.
- *
- * Any references to all caches are invalidated.
- */
- public void clear(){
- children.clear();
- }
-
- @Override
- public List collect() {
- List mfs = new ArrayList();
- List labelNames = Arrays.asList("cache");
-
- CounterMetricFamily cacheHitTotal = new CounterMetricFamily("guava_cache_hit_total",
- "Cache hit totals", labelNames);
- mfs.add(cacheHitTotal);
-
- CounterMetricFamily cacheMissTotal = new CounterMetricFamily("guava_cache_miss_total",
- "Cache miss totals", labelNames);
- mfs.add(cacheMissTotal);
-
- CounterMetricFamily cacheRequestsTotal = new CounterMetricFamily("guava_cache_requests_total",
- "Cache request totals, hits + misses", labelNames);
- mfs.add(cacheRequestsTotal);
-
- CounterMetricFamily cacheEvictionTotal = new CounterMetricFamily("guava_cache_eviction_total",
- "Cache eviction totals, doesn't include manually removed entries", labelNames);
- mfs.add(cacheEvictionTotal);
-
- CounterMetricFamily cacheLoadFailure = new CounterMetricFamily("guava_cache_load_failure_total",
- "Cache load failures", labelNames);
- mfs.add(cacheLoadFailure);
-
- CounterMetricFamily cacheLoadTotal = new CounterMetricFamily("guava_cache_loads_total",
- "Cache loads: both success and failures", labelNames);
- mfs.add(cacheLoadTotal);
-
- GaugeMetricFamily cacheSize = new GaugeMetricFamily("guava_cache_size",
- "Cache size", labelNames);
- mfs.add(cacheSize);
-
- SummaryMetricFamily cacheLoadSummary = new SummaryMetricFamily("guava_cache_load_duration_seconds",
- "Cache load duration: both success and failures", labelNames);
- mfs.add(cacheLoadSummary);
-
- for(Map.Entry c: children.entrySet()) {
- List cacheName = Arrays.asList(c.getKey());
- CacheStats stats = c.getValue().stats();
-
- cacheHitTotal.addMetric(cacheName, stats.hitCount());
- cacheMissTotal.addMetric(cacheName, stats.missCount());
- cacheRequestsTotal.addMetric(cacheName, stats.requestCount());
- cacheEvictionTotal.addMetric(cacheName, stats.evictionCount());
- cacheSize.addMetric(cacheName, c.getValue().size());
-
- if(c.getValue() instanceof LoadingCache) {
- cacheLoadFailure.addMetric(cacheName, stats.loadExceptionCount());
- cacheLoadTotal.addMetric(cacheName, stats.loadCount());
-
- cacheLoadSummary.addMetric(cacheName, stats.loadCount(), stats.totalLoadTime() / Collector.NANOSECONDS_PER_SECOND);
- }
- }
- return mfs;
- }
-}
diff --git a/simpleclient-archive/simpleclient_guava/src/test/java/io/prometheus/client/guava/cache/CacheMetricsCollectorTest.java b/simpleclient-archive/simpleclient_guava/src/test/java/io/prometheus/client/guava/cache/CacheMetricsCollectorTest.java
deleted file mode 100644
index dab30b9fb..000000000
--- a/simpleclient-archive/simpleclient_guava/src/test/java/io/prometheus/client/guava/cache/CacheMetricsCollectorTest.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package io.prometheus.client.guava.cache;
-
-import com.google.common.cache.Cache;
-import com.google.common.cache.CacheBuilder;
-import com.google.common.cache.CacheLoader;
-import com.google.common.cache.LoadingCache;
-import io.prometheus.client.CollectorRegistry;
-import org.junit.Test;
-
-import static org.assertj.core.api.Java6Assertions.assertThat;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class CacheMetricsCollectorTest {
-
- @Test
- public void cacheExposesMetricsForHitMissAndEviction() throws Exception {
- Cache cache = CacheBuilder.newBuilder().maximumSize(2).recordStats().build();
- CollectorRegistry registry = new CollectorRegistry();
-
- CacheMetricsCollector collector = new CacheMetricsCollector().register(registry);
- collector.addCache("users", cache);
-
- cache.getIfPresent("user1");
- cache.getIfPresent("user1");
- cache.put("user1", "First User");
- cache.getIfPresent("user1");
-
- // Add to cache to trigger eviction.
- cache.put("user2", "Second User");
- cache.put("user3", "Third User");
- cache.put("user4", "Fourth User");
-
- assertMetric(registry, "guava_cache_hit_total", "users", 1.0);
- assertMetric(registry, "guava_cache_miss_total", "users", 2.0);
- assertMetric(registry, "guava_cache_requests_total", "users", 3.0);
- assertMetric(registry, "guava_cache_eviction_total", "users", 2.0);
- }
-
- @SuppressWarnings("unchecked")
- @Test
- public void loadingCacheExposesMetricsForLoadsAndExceptions() throws Exception {
- CacheLoader loader = mock(CacheLoader.class);
- when(loader.load(anyString()))
- .thenReturn("First User")
- .thenThrow(new RuntimeException("Seconds time fails"))
- .thenReturn("Third User");
-
- LoadingCache cache = CacheBuilder.newBuilder().recordStats().build(loader);
- CollectorRegistry registry = new CollectorRegistry();
- CacheMetricsCollector collector = new CacheMetricsCollector().register(registry);
- collector.addCache("loadingusers", cache);
-
- cache.get("user1");
- cache.get("user1");
- try{
- cache.get("user2");
- } catch (Exception e) {
- // ignoring.
- }
- cache.get("user3");
-
- assertMetric(registry, "guava_cache_hit_total", "loadingusers", 1.0);
- assertMetric(registry, "guava_cache_miss_total", "loadingusers", 3.0);
-
- assertMetric(registry, "guava_cache_load_failure_total", "loadingusers", 1.0);
- assertMetric(registry, "guava_cache_loads_total", "loadingusers", 3.0);
-
- assertMetric(registry, "guava_cache_load_duration_seconds_count", "loadingusers", 3.0);
- assertMetricGreatThan(registry, "guava_cache_load_duration_seconds_sum", "loadingusers", 0.0);
- }
-
-
- private void assertMetric(CollectorRegistry registry, String name, String cacheName, double value) {
- assertThat(registry.getSampleValue(name, new String[]{"cache"}, new String[]{cacheName})).isEqualTo(value);
- }
-
-
- private void assertMetricGreatThan(CollectorRegistry registry, String name, String cacheName, double value) {
- assertThat(registry.getSampleValue(name, new String[]{"cache"}, new String[]{cacheName})).isGreaterThan(value);
- }
-
-
-}