From a02c3f203442a106579a6e7600ace7e37e103040 Mon Sep 17 00:00:00 2001 From: Jean Hominal Date: Sun, 7 Jan 2024 08:21:53 +0100 Subject: [PATCH 1/5] Change caffeine_cache_eviction_weight from Gauge to Counter Signed-off-by: Jean Hominal --- .../instrumentation/caffeine/CacheMetricsCollector.java | 8 ++++---- .../caffeine/CacheMetricsCollectorTest.java | 7 ++++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/prometheus-metrics-instrumentation-caffeine/src/main/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollector.java b/prometheus-metrics-instrumentation-caffeine/src/main/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollector.java index c5c9fef3c..59bd28a9c 100644 --- a/prometheus-metrics-instrumentation-caffeine/src/main/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollector.java +++ b/prometheus-metrics-instrumentation-caffeine/src/main/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollector.java @@ -146,10 +146,10 @@ public MetricSnapshots collect() { .name(METRIC_NAME_CACHE_EVICTION) .help("Cache eviction totals, doesn't include manually removed entries"); - final GaugeSnapshot.Builder cacheEvictionWeight = - GaugeSnapshot.builder() + final CounterSnapshot.Builder cacheEvictionWeight = + CounterSnapshot.builder() .name(METRIC_NAME_CACHE_EVICTION_WEIGHT) - .help("Cache eviction weight"); + .help("Weight of evicted cache entries, doesn't include manually removed entries"); final CounterSnapshot.Builder cacheLoadFailure = CounterSnapshot.builder().name(METRIC_NAME_CACHE_LOAD_FAILURE).help("Cache load failures"); @@ -175,7 +175,7 @@ public MetricSnapshots collect() { try { cacheEvictionWeight.dataPoint( - GaugeSnapshot.GaugeDataPointSnapshot.builder() + CounterSnapshot.CounterDataPointSnapshot.builder() .labels(labels) .value(stats.evictionWeight()) .build()); diff --git a/prometheus-metrics-instrumentation-caffeine/src/test/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollectorTest.java b/prometheus-metrics-instrumentation-caffeine/src/test/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollectorTest.java index 4ffb1d794..f284d128f 100644 --- a/prometheus-metrics-instrumentation-caffeine/src/test/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollectorTest.java +++ b/prometheus-metrics-instrumentation-caffeine/src/test/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollectorTest.java @@ -52,6 +52,7 @@ public void cacheExposesMetricsForHitMissAndEviction() { assertCounterMetric(registry, "caffeine_cache_miss", "users", 2.0); assertCounterMetric(registry, "caffeine_cache_requests", "users", 3.0); assertCounterMetric(registry, "caffeine_cache_eviction", "users", 2.0); + assertCounterMetric(registry, "caffeine_cache_eviction_weight", "users", 2.0); final String expected = "# TYPE caffeine_cache_estimated_size gauge\n" @@ -60,9 +61,9 @@ public void cacheExposesMetricsForHitMissAndEviction() { + "# TYPE caffeine_cache_eviction counter\n" + "# HELP caffeine_cache_eviction Cache eviction totals, doesn't include manually removed entries\n" + "caffeine_cache_eviction_total{cache=\"users\"} 2.0\n" - + "# TYPE caffeine_cache_eviction_weight gauge\n" - + "# HELP caffeine_cache_eviction_weight Cache eviction weight\n" - + "caffeine_cache_eviction_weight{cache=\"users\"} 2.0\n" + + "# TYPE caffeine_cache_eviction_weight counter\n" + + "# HELP caffeine_cache_eviction_weight Weight of evicted cache entries, doesn't include manually removed entries\n" + + "caffeine_cache_eviction_weight_total{cache=\"users\"} 2.0\n" + "# TYPE caffeine_cache_hit counter\n" + "# HELP caffeine_cache_hit Cache hit totals\n" + "caffeine_cache_hit_total{cache=\"users\"} 1.0\n" From 3c2f60bf4d0ae7dd2b7e4f172b9f8b41949959fa Mon Sep 17 00:00:00 2001 From: Jean Hominal Date: Sun, 7 Jan 2024 09:18:12 +0100 Subject: [PATCH 2/5] Add caffeine_cache_weighted_size gauge metric to caffeine-instrumentation Signed-off-by: Jean Hominal --- .../caffeine/CacheMetricsCollector.java | 19 ++++++ .../caffeine/CacheMetricsCollectorTest.java | 60 +++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/prometheus-metrics-instrumentation-caffeine/src/main/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollector.java b/prometheus-metrics-instrumentation-caffeine/src/main/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollector.java index 59bd28a9c..19a906146 100644 --- a/prometheus-metrics-instrumentation-caffeine/src/main/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollector.java +++ b/prometheus-metrics-instrumentation-caffeine/src/main/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollector.java @@ -3,6 +3,7 @@ import com.github.benmanes.caffeine.cache.AsyncCache; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.LoadingCache; +import com.github.benmanes.caffeine.cache.Policy; import com.github.benmanes.caffeine.cache.stats.CacheStats; import io.prometheus.metrics.model.registry.MultiCollector; import io.prometheus.metrics.model.snapshots.CounterSnapshot; @@ -14,6 +15,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -63,6 +65,7 @@ public class CacheMetricsCollector implements MultiCollector { private static final String METRIC_NAME_CACHE_LOAD_FAILURE = "caffeine_cache_load_failure"; private static final String METRIC_NAME_CACHE_LOADS = "caffeine_cache_loads"; private static final String METRIC_NAME_CACHE_ESTIMATED_SIZE = "caffeine_cache_estimated_size"; + private static final String METRIC_NAME_CACHE_WEIGHTED_SIZE = "caffeine_cache_weighted_size"; private static final String METRIC_NAME_CACHE_LOAD_DURATION_SECONDS = "caffeine_cache_load_duration_seconds"; @@ -77,6 +80,7 @@ public class CacheMetricsCollector implements MultiCollector { METRIC_NAME_CACHE_LOAD_FAILURE, METRIC_NAME_CACHE_LOADS, METRIC_NAME_CACHE_ESTIMATED_SIZE, + METRIC_NAME_CACHE_WEIGHTED_SIZE, METRIC_NAME_CACHE_LOAD_DURATION_SECONDS)); protected final ConcurrentMap> children = new ConcurrentHashMap<>(); @@ -162,6 +166,11 @@ public MetricSnapshots collect() { final GaugeSnapshot.Builder cacheSize = GaugeSnapshot.builder().name(METRIC_NAME_CACHE_ESTIMATED_SIZE).help("Estimated cache size"); + final GaugeSnapshot.Builder cacheWeightedSize = + GaugeSnapshot.builder() + .name(METRIC_NAME_CACHE_WEIGHTED_SIZE) + .help("Approximate accumulated weight of cache entries"); + final SummarySnapshot.Builder cacheLoadSummary = SummarySnapshot.builder() .name(METRIC_NAME_CACHE_LOAD_DURATION_SECONDS) @@ -183,6 +192,15 @@ public MetricSnapshots collect() { // EvictionWeight metric is unavailable, newer version of Caffeine is needed. } + final Optional> eviction = c.getValue().policy().eviction(); + if (eviction.isPresent() && eviction.get().weightedSize().isPresent()) { + cacheWeightedSize.dataPoint( + GaugeSnapshot.GaugeDataPointSnapshot.builder() + .labels(labels) + .value(eviction.get().weightedSize().getAsLong()) + .build()); + } + cacheHitTotal.dataPoint( CounterSnapshot.CounterDataPointSnapshot.builder() .labels(labels) @@ -244,6 +262,7 @@ public MetricSnapshots collect() { .metricSnapshot(cacheLoadFailure.build()) .metricSnapshot(cacheLoadTotal.build()) .metricSnapshot(cacheSize.build()) + .metricSnapshot(cacheWeightedSize.build()) .metricSnapshot(cacheLoadSummary.build()) .build(); } diff --git a/prometheus-metrics-instrumentation-caffeine/src/test/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollectorTest.java b/prometheus-metrics-instrumentation-caffeine/src/test/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollectorTest.java index f284d128f..5d53813be 100644 --- a/prometheus-metrics-instrumentation-caffeine/src/test/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollectorTest.java +++ b/prometheus-metrics-instrumentation-caffeine/src/test/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollectorTest.java @@ -78,6 +78,66 @@ public void cacheExposesMetricsForHitMissAndEviction() { assertThat(convertToOpenMetricsFormat(registry)).isEqualTo(expected); } + @Test + public void weightedCacheExposesMetricsForHitMissAndEvictionWeightedSize() { + // Run cleanup in same thread, to remove async behavior with evictions + final Cache cache = + Caffeine.newBuilder() + .weigher((String k, String v) -> k.length() + v.length()) + .maximumWeight(35) + .recordStats() + .executor(Runnable::run) + .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, "caffeine_cache_hit", "users", 1.0); + assertCounterMetric(registry, "caffeine_cache_miss", "users", 2.0); + assertCounterMetric(registry, "caffeine_cache_requests", "users", 3.0); + assertCounterMetric(registry, "caffeine_cache_eviction", "users", 2.0); + assertCounterMetric(registry, "caffeine_cache_eviction_weight", "users", 31.0); + + final String expected = + "# TYPE caffeine_cache_estimated_size gauge\n" + + "# HELP caffeine_cache_estimated_size Estimated cache size\n" + + "caffeine_cache_estimated_size{cache=\"users\"} 2.0\n" + + "# TYPE caffeine_cache_eviction counter\n" + + "# HELP caffeine_cache_eviction Cache eviction totals, doesn't include manually removed entries\n" + + "caffeine_cache_eviction_total{cache=\"users\"} 2.0\n" + + "# TYPE caffeine_cache_eviction_weight counter\n" + + "# HELP caffeine_cache_eviction_weight Weight of evicted cache entries, doesn't include manually removed entries\n" + + "caffeine_cache_eviction_weight_total{cache=\"users\"} 31.0\n" + + "# TYPE caffeine_cache_hit counter\n" + + "# HELP caffeine_cache_hit Cache hit totals\n" + + "caffeine_cache_hit_total{cache=\"users\"} 1.0\n" + + "# TYPE caffeine_cache_miss counter\n" + + "# HELP caffeine_cache_miss Cache miss totals\n" + + "caffeine_cache_miss_total{cache=\"users\"} 2.0\n" + + "# TYPE caffeine_cache_requests counter\n" + + "# HELP caffeine_cache_requests Cache request totals, hits + misses\n" + + "caffeine_cache_requests_total{cache=\"users\"} 3.0\n" + + "# TYPE caffeine_cache_weighted_size gauge\n" + + "# HELP caffeine_cache_weighted_size Approximate accumulated weight of cache entries\n" + + "caffeine_cache_weighted_size{cache=\"users\"} 31.0\n" + + "# EOF\n"; + + assertThat(convertToOpenMetricsFormat(registry)).isEqualTo(expected); + } + @SuppressWarnings("unchecked") @Test public void loadingCacheExposesMetricsForLoadsAndExceptions() throws Exception { From 27cefa73d8746c810056ca1dbc4176985bb9db89 Mon Sep 17 00:00:00 2001 From: Jean Hominal Date: Sat, 18 Jan 2025 00:00:53 +0100 Subject: [PATCH 3/5] Add Builder pattern for caffeine CacheMetricsCollector Signed-off-by: Jean Hominal --- .../caffeine/CacheMetricsCollector.java | 12 +++++++++++- .../caffeine/CacheMetricsCollectorTest.java | 10 +++++----- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/prometheus-metrics-instrumentation-caffeine/src/main/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollector.java b/prometheus-metrics-instrumentation-caffeine/src/main/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollector.java index 19a906146..58f117bf5 100644 --- a/prometheus-metrics-instrumentation-caffeine/src/main/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollector.java +++ b/prometheus-metrics-instrumentation-caffeine/src/main/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollector.java @@ -27,7 +27,7 @@ *
{@code
  * // Note that `recordStats()` is required to gather non-zero statistics
  * Cache cache = Caffeine.newBuilder().recordStats().build();
- * CacheMetricsCollector cacheMetrics = new CacheMetricsCollector();
+ * CacheMetricsCollector cacheMetrics = CacheMetricsCollector.builder().build();
  * PrometheusRegistry.defaultRegistry.register(cacheMetrics);
  * cacheMetrics.addCache("mycache", cache);
  *
@@ -271,4 +271,14 @@ public MetricSnapshots collect() {
   public List getPrometheusNames() {
     return ALL_METRIC_NAMES;
   }
+
+  public static Builder builder() {
+    return new Builder();
+  }
+
+  public static class Builder {
+    public CacheMetricsCollector build() {
+      return new CacheMetricsCollector();
+    }
+  }
 }
diff --git a/prometheus-metrics-instrumentation-caffeine/src/test/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollectorTest.java b/prometheus-metrics-instrumentation-caffeine/src/test/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollectorTest.java
index 5d53813be..19ece9263 100644
--- a/prometheus-metrics-instrumentation-caffeine/src/test/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollectorTest.java
+++ b/prometheus-metrics-instrumentation-caffeine/src/test/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollectorTest.java
@@ -32,7 +32,7 @@ public void cacheExposesMetricsForHitMissAndEviction() {
     final Cache cache =
         Caffeine.newBuilder().maximumSize(2).recordStats().executor(Runnable::run).build();
 
-    final CacheMetricsCollector collector = new CacheMetricsCollector();
+    final CacheMetricsCollector collector = CacheMetricsCollector.builder().build();
     collector.addCache("users", cache);
 
     final PrometheusRegistry registry = new PrometheusRegistry();
@@ -89,7 +89,7 @@ public void weightedCacheExposesMetricsForHitMissAndEvictionWeightedSize() {
             .executor(Runnable::run)
             .build();
 
-    final CacheMetricsCollector collector = new CacheMetricsCollector();
+    final CacheMetricsCollector collector = CacheMetricsCollector.builder().build();
     collector.addCache("users", cache);
 
     final PrometheusRegistry registry = new PrometheusRegistry();
@@ -148,7 +148,7 @@ public void loadingCacheExposesMetricsForLoadsAndExceptions() throws Exception {
         .thenReturn("Third User");
 
     final LoadingCache cache = Caffeine.newBuilder().recordStats().build(loader);
-    final CacheMetricsCollector collector = new CacheMetricsCollector();
+    final CacheMetricsCollector collector = CacheMetricsCollector.builder().build();
 
     collector.addCache("loadingusers", cache);
 
@@ -180,7 +180,7 @@ public void loadingCacheExposesMetricsForLoadsAndExceptions() throws Exception {
 
   @Test
   public void getPrometheusNamesHasSameSizeAsMetricSizeWhenScraping() {
-    final CacheMetricsCollector collector = new CacheMetricsCollector();
+    final CacheMetricsCollector collector = CacheMetricsCollector.builder().build();
 
     final PrometheusRegistry registry = new PrometheusRegistry();
     registry.register(collector);
@@ -193,7 +193,7 @@ public void getPrometheusNamesHasSameSizeAsMetricSizeWhenScraping() {
 
   @Test
   public void collectedMetricNamesAreKnownPrometheusNames() {
-    final CacheMetricsCollector collector = new CacheMetricsCollector();
+    final CacheMetricsCollector collector = CacheMetricsCollector.builder().build();
 
     final PrometheusRegistry registry = new PrometheusRegistry();
     registry.register(collector);

From 5515d62cf47bab5b5bf64ea93b21878388754582 Mon Sep 17 00:00:00 2001
From: Jean Hominal 
Date: Sat, 18 Jan 2025 01:47:16 +0100
Subject: [PATCH 4/5] Add option collectEvictionWeightAsCounter to collect
 caffeine_cache_eviction_weight as an incremental counter

Signed-off-by: Jean Hominal 
---
 .../caffeine/CacheMetricsCollector.java       |  48 ++++++++-
 .../caffeine/CacheMetricsCollectorTest.java   | 100 ++++++++++++++----
 2 files changed, 126 insertions(+), 22 deletions(-)

diff --git a/prometheus-metrics-instrumentation-caffeine/src/main/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollector.java b/prometheus-metrics-instrumentation-caffeine/src/main/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollector.java
index 58f117bf5..df2b30783 100644
--- a/prometheus-metrics-instrumentation-caffeine/src/main/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollector.java
+++ b/prometheus-metrics-instrumentation-caffeine/src/main/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollector.java
@@ -84,6 +84,30 @@ public class CacheMetricsCollector implements MultiCollector {
               METRIC_NAME_CACHE_LOAD_DURATION_SECONDS));
 
   protected final ConcurrentMap> children = new ConcurrentHashMap<>();
+  private final boolean collectEvictionWeightAsCounter;
+
+  /**
+   * Instantiates a {@link CacheMetricsCollector}, with the legacy parameters.
+   *
+   * 

The use of this constructor is discouraged, in favor of a Builder pattern {@link #builder()} + * + *

Note that the {@link #builder()} API has different default values than this deprecated + * constructor. + */ + @Deprecated + public CacheMetricsCollector() { + this(false); + } + + /** + * Instantiate a {@link CacheMetricsCollector} + * + * @param collectEvictionWeightAsCounter If true, {@code caffeine_cache_eviction_weight} will be + * observed as an incrementing counter instead of a gauge. + */ + protected CacheMetricsCollector(boolean collectEvictionWeightAsCounter) { + this.collectEvictionWeightAsCounter = collectEvictionWeightAsCounter; + } /** * Add or replace the cache with the given name. @@ -154,6 +178,10 @@ public MetricSnapshots collect() { CounterSnapshot.builder() .name(METRIC_NAME_CACHE_EVICTION_WEIGHT) .help("Weight of evicted cache entries, doesn't include manually removed entries"); + final GaugeSnapshot.Builder cacheEvictionWeightLegacyGauge = + GaugeSnapshot.builder() + .name(METRIC_NAME_CACHE_EVICTION_WEIGHT) + .help("Weight of evicted cache entries, doesn't include manually removed entries"); final CounterSnapshot.Builder cacheLoadFailure = CounterSnapshot.builder().name(METRIC_NAME_CACHE_LOAD_FAILURE).help("Cache load failures"); @@ -188,6 +216,11 @@ public MetricSnapshots collect() { .labels(labels) .value(stats.evictionWeight()) .build()); + cacheEvictionWeightLegacyGauge.dataPoint( + GaugeSnapshot.GaugeDataPointSnapshot.builder() + .labels(labels) + .value(stats.evictionWeight()) + .build()); } catch (Exception e) { // EvictionWeight metric is unavailable, newer version of Caffeine is needed. } @@ -258,7 +291,10 @@ public MetricSnapshots collect() { .metricSnapshot(cacheMissTotal.build()) .metricSnapshot(cacheRequestsTotal.build()) .metricSnapshot(cacheEvictionTotal.build()) - .metricSnapshot(cacheEvictionWeight.build()) + .metricSnapshot( + collectEvictionWeightAsCounter + ? cacheEvictionWeight.build() + : cacheEvictionWeightLegacyGauge.build()) .metricSnapshot(cacheLoadFailure.build()) .metricSnapshot(cacheLoadTotal.build()) .metricSnapshot(cacheSize.build()) @@ -277,8 +313,16 @@ public static Builder builder() { } public static class Builder { + + private boolean collectEvictionWeightAsCounter = true; + + public Builder collectEvictionWeightAsCounter(boolean collectEvictionWeightAsCounter) { + this.collectEvictionWeightAsCounter = collectEvictionWeightAsCounter; + return this; + } + public CacheMetricsCollector build() { - return new CacheMetricsCollector(); + return new CacheMetricsCollector(collectEvictionWeightAsCounter); } } } diff --git a/prometheus-metrics-instrumentation-caffeine/src/test/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollectorTest.java b/prometheus-metrics-instrumentation-caffeine/src/test/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollectorTest.java index 19ece9263..55c13a42c 100644 --- a/prometheus-metrics-instrumentation-caffeine/src/test/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollectorTest.java +++ b/prometheus-metrics-instrumentation-caffeine/src/test/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollectorTest.java @@ -13,6 +13,7 @@ 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.GaugeSnapshot; import io.prometheus.metrics.model.snapshots.Labels; import io.prometheus.metrics.model.snapshots.MetricSnapshots; import io.prometheus.metrics.model.snapshots.SummarySnapshot; @@ -22,17 +23,34 @@ import java.nio.charset.StandardCharsets; import java.util.List; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; @SuppressWarnings("CheckReturnValue") class CacheMetricsCollectorTest { + // This enum was added to simplify test parametrization on argument options. + public enum Options { + LEGACY(false), + COLLECT_EVICTION_WEIGHT_AS_COUNTER(true); - @Test - public void cacheExposesMetricsForHitMissAndEviction() { + private final boolean collectEvictionWeightAsCounter; + + Options(boolean collectEvictionWeightAsCounter) { + this.collectEvictionWeightAsCounter = collectEvictionWeightAsCounter; + } + } + + @ParameterizedTest + @EnumSource + public void cacheExposesMetricsForHitMissAndEviction(Options options) { // Run cleanup in same thread, to remove async behavior with evictions final Cache cache = Caffeine.newBuilder().maximumSize(2).recordStats().executor(Runnable::run).build(); - final CacheMetricsCollector collector = CacheMetricsCollector.builder().build(); + final CacheMetricsCollector collector = + CacheMetricsCollector.builder() + .collectEvictionWeightAsCounter(options.collectEvictionWeightAsCounter) + .build(); collector.addCache("users", cache); final PrometheusRegistry registry = new PrometheusRegistry(); @@ -52,7 +70,20 @@ public void cacheExposesMetricsForHitMissAndEviction() { assertCounterMetric(registry, "caffeine_cache_miss", "users", 2.0); assertCounterMetric(registry, "caffeine_cache_requests", "users", 3.0); assertCounterMetric(registry, "caffeine_cache_eviction", "users", 2.0); - assertCounterMetric(registry, "caffeine_cache_eviction_weight", "users", 2.0); + String openMetricEvictionWeightExpectedText; + if (options.collectEvictionWeightAsCounter) { + assertCounterMetric(registry, "caffeine_cache_eviction_weight", "users", 2.0); + openMetricEvictionWeightExpectedText = + "# TYPE caffeine_cache_eviction_weight counter\n" + + "# HELP caffeine_cache_eviction_weight Weight of evicted cache entries, doesn't include manually removed entries\n" + + "caffeine_cache_eviction_weight_total{cache=\"users\"} 2.0\n"; + } else { + assertGaugeMetric(registry, "caffeine_cache_eviction_weight", "users", 2.0); + openMetricEvictionWeightExpectedText = + "# TYPE caffeine_cache_eviction_weight gauge\n" + + "# HELP caffeine_cache_eviction_weight Weight of evicted cache entries, doesn't include manually removed entries\n" + + "caffeine_cache_eviction_weight{cache=\"users\"} 2.0\n"; + } final String expected = "# TYPE caffeine_cache_estimated_size gauge\n" @@ -61,9 +92,7 @@ public void cacheExposesMetricsForHitMissAndEviction() { + "# TYPE caffeine_cache_eviction counter\n" + "# HELP caffeine_cache_eviction Cache eviction totals, doesn't include manually removed entries\n" + "caffeine_cache_eviction_total{cache=\"users\"} 2.0\n" - + "# TYPE caffeine_cache_eviction_weight counter\n" - + "# HELP caffeine_cache_eviction_weight Weight of evicted cache entries, doesn't include manually removed entries\n" - + "caffeine_cache_eviction_weight_total{cache=\"users\"} 2.0\n" + + openMetricEvictionWeightExpectedText + "# TYPE caffeine_cache_hit counter\n" + "# HELP caffeine_cache_hit Cache hit totals\n" + "caffeine_cache_hit_total{cache=\"users\"} 1.0\n" @@ -78,8 +107,9 @@ public void cacheExposesMetricsForHitMissAndEviction() { assertThat(convertToOpenMetricsFormat(registry)).isEqualTo(expected); } - @Test - public void weightedCacheExposesMetricsForHitMissAndEvictionWeightedSize() { + @ParameterizedTest + @EnumSource + public void weightedCacheExposesMetricsForHitMissAndEvictionWeightedSize(Options options) { // Run cleanup in same thread, to remove async behavior with evictions final Cache cache = Caffeine.newBuilder() @@ -89,7 +119,10 @@ public void weightedCacheExposesMetricsForHitMissAndEvictionWeightedSize() { .executor(Runnable::run) .build(); - final CacheMetricsCollector collector = CacheMetricsCollector.builder().build(); + final CacheMetricsCollector collector = + CacheMetricsCollector.builder() + .collectEvictionWeightAsCounter(options.collectEvictionWeightAsCounter) + .build(); collector.addCache("users", cache); final PrometheusRegistry registry = new PrometheusRegistry(); @@ -109,7 +142,20 @@ public void weightedCacheExposesMetricsForHitMissAndEvictionWeightedSize() { assertCounterMetric(registry, "caffeine_cache_miss", "users", 2.0); assertCounterMetric(registry, "caffeine_cache_requests", "users", 3.0); assertCounterMetric(registry, "caffeine_cache_eviction", "users", 2.0); - assertCounterMetric(registry, "caffeine_cache_eviction_weight", "users", 31.0); + String openMetricEvictionWeightExpectedText; + if (options.collectEvictionWeightAsCounter) { + assertCounterMetric(registry, "caffeine_cache_eviction_weight", "users", 31.0); + openMetricEvictionWeightExpectedText = + "# TYPE caffeine_cache_eviction_weight counter\n" + + "# HELP caffeine_cache_eviction_weight Weight of evicted cache entries, doesn't include manually removed entries\n" + + "caffeine_cache_eviction_weight_total{cache=\"users\"} 31.0\n"; + } else { + assertGaugeMetric(registry, "caffeine_cache_eviction_weight", "users", 31.0); + openMetricEvictionWeightExpectedText = + "# TYPE caffeine_cache_eviction_weight gauge\n" + + "# HELP caffeine_cache_eviction_weight Weight of evicted cache entries, doesn't include manually removed entries\n" + + "caffeine_cache_eviction_weight{cache=\"users\"} 31.0\n"; + } final String expected = "# TYPE caffeine_cache_estimated_size gauge\n" @@ -118,9 +164,7 @@ public void weightedCacheExposesMetricsForHitMissAndEvictionWeightedSize() { + "# TYPE caffeine_cache_eviction counter\n" + "# HELP caffeine_cache_eviction Cache eviction totals, doesn't include manually removed entries\n" + "caffeine_cache_eviction_total{cache=\"users\"} 2.0\n" - + "# TYPE caffeine_cache_eviction_weight counter\n" - + "# HELP caffeine_cache_eviction_weight Weight of evicted cache entries, doesn't include manually removed entries\n" - + "caffeine_cache_eviction_weight_total{cache=\"users\"} 31.0\n" + + openMetricEvictionWeightExpectedText + "# TYPE caffeine_cache_hit counter\n" + "# HELP caffeine_cache_hit Cache hit totals\n" + "caffeine_cache_hit_total{cache=\"users\"} 1.0\n" @@ -178,9 +222,13 @@ public void loadingCacheExposesMetricsForLoadsAndExceptions() throws Exception { assertThat(loadDuration.getSum()).isGreaterThan(0); } - @Test - public void getPrometheusNamesHasSameSizeAsMetricSizeWhenScraping() { - final CacheMetricsCollector collector = CacheMetricsCollector.builder().build(); + @ParameterizedTest + @EnumSource + public void getPrometheusNamesHasSameSizeAsMetricSizeWhenScraping(Options options) { + final CacheMetricsCollector collector = + CacheMetricsCollector.builder() + .collectEvictionWeightAsCounter(options.collectEvictionWeightAsCounter) + .build(); final PrometheusRegistry registry = new PrometheusRegistry(); registry.register(collector); @@ -191,9 +239,13 @@ public void getPrometheusNamesHasSameSizeAsMetricSizeWhenScraping() { assertThat(prometheusNames).hasSize(metricSnapshots.size()); } - @Test - public void collectedMetricNamesAreKnownPrometheusNames() { - final CacheMetricsCollector collector = CacheMetricsCollector.builder().build(); + @ParameterizedTest + @EnumSource + public void collectedMetricNamesAreKnownPrometheusNames(Options options) { + final CacheMetricsCollector collector = + CacheMetricsCollector.builder() + .collectEvictionWeightAsCounter(options.collectEvictionWeightAsCounter) + .build(); final PrometheusRegistry registry = new PrometheusRegistry(); registry.register(collector); @@ -214,6 +266,14 @@ private void assertCounterMetric( assertThat(dataPointSnapshot.getValue()).isEqualTo(value); } + private void assertGaugeMetric( + PrometheusRegistry registry, String name, String cacheName, double value) { + final GaugeSnapshot.GaugeDataPointSnapshot dataPointSnapshot = + (GaugeSnapshot.GaugeDataPointSnapshot) getDataPointSnapshot(registry, name, cacheName); + + assertThat(dataPointSnapshot.getValue()).isEqualTo(value); + } + private DataPointSnapshot getDataPointSnapshot( PrometheusRegistry registry, String name, String cacheName) { final Labels labels = Labels.of(new String[] {"cache"}, new String[] {cacheName}); From d7930f536dddb8519e5576fe0ac713af679354a3 Mon Sep 17 00:00:00 2001 From: Jean Hominal Date: Sat, 18 Jan 2025 02:07:34 +0100 Subject: [PATCH 5/5] Add option collectWeightedSize to enable collection of caffeine_cache_weighted_size Signed-off-by: Jean Hominal --- .../caffeine/CacheMetricsCollector.java | 43 ++++++++++++++----- .../caffeine/CacheMetricsCollectorTest.java | 27 +++++++++--- 2 files changed, 53 insertions(+), 17 deletions(-) diff --git a/prometheus-metrics-instrumentation-caffeine/src/main/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollector.java b/prometheus-metrics-instrumentation-caffeine/src/main/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollector.java index df2b30783..a1b8782a3 100644 --- a/prometheus-metrics-instrumentation-caffeine/src/main/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollector.java +++ b/prometheus-metrics-instrumentation-caffeine/src/main/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollector.java @@ -18,6 +18,7 @@ import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.stream.Collectors; /** * Collect metrics from Caffeine's com.github.benmanes.caffeine.cache.Cache. @@ -85,6 +86,7 @@ public class CacheMetricsCollector implements MultiCollector { protected final ConcurrentMap> children = new ConcurrentHashMap<>(); private final boolean collectEvictionWeightAsCounter; + private final boolean collectWeightedSize; /** * Instantiates a {@link CacheMetricsCollector}, with the legacy parameters. @@ -96,7 +98,7 @@ public class CacheMetricsCollector implements MultiCollector { */ @Deprecated public CacheMetricsCollector() { - this(false); + this(false, false); } /** @@ -104,9 +106,12 @@ public CacheMetricsCollector() { * * @param collectEvictionWeightAsCounter If true, {@code caffeine_cache_eviction_weight} will be * observed as an incrementing counter instead of a gauge. + * @param collectWeightedSize If true, {@code caffeine_cache_weighted_size} will be observed. */ - protected CacheMetricsCollector(boolean collectEvictionWeightAsCounter) { + protected CacheMetricsCollector( + boolean collectEvictionWeightAsCounter, boolean collectWeightedSize) { this.collectEvictionWeightAsCounter = collectEvictionWeightAsCounter; + this.collectWeightedSize = collectWeightedSize; } /** @@ -225,13 +230,15 @@ public MetricSnapshots collect() { // EvictionWeight metric is unavailable, newer version of Caffeine is needed. } - final Optional> eviction = c.getValue().policy().eviction(); - if (eviction.isPresent() && eviction.get().weightedSize().isPresent()) { - cacheWeightedSize.dataPoint( - GaugeSnapshot.GaugeDataPointSnapshot.builder() - .labels(labels) - .value(eviction.get().weightedSize().getAsLong()) - .build()); + if (collectWeightedSize) { + final Optional> eviction = c.getValue().policy().eviction(); + if (eviction.isPresent() && eviction.get().weightedSize().isPresent()) { + cacheWeightedSize.dataPoint( + GaugeSnapshot.GaugeDataPointSnapshot.builder() + .labels(labels) + .value(eviction.get().weightedSize().getAsLong()) + .build()); + } } cacheHitTotal.dataPoint( @@ -286,6 +293,10 @@ public MetricSnapshots collect() { } } + if (collectWeightedSize) { + metricSnapshotsBuilder.metricSnapshot(cacheWeightedSize.build()); + } + return metricSnapshotsBuilder .metricSnapshot(cacheHitTotal.build()) .metricSnapshot(cacheMissTotal.build()) @@ -298,13 +309,17 @@ public MetricSnapshots collect() { .metricSnapshot(cacheLoadFailure.build()) .metricSnapshot(cacheLoadTotal.build()) .metricSnapshot(cacheSize.build()) - .metricSnapshot(cacheWeightedSize.build()) .metricSnapshot(cacheLoadSummary.build()) .build(); } @Override public List getPrometheusNames() { + if (!collectWeightedSize) { + return ALL_METRIC_NAMES.stream() + .filter(s -> !METRIC_NAME_CACHE_WEIGHTED_SIZE.equals(s)) + .collect(Collectors.toList()); + } return ALL_METRIC_NAMES; } @@ -315,14 +330,20 @@ public static Builder builder() { public static class Builder { private boolean collectEvictionWeightAsCounter = true; + private boolean collectWeightedSize = true; public Builder collectEvictionWeightAsCounter(boolean collectEvictionWeightAsCounter) { this.collectEvictionWeightAsCounter = collectEvictionWeightAsCounter; return this; } + public Builder collectWeightedSize(boolean collectWeightedSize) { + this.collectWeightedSize = collectWeightedSize; + return this; + } + public CacheMetricsCollector build() { - return new CacheMetricsCollector(collectEvictionWeightAsCounter); + return new CacheMetricsCollector(collectEvictionWeightAsCounter, collectWeightedSize); } } } diff --git a/prometheus-metrics-instrumentation-caffeine/src/test/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollectorTest.java b/prometheus-metrics-instrumentation-caffeine/src/test/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollectorTest.java index 55c13a42c..ac5ec9e2a 100644 --- a/prometheus-metrics-instrumentation-caffeine/src/test/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollectorTest.java +++ b/prometheus-metrics-instrumentation-caffeine/src/test/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollectorTest.java @@ -30,13 +30,17 @@ class CacheMetricsCollectorTest { // This enum was added to simplify test parametrization on argument options. public enum Options { - LEGACY(false), - COLLECT_EVICTION_WEIGHT_AS_COUNTER(true); + LEGACY(false, false), + COLLECT_EVICTION_WEIGHT_AS_COUNTER(true, false), + COLLECT_WEIGHTED_SIZE(false, true), + BUILDER_DEFAULT(true, true); private final boolean collectEvictionWeightAsCounter; + private final boolean collectWeightedSize; - Options(boolean collectEvictionWeightAsCounter) { + Options(boolean collectEvictionWeightAsCounter, boolean collectWeightedSize) { this.collectEvictionWeightAsCounter = collectEvictionWeightAsCounter; + this.collectWeightedSize = collectWeightedSize; } } @@ -50,6 +54,7 @@ public void cacheExposesMetricsForHitMissAndEviction(Options options) { final CacheMetricsCollector collector = CacheMetricsCollector.builder() .collectEvictionWeightAsCounter(options.collectEvictionWeightAsCounter) + .collectWeightedSize(options.collectWeightedSize) .build(); collector.addCache("users", cache); @@ -122,6 +127,7 @@ public void weightedCacheExposesMetricsForHitMissAndEvictionWeightedSize(Options final CacheMetricsCollector collector = CacheMetricsCollector.builder() .collectEvictionWeightAsCounter(options.collectEvictionWeightAsCounter) + .collectWeightedSize(options.collectWeightedSize) .build(); collector.addCache("users", cache); @@ -156,6 +162,15 @@ public void weightedCacheExposesMetricsForHitMissAndEvictionWeightedSize(Options + "# HELP caffeine_cache_eviction_weight Weight of evicted cache entries, doesn't include manually removed entries\n" + "caffeine_cache_eviction_weight{cache=\"users\"} 31.0\n"; } + String openMetricWeightedSizeExpectedText; + if (options.collectWeightedSize) { + openMetricWeightedSizeExpectedText = + "# TYPE caffeine_cache_weighted_size gauge\n" + + "# HELP caffeine_cache_weighted_size Approximate accumulated weight of cache entries\n" + + "caffeine_cache_weighted_size{cache=\"users\"} 31.0\n"; + } else { + openMetricWeightedSizeExpectedText = ""; + } final String expected = "# TYPE caffeine_cache_estimated_size gauge\n" @@ -174,9 +189,7 @@ public void weightedCacheExposesMetricsForHitMissAndEvictionWeightedSize(Options + "# TYPE caffeine_cache_requests counter\n" + "# HELP caffeine_cache_requests Cache request totals, hits + misses\n" + "caffeine_cache_requests_total{cache=\"users\"} 3.0\n" - + "# TYPE caffeine_cache_weighted_size gauge\n" - + "# HELP caffeine_cache_weighted_size Approximate accumulated weight of cache entries\n" - + "caffeine_cache_weighted_size{cache=\"users\"} 31.0\n" + + openMetricWeightedSizeExpectedText + "# EOF\n"; assertThat(convertToOpenMetricsFormat(registry)).isEqualTo(expected); @@ -228,6 +241,7 @@ public void getPrometheusNamesHasSameSizeAsMetricSizeWhenScraping(Options option final CacheMetricsCollector collector = CacheMetricsCollector.builder() .collectEvictionWeightAsCounter(options.collectEvictionWeightAsCounter) + .collectWeightedSize(options.collectWeightedSize) .build(); final PrometheusRegistry registry = new PrometheusRegistry(); @@ -245,6 +259,7 @@ public void collectedMetricNamesAreKnownPrometheusNames(Options options) { final CacheMetricsCollector collector = CacheMetricsCollector.builder() .collectEvictionWeightAsCounter(options.collectEvictionWeightAsCounter) + .collectWeightedSize(options.collectWeightedSize) .build(); final PrometheusRegistry registry = new PrometheusRegistry();