Skip to content

Commit

Permalink
add support for guava instrumentation with 1.X.X (#979)
Browse files Browse the repository at this point in the history
* move files out of archive
* add support for guava instrumentation with 1.X.X

---------

Signed-off-by: Petar Heyken <[email protected]>
  • Loading branch information
pheyken authored Aug 29, 2024
1 parent b29d4b8 commit c615b0a
Show file tree
Hide file tree
Showing 7 changed files with 371 additions and 235 deletions.
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
<module>prometheus-metrics-exporter-pushgateway</module>
<module>prometheus-metrics-instrumentation-jvm</module>
<module>prometheus-metrics-instrumentation-dropwizard5</module>
<module>prometheus-metrics-instrumentation-guava</module>
<module>prometheus-metrics-simpleclient-bridge</module>
<!-- <module>prometheus-metrics-shaded-dependencies</module> -->
<module>examples</module>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,21 @@
<parent>
<groupId>io.prometheus</groupId>
<artifactId>client_java</artifactId>
<version>1.0.0-beta-2-SNAPSHOT</version>
<version>1.4.0-SNAPSHOT</version>
</parent>

<artifactId>simpleclient_guava</artifactId>
<artifactId>prometheus-metrics-instrumentation-guava</artifactId>
<packaging>bundle</packaging>

<name>Prometheus Java Simpleclient guava</name>
<name>Prometheus Metrics Instrumentation - Guava</name>
<description>
Metrics collector for guava based caches
Instrumentation library guava based caches
</description>

<properties>
<automatic.module.name>io.prometheus.metrics.instrumentation.guava</automatic.module.name>
</properties>

<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
Expand All @@ -30,18 +34,25 @@
<name>Clint Checketts</name>
<email>[email protected]</email>
</developer>

<developer>
<id>pheyken</id>
<name>Petar Heyken</name>
<email>[email protected]</email>
</developer>
</developers>

<dependencies>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient</artifactId>
<artifactId>prometheus-metrics-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.1-jre</version>
<version>33.2.1-jre</version>
<scope>provided</scope>
</dependency>


Expand All @@ -55,15 +66,21 @@
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>4.6.1</version>
<version>5.12.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.23.1</version>
<version>3.26.3</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,203 @@
package io.prometheus.metrics.instrumentation.guava;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheStats;
import com.google.common.cache.LoadingCache;
import io.prometheus.metrics.model.registry.MultiCollector;
import io.prometheus.metrics.model.snapshots.CounterSnapshot;
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;

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.
* <p>
* <pre>{@code
*
* // Note that `recordStats()` is required to gather non-zero statistics
* Cache<String, String> cache = CacheBuilder.newBuilder().recordStats().build();
* CacheMetricsCollector cacheMetrics = new CacheMetricsCollector().register();
* cacheMetrics.addCache("mycache", cache);
*
* }</pre>
*
* Exposed metrics are labeled with the provided cache name.
*
* With the example above, sample metric names would be:
* <pre>
* 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
* </pre>
*
* Additionally, if the cache includes a loader, the following metrics would be provided:
* <pre>
* 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
* </pre>
*
*/
public class CacheMetricsCollector implements MultiCollector {

private static final double NANOSECONDS_PER_SECOND = 1_000_000_000.0;

protected final ConcurrentMap<String, Cache> children = new ConcurrentHashMap<>();

/**
* Add or replace the cache with the given name.
* <p>
* 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.
* <p>
* 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.
* <p>
* Any references to all caches are invalidated.
*/
public void clear(){
children.clear();
}

@Override
public MetricSnapshots collect() {
final MetricSnapshots.Builder metricSnapshotsBuilder = MetricSnapshots.builder();
final List<String> 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<String, Cache> c: children.entrySet()) {
final List<String> 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();
}
}
Loading

0 comments on commit c615b0a

Please sign in to comment.