Skip to content

Commit c1d0fb9

Browse files
authored
Add a more type safe way of registering gauges (#2642)
Add the `registerGauge` method to `MetricRegistry` that accepts `Gauge<T>` instead of `Metric` which makes it possible to register a gauge as a lambda expression without declaring its type explicitly.
1 parent d785a56 commit c1d0fb9

File tree

16 files changed

+196
-173
lines changed

16 files changed

+196
-173
lines changed

metrics-core/src/main/java/com/codahale/metrics/InstrumentedExecutorService.java

+22-22
Original file line numberDiff line numberDiff line change
@@ -58,31 +58,31 @@ public InstrumentedExecutorService(ExecutorService delegate, MetricRegistry regi
5858

5959
if (delegate instanceof ThreadPoolExecutor) {
6060
ThreadPoolExecutor executor = (ThreadPoolExecutor) delegate;
61-
registry.register(MetricRegistry.name(name, "pool.size"),
62-
(Gauge<Integer>) executor::getPoolSize);
63-
registry.register(MetricRegistry.name(name, "pool.core"),
64-
(Gauge<Integer>) executor::getCorePoolSize);
65-
registry.register(MetricRegistry.name(name, "pool.max"),
66-
(Gauge<Integer>) executor::getMaximumPoolSize);
61+
registry.registerGauge(MetricRegistry.name(name, "pool.size"),
62+
executor::getPoolSize);
63+
registry.registerGauge(MetricRegistry.name(name, "pool.core"),
64+
executor::getCorePoolSize);
65+
registry.registerGauge(MetricRegistry.name(name, "pool.max"),
66+
executor::getMaximumPoolSize);
6767
final BlockingQueue<Runnable> queue = executor.getQueue();
68-
registry.register(MetricRegistry.name(name, "tasks.active"),
69-
(Gauge<Integer>) executor::getActiveCount);
70-
registry.register(MetricRegistry.name(name, "tasks.completed"),
71-
(Gauge<Long>) executor::getCompletedTaskCount);
72-
registry.register(MetricRegistry.name(name, "tasks.queued"),
73-
(Gauge<Integer>) queue::size);
74-
registry.register(MetricRegistry.name(name, "tasks.capacity"),
75-
(Gauge<Integer>) queue::remainingCapacity);
68+
registry.registerGauge(MetricRegistry.name(name, "tasks.active"),
69+
executor::getActiveCount);
70+
registry.registerGauge(MetricRegistry.name(name, "tasks.completed"),
71+
executor::getCompletedTaskCount);
72+
registry.registerGauge(MetricRegistry.name(name, "tasks.queued"),
73+
queue::size);
74+
registry.registerGauge(MetricRegistry.name(name, "tasks.capacity"),
75+
queue::remainingCapacity);
7676
} else if (delegate instanceof ForkJoinPool) {
7777
ForkJoinPool forkJoinPool = (ForkJoinPool) delegate;
78-
registry.register(MetricRegistry.name(name, "tasks.stolen"),
79-
(Gauge<Long>) forkJoinPool::getStealCount);
80-
registry.register(MetricRegistry.name(name, "tasks.queued"),
81-
(Gauge<Long>) forkJoinPool::getQueuedTaskCount);
82-
registry.register(MetricRegistry.name(name, "threads.active"),
83-
(Gauge<Integer>) forkJoinPool::getActiveThreadCount);
84-
registry.register(MetricRegistry.name(name, "threads.running"),
85-
(Gauge<Integer>) forkJoinPool::getRunningThreadCount);
78+
registry.registerGauge(MetricRegistry.name(name, "tasks.stolen"),
79+
forkJoinPool::getStealCount);
80+
registry.registerGauge(MetricRegistry.name(name, "tasks.queued"),
81+
forkJoinPool::getQueuedTaskCount);
82+
registry.registerGauge(MetricRegistry.name(name, "threads.active"),
83+
forkJoinPool::getActiveThreadCount);
84+
registry.registerGauge(MetricRegistry.name(name, "threads.running"),
85+
forkJoinPool::getRunningThreadCount);
8686
}
8787
}
8888

metrics-core/src/main/java/com/codahale/metrics/MetricRegistry.java

+13-1
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,18 @@ protected ConcurrentMap<String, Metric> buildMap() {
7676
return new ConcurrentHashMap<>();
7777
}
7878

79+
/**
80+
* Given a {@link Gauge}, registers it under the given name and returns it
81+
*
82+
* @param name the name of the gauge
83+
* @param <T> the type of the gauge's value
84+
* @return the registered {@link Gauge}
85+
* @since 4.2.10
86+
*/
87+
public <T> Gauge<T> registerGauge(String name, Gauge<T> metric) throws IllegalArgumentException {
88+
return register(name, metric);
89+
}
90+
7991
/**
8092
* Given a {@link Metric}, registers it under the given name.
8193
*
@@ -93,7 +105,7 @@ public <T extends Metric> T register(String name, T metric) throws IllegalArgume
93105
}
94106

95107
if (metric instanceof MetricRegistry) {
96-
final MetricRegistry childRegistry = (MetricRegistry)metric;
108+
final MetricRegistry childRegistry = (MetricRegistry) metric;
97109
final String childName = name;
98110
childRegistry.addListener(new MetricRegistryListener() {
99111
@Override

metrics-core/src/test/java/com/codahale/metrics/MetricRegistryTest.java

+16-2
Original file line numberDiff line numberDiff line change
@@ -615,15 +615,29 @@ public void removingDeepChildMetricsAfterRegister() {
615615
assertThat(deepChildMetrics.size()).isEqualTo(1);
616616
assertThat(childMetrics.size()).isEqualTo(3);
617617
}
618-
618+
619619
@Test
620620
public void registerNullMetric() {
621-
MetricRegistry registry = new MetricRegistry();
621+
MetricRegistry registry = new MetricRegistry();
622622
try {
623623
registry.register("any_name", null);
624624
Assert.fail("NullPointerException must be thrown !!!");
625625
} catch (NullPointerException e) {
626626
Assert.assertEquals("metric == null", e.getMessage());
627627
}
628628
}
629+
630+
@Test
631+
public void infersGaugeType() {
632+
Gauge<Long> gauge = registry.registerGauge("gauge", () -> 10_000_000_000L);
633+
634+
assertThat(gauge.getValue()).isEqualTo(10_000_000_000L);
635+
}
636+
637+
@Test
638+
public void registersGaugeAsLambda() {
639+
registry.registerGauge("gauge", () -> 3.14);
640+
641+
assertThat(registry.gauge("gauge").getValue()).isEqualTo(3.14);
642+
}
629643
}

metrics-ehcache/src/main/java/com/codahale/metrics/ehcache/InstrumentedEhcache.java

+34-35
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.codahale.metrics.ehcache;
22

3-
import com.codahale.metrics.Gauge;
43
import com.codahale.metrics.MetricRegistry;
54
import com.codahale.metrics.Timer;
65
import net.sf.ehcache.CacheException;
@@ -118,56 +117,56 @@ public class InstrumentedEhcache extends EhcacheDecoratorAdapter {
118117
public static Ehcache instrument(MetricRegistry registry, final Ehcache cache) {
119118

120119
final String prefix = name(cache.getClass(), cache.getName());
121-
registry.register(name(prefix, "hits"),
122-
(Gauge<Long>) () -> cache.getStatistics().cacheHitCount());
120+
registry.registerGauge(name(prefix, "hits"),
121+
() -> cache.getStatistics().cacheHitCount());
123122

124-
registry.register(name(prefix, "in-memory-hits"),
125-
(Gauge<Long>) () -> cache.getStatistics().localHeapHitCount());
123+
registry.registerGauge(name(prefix, "in-memory-hits"),
124+
() -> cache.getStatistics().localHeapHitCount());
126125

127-
registry.register(name(prefix, "off-heap-hits"),
128-
(Gauge<Long>) () -> cache.getStatistics().localOffHeapHitCount());
126+
registry.registerGauge(name(prefix, "off-heap-hits"),
127+
() -> cache.getStatistics().localOffHeapHitCount());
129128

130-
registry.register(name(prefix, "on-disk-hits"),
131-
(Gauge<Long>) () -> cache.getStatistics().localDiskHitCount());
129+
registry.registerGauge(name(prefix, "on-disk-hits"),
130+
() -> cache.getStatistics().localDiskHitCount());
132131

133-
registry.register(name(prefix, "misses"),
134-
(Gauge<Long>) () -> cache.getStatistics().cacheMissCount());
132+
registry.registerGauge(name(prefix, "misses"),
133+
() -> cache.getStatistics().cacheMissCount());
135134

136-
registry.register(name(prefix, "in-memory-misses"),
137-
(Gauge<Long>) () -> cache.getStatistics().localHeapMissCount());
135+
registry.registerGauge(name(prefix, "in-memory-misses"),
136+
() -> cache.getStatistics().localHeapMissCount());
138137

139-
registry.register(name(prefix, "off-heap-misses"),
140-
(Gauge<Long>) () -> cache.getStatistics().localOffHeapMissCount());
138+
registry.registerGauge(name(prefix, "off-heap-misses"),
139+
() -> cache.getStatistics().localOffHeapMissCount());
141140

142-
registry.register(name(prefix, "on-disk-misses"),
143-
(Gauge<Long>) () -> cache.getStatistics().localDiskMissCount());
141+
registry.registerGauge(name(prefix, "on-disk-misses"),
142+
() -> cache.getStatistics().localDiskMissCount());
144143

145-
registry.register(name(prefix, "objects"),
146-
(Gauge<Long>) () -> cache.getStatistics().getSize());
144+
registry.registerGauge(name(prefix, "objects"),
145+
() -> cache.getStatistics().getSize());
147146

148-
registry.register(name(prefix, "in-memory-objects"),
149-
(Gauge<Long>) () -> cache.getStatistics().getLocalHeapSize());
147+
registry.registerGauge(name(prefix, "in-memory-objects"),
148+
() -> cache.getStatistics().getLocalHeapSize());
150149

151-
registry.register(name(prefix, "off-heap-objects"),
152-
(Gauge<Long>) () -> cache.getStatistics().getLocalOffHeapSize());
150+
registry.registerGauge(name(prefix, "off-heap-objects"),
151+
() -> cache.getStatistics().getLocalOffHeapSize());
153152

154-
registry.register(name(prefix, "on-disk-objects"),
155-
(Gauge<Long>) () -> cache.getStatistics().getLocalDiskSize());
153+
registry.registerGauge(name(prefix, "on-disk-objects"),
154+
() -> cache.getStatistics().getLocalDiskSize());
156155

157-
registry.register(name(prefix, "mean-get-time"),
158-
(Gauge<Double>) () -> cache.getStatistics().cacheGetOperation().latency().average().value());
156+
registry.registerGauge(name(prefix, "mean-get-time"),
157+
() -> cache.getStatistics().cacheGetOperation().latency().average().value());
159158

160-
registry.register(name(prefix, "mean-search-time"),
161-
(Gauge<Double>) () -> cache.getStatistics().cacheSearchOperation().latency().average().value());
159+
registry.registerGauge(name(prefix, "mean-search-time"),
160+
() -> cache.getStatistics().cacheSearchOperation().latency().average().value());
162161

163-
registry.register(name(prefix, "eviction-count"),
164-
(Gauge<Long>) () -> cache.getStatistics().cacheEvictionOperation().count().value());
162+
registry.registerGauge(name(prefix, "eviction-count"),
163+
() -> cache.getStatistics().cacheEvictionOperation().count().value());
165164

166-
registry.register(name(prefix, "searches-per-second"),
167-
(Gauge<Double>) () -> cache.getStatistics().cacheSearchOperation().rate().value());
165+
registry.registerGauge(name(prefix, "searches-per-second"),
166+
() -> cache.getStatistics().cacheSearchOperation().rate().value());
168167

169-
registry.register(name(prefix, "writer-queue-size"),
170-
(Gauge<Long>) () -> cache.getStatistics().getWriterQueueLength());
168+
registry.registerGauge(name(prefix, "writer-queue-size"),
169+
() -> cache.getStatistics().getWriterQueueLength());
171170

172171
return new InstrumentedEhcache(registry, cache);
173172
}

metrics-ehcache/src/test/java/com/codahale/metrics/ehcache/InstrumentedEhcacheTest.java

+22
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
import static com.codahale.metrics.MetricRegistry.name;
1414
import static org.assertj.core.api.Assertions.assertThat;
15+
import static org.assertj.core.api.Assertions.entry;
1516

1617
public class InstrumentedEhcacheTest {
1718
private static final CacheManager MANAGER = CacheManager.create();
@@ -24,6 +25,27 @@ public void setUp() {
2425
final Cache c = new Cache(new CacheConfiguration("test", 100));
2526
MANAGER.addCache(c);
2627
this.cache = InstrumentedEhcache.instrument(registry, c);
28+
assertThat(registry.getGauges().entrySet().stream()
29+
.map(e -> entry(e.getKey(), e.getValue().getValue())))
30+
.containsOnly(
31+
entry("net.sf.ehcache.Cache.test.eviction-count", 0L),
32+
entry("net.sf.ehcache.Cache.test.hits", 0L),
33+
entry("net.sf.ehcache.Cache.test.in-memory-hits", 0L),
34+
entry("net.sf.ehcache.Cache.test.in-memory-misses", 0L),
35+
entry("net.sf.ehcache.Cache.test.in-memory-objects", 0L),
36+
entry("net.sf.ehcache.Cache.test.mean-get-time", Double.NaN),
37+
entry("net.sf.ehcache.Cache.test.mean-search-time", Double.NaN),
38+
entry("net.sf.ehcache.Cache.test.misses", 0L),
39+
entry("net.sf.ehcache.Cache.test.objects", 0L),
40+
entry("net.sf.ehcache.Cache.test.off-heap-hits", 0L),
41+
entry("net.sf.ehcache.Cache.test.off-heap-misses", 0L),
42+
entry("net.sf.ehcache.Cache.test.off-heap-objects", 0L),
43+
entry("net.sf.ehcache.Cache.test.on-disk-hits", 0L),
44+
entry("net.sf.ehcache.Cache.test.on-disk-misses", 0L),
45+
entry("net.sf.ehcache.Cache.test.on-disk-objects", 0L),
46+
entry("net.sf.ehcache.Cache.test.searches-per-second", 0.0),
47+
entry("net.sf.ehcache.Cache.test.writer-queue-size", 0L)
48+
);
2749
}
2850

2951
@Test
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.codahale.metrics.httpasyncclient;
22

3-
import com.codahale.metrics.Gauge;
43
import com.codahale.metrics.MetricRegistry;
54
import org.apache.http.config.Registry;
65
import org.apache.http.conn.DnsResolver;
@@ -20,26 +19,18 @@ public class InstrumentedNClientConnManager extends PoolingNHttpClientConnection
2019

2120
public InstrumentedNClientConnManager(final ConnectingIOReactor ioreactor, final NHttpConnectionFactory<ManagedNHttpClientConnection> connFactory, final SchemePortResolver schemePortResolver, final MetricRegistry metricRegistry, final Registry<SchemeIOSessionStrategy> iosessionFactoryRegistry, final long timeToLive, final TimeUnit tunit, final DnsResolver dnsResolver, final String name) {
2221
super(ioreactor, connFactory, iosessionFactoryRegistry, schemePortResolver, dnsResolver, timeToLive, tunit);
23-
metricRegistry.register(name(NHttpClientConnectionManager.class, name, "available-connections"),
24-
(Gauge<Integer>) () -> {
25-
// this acquires a lock on the connection pool; remove if contention sucks
26-
return getTotalStats().getAvailable();
27-
});
28-
metricRegistry.register(name(NHttpClientConnectionManager.class, name, "leased-connections"),
29-
(Gauge<Integer>) () -> {
30-
// this acquires a lock on the connection pool; remove if contention sucks
31-
return getTotalStats().getLeased();
32-
});
33-
metricRegistry.register(name(NHttpClientConnectionManager.class, name, "max-connections"),
34-
(Gauge<Integer>) () -> {
35-
// this acquires a lock on the connection pool; remove if contention sucks
36-
return getTotalStats().getMax();
37-
});
38-
metricRegistry.register(name(NHttpClientConnectionManager.class, name, "pending-connections"),
39-
(Gauge<Integer>) () -> {
40-
// this acquires a lock on the connection pool; remove if contention sucks
41-
return getTotalStats().getPending();
42-
});
22+
// this acquires a lock on the connection pool; remove if contention sucks
23+
metricRegistry.registerGauge(name(NHttpClientConnectionManager.class, name, "available-connections"),
24+
() -> getTotalStats().getAvailable());
25+
// this acquires a lock on the connection pool; remove if contention sucks
26+
metricRegistry.registerGauge(name(NHttpClientConnectionManager.class, name, "leased-connections"),
27+
() -> getTotalStats().getLeased());
28+
// this acquires a lock on the connection pool; remove if contention sucks
29+
metricRegistry.registerGauge(name(NHttpClientConnectionManager.class, name, "max-connections"),
30+
() -> getTotalStats().getMax());
31+
// this acquires a lock on the connection pool; remove if contention sucks
32+
metricRegistry.registerGauge(name(NHttpClientConnectionManager.class, name, "pending-connections"),
33+
() -> getTotalStats().getPending());
4334
}
4435

4536
}

metrics-httpclient/src/main/java/com/codahale/metrics/httpclient/InstrumentedHttpClientConnectionManager.java

+12-21
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.codahale.metrics.httpclient;
22

3-
import com.codahale.metrics.Gauge;
43
import com.codahale.metrics.MetricRegistry;
54
import org.apache.http.config.Registry;
65
import org.apache.http.config.RegistryBuilder;
@@ -104,26 +103,18 @@ public InstrumentedHttpClientConnectionManager(MetricRegistry metricsRegistry,
104103
this.metricsRegistry = metricsRegistry;
105104
this.name = name;
106105

107-
metricsRegistry.register(name(HttpClientConnectionManager.class, name, "available-connections"),
108-
(Gauge<Integer>) () -> {
109-
// this acquires a lock on the connection pool; remove if contention sucks
110-
return getTotalStats().getAvailable();
111-
});
112-
metricsRegistry.register(name(HttpClientConnectionManager.class, name, "leased-connections"),
113-
(Gauge<Integer>) () -> {
114-
// this acquires a lock on the connection pool; remove if contention sucks
115-
return getTotalStats().getLeased();
116-
});
117-
metricsRegistry.register(name(HttpClientConnectionManager.class, name, "max-connections"),
118-
(Gauge<Integer>) () -> {
119-
// this acquires a lock on the connection pool; remove if contention sucks
120-
return getTotalStats().getMax();
121-
});
122-
metricsRegistry.register(name(HttpClientConnectionManager.class, name, "pending-connections"),
123-
(Gauge<Integer>) () -> {
124-
// this acquires a lock on the connection pool; remove if contention sucks
125-
return getTotalStats().getPending();
126-
});
106+
// this acquires a lock on the connection pool; remove if contention sucks
107+
metricsRegistry.registerGauge(name(HttpClientConnectionManager.class, name, "available-connections"),
108+
() -> getTotalStats().getAvailable());
109+
// this acquires a lock on the connection pool; remove if contention sucks
110+
metricsRegistry.registerGauge(name(HttpClientConnectionManager.class, name, "leased-connections"),
111+
() -> getTotalStats().getLeased());
112+
// this acquires a lock on the connection pool; remove if contention sucks
113+
metricsRegistry.registerGauge(name(HttpClientConnectionManager.class, name, "max-connections"),
114+
() -> getTotalStats().getMax());
115+
// this acquires a lock on the connection pool; remove if contention sucks
116+
metricsRegistry.registerGauge(name(HttpClientConnectionManager.class, name, "pending-connections"),
117+
() -> getTotalStats().getPending());
127118
}
128119

129120
@Override

metrics-httpclient/src/test/java/com/codahale/metrics/httpclient/InstrumentedHttpClientConnectionManagerTest.java

+9-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
import org.mockito.Mockito;
88

99
import static junit.framework.TestCase.assertTrue;
10+
import static org.assertj.core.api.Assertions.assertThat;
11+
import static org.assertj.core.api.Assertions.entry;
1012
import static org.mockito.ArgumentMatchers.any;
1113

1214

@@ -16,7 +18,12 @@ public class InstrumentedHttpClientConnectionManagerTest {
1618
@Test
1719
public void shouldRemoveGauges() {
1820
final InstrumentedHttpClientConnectionManager instrumentedHttpClientConnectionManager = InstrumentedHttpClientConnectionManager.builder(metricRegistry).build();
19-
Assert.assertEquals(4, metricRegistry.getGauges().size());
21+
assertThat(metricRegistry.getGauges().entrySet().stream()
22+
.map(e -> entry(e.getKey(), e.getValue().getValue())))
23+
.containsOnly(entry("org.apache.http.conn.HttpClientConnectionManager.available-connections", 0),
24+
entry("org.apache.http.conn.HttpClientConnectionManager.leased-connections", 0),
25+
entry("org.apache.http.conn.HttpClientConnectionManager.max-connections", 20),
26+
entry("org.apache.http.conn.HttpClientConnectionManager.pending-connections", 0));
2027

2128
instrumentedHttpClientConnectionManager.close();
2229
Assert.assertEquals(0, metricRegistry.getGauges().size());
@@ -36,7 +43,7 @@ public void configurableViaBuilder() {
3643
.close();
3744

3845
ArgumentCaptor<String> argumentCaptor = ArgumentCaptor.forClass(String.class);
39-
Mockito.verify(registry, Mockito.atLeast(1)).register(argumentCaptor.capture(), any());
46+
Mockito.verify(registry, Mockito.atLeast(1)).registerGauge(argumentCaptor.capture(), any());
4047
assertTrue(argumentCaptor.getValue().contains("some-other-name"));
4148
}
4249
}

0 commit comments

Comments
 (0)