Skip to content

Commit 9b5097d

Browse files
authored
Merge pull request #120 from xenit-eu/master
Release 0.7.1
2 parents 27f9bf1 + 04a71ad commit 9b5097d

File tree

5 files changed

+89
-40
lines changed

5 files changed

+89
-40
lines changed

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ Version template:
2121
-->
2222

2323
# Alfred Telemetry Changelog
24+
25+
## [0.7.1] - 2021-07-12
26+
27+
### Fixed
28+
* Hazelcast cache metrics broken causing, among other things, a broken Prometheus scrape endpoint [#116]
29+
2430
## [0.7.0] - 2021-07-09
2531

2632
### Added

alfred-telemetry-platform/build.gradle

+4-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@ dependencies {
3232

3333
// 'alfresco-enterprise-repository' not transitive because it will try to download a bunch of unreachable artifacts
3434
alfrescoProvided('org.alfresco:alfresco-enterprise-repository') { transitive = false }
35-
alfrescoProvided('com.hazelcast:hazelcast') { transitive = false }
35+
alfrescoProvided('com.hazelcast:hazelcast:2.4') {
36+
force = true
37+
transitive = false
38+
}
3639

3740
implementation("io.micrometer:micrometer-core:${micrometerVersion}") {
3841
exclude group: "org.slf4j", module: "*"

alfred-telemetry-platform/src/main/java/eu/xenit/alfred/telemetry/binder/cache/Hazelcast2CacheMetrics.java

+14-38
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,19 @@
1010
import io.micrometer.core.instrument.binder.cache.CacheMeterBinder;
1111
import io.micrometer.core.instrument.binder.cache.HazelcastCacheMetrics;
1212
import io.micrometer.core.lang.Nullable;
13-
import java.lang.reflect.Method;
1413
import java.util.concurrent.TimeUnit;
1514
import javax.annotation.Nonnull;
16-
import org.slf4j.Logger;
17-
import org.slf4j.LoggerFactory;
1815

1916
/**
2017
* {@link HazelcastCacheMetrics} equivalent which is compatible with Hazelcast 2 (Alfresco 5.x)
2118
*/
2219
public class Hazelcast2CacheMetrics extends CacheMeterBinder {
2320

24-
private static final Logger logger = LoggerFactory.getLogger(Hazelcast2CacheMetrics.class);
21+
static final String METER_CACHE_GETS_LATENCY = "cache.gets.latency";
22+
static final String METER_CACHE_PUTS_LATENCY = "cache.puts.latency";
23+
static final String METER_CACHE_REMOVALS_LATENCY = "cache.removals.latency";
2524

2625
private static final String TAG_OWNERSHIP = "ownership";
27-
private static final String METHOD_GET_OPERATION_STATS = "getOperationStats";
2826

2927
private final IMap<?, ?> cache;
3028

@@ -97,7 +95,7 @@ protected Long evictionCount() {
9795

9896
@Override
9997
protected long putCount() {
100-
return cache.getLocalMapStats().getPutOperationCount();
98+
return cache.getLocalMapStats().getOperationStats().getNumberOfPuts();
10199
}
102100

103101
@Override
@@ -125,8 +123,7 @@ protected void bindImplementationSpecificMetrics(@Nonnull MeterRegistry registry
125123
.register(registry);
126124

127125
FunctionCounter.builder("cache.partition.gets", cache,
128-
cache -> extractMetricWithReflection(cache.getLocalMapStats(), METHOD_GET_OPERATION_STATS,
129-
"getNumberOfGets"))
126+
c -> c.getLocalMapStats().getOperationStats().getNumberOfGets())
130127
.tags(getTagsWithCacheName())
131128
.description("The total number of get operations executed against this partition")
132129
.register(registry);
@@ -136,50 +133,29 @@ protected void bindImplementationSpecificMetrics(@Nonnull MeterRegistry registry
136133
}
137134

138135
private void timings(MeterRegistry registry) {
139-
FunctionTimer.builder("cache.gets.latency", cache,
140-
cache -> extractMetricWithReflection(cache.getLocalMapStats(), METHOD_GET_OPERATION_STATS,
141-
"getNumberOfGets"),
142-
cache -> extractMetricWithReflection(cache.getLocalMapStats(), METHOD_GET_OPERATION_STATS,
143-
"getTotalGetLatency"),
136+
FunctionTimer.builder(METER_CACHE_GETS_LATENCY, cache,
137+
c -> c.getLocalMapStats().getOperationStats().getNumberOfGets(),
138+
c -> c.getLocalMapStats().getOperationStats().getTotalGetLatency(),
144139
TimeUnit.NANOSECONDS)
145140
.tags(getTagsWithCacheName())
146141
.description("Cache gets")
147142
.register(registry);
148143

149-
FunctionTimer.builder("cache.puts.latency", cache,
150-
cache -> extractMetricWithReflection(cache.getLocalMapStats(), METHOD_GET_OPERATION_STATS,
151-
"getNumberOfPuts"),
152-
cache -> extractMetricWithReflection(cache.getLocalMapStats(), METHOD_GET_OPERATION_STATS,
153-
"getTotalPutLatency"),
144+
FunctionTimer.builder(METER_CACHE_PUTS_LATENCY, cache,
145+
c -> c.getLocalMapStats().getOperationStats().getNumberOfPuts(),
146+
c -> c.getLocalMapStats().getOperationStats().getTotalPutLatency(),
154147
TimeUnit.NANOSECONDS)
155148
.tags(getTagsWithCacheName())
156149
.description("Cache puts")
157150
.register(registry);
158151

159-
FunctionTimer.builder("cache.removals.latency", cache,
160-
cache -> extractMetricWithReflection(cache.getLocalMapStats(), METHOD_GET_OPERATION_STATS,
161-
"getNumberOfRemoves"),
162-
cache -> extractMetricWithReflection(cache.getLocalMapStats(), METHOD_GET_OPERATION_STATS,
163-
"getTotalRemoveLatency"),
152+
FunctionTimer.builder(METER_CACHE_REMOVALS_LATENCY, cache,
153+
c -> c.getLocalMapStats().getOperationStats().getNumberOfRemoves(),
154+
c -> c.getLocalMapStats().getOperationStats().getTotalRemoveLatency(),
164155
TimeUnit.NANOSECONDS)
165156
.tags(getTagsWithCacheName())
166157
.description("Cache removals")
167158
.register(registry);
168159
}
169160

170-
public static long extractMetricWithReflection(final Object object, final String... methods) {
171-
try {
172-
Object currentObject = object;
173-
for (String methodToExecute : methods) {
174-
final Method method = currentObject.getClass().getMethod(methodToExecute);
175-
method.setAccessible(true);
176-
currentObject = method.invoke(currentObject);
177-
}
178-
return (long) currentObject;
179-
} catch (Throwable e) {
180-
logger.warn("Unable to extract metric using reflection", e);
181-
return -1;
182-
}
183-
}
184-
185161
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package eu.xenit.alfred.telemetry.binder.cache;
2+
3+
import static eu.xenit.alfred.telemetry.binder.cache.Hazelcast2CacheMetrics.METER_CACHE_GETS_LATENCY;
4+
import static eu.xenit.alfred.telemetry.binder.cache.Hazelcast2CacheMetrics.METER_CACHE_PUTS_LATENCY;
5+
import static eu.xenit.alfred.telemetry.binder.cache.Hazelcast2CacheMetrics.METER_CACHE_REMOVALS_LATENCY;
6+
import static org.awaitility.Awaitility.await;
7+
import static org.hamcrest.MatcherAssert.assertThat;
8+
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
9+
import static org.hamcrest.Matchers.is;
10+
import static org.hamcrest.Matchers.nullValue;
11+
12+
import com.hazelcast.config.Config;
13+
import com.hazelcast.core.Hazelcast;
14+
import com.hazelcast.core.HazelcastInstance;
15+
import com.hazelcast.core.IMap;
16+
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
17+
import java.time.Duration;
18+
import java.util.concurrent.TimeUnit;
19+
import org.hamcrest.Matcher;
20+
import org.junit.jupiter.api.BeforeEach;
21+
import org.junit.jupiter.api.Test;
22+
23+
class Hazelcast2CacheMetricsTest {
24+
25+
private SimpleMeterRegistry meterRegistry;
26+
27+
@BeforeEach
28+
void setup() {
29+
meterRegistry = new SimpleMeterRegistry();
30+
}
31+
32+
@Test
33+
void testCacheMetrics() {
34+
HazelcastInstance hazelcastInstance = Hazelcast.newHazelcastInstance(new Config());
35+
IMap<String, String> cache = hazelcastInstance.getMap(this.getClass().getSimpleName());
36+
37+
Hazelcast2CacheMetrics.monitor(meterRegistry, cache);
38+
cache.put("foo", "bar");
39+
40+
assertThat(cache.get("foo"), is("bar"));
41+
assertThat(cache.get("baz"), is(nullValue()));
42+
43+
assertThat(meterRegistry.get("cache.gets").tag("result", "hit").functionCounter().count(), is(1.0));
44+
await().atMost(Duration.ofSeconds(5))
45+
.until(() -> meterRegistry.get("cache.puts").functionCounter().count(), is(1.0));
46+
47+
validateLatencyMetrics(METER_CACHE_GETS_LATENCY, is(2.0), is(greaterThanOrEqualTo(0.0)));
48+
validateLatencyMetrics(METER_CACHE_PUTS_LATENCY, is(1.0), is(greaterThanOrEqualTo(0.0)));
49+
validateLatencyMetrics(METER_CACHE_REMOVALS_LATENCY, is(0.0), is(0.0));
50+
51+
cache.remove("foo");
52+
validateLatencyMetrics(METER_CACHE_REMOVALS_LATENCY, is(1.0), is(greaterThanOrEqualTo(0.0)));
53+
}
54+
55+
private void validateLatencyMetrics(final String latencyMeterName, Matcher<Double> counterMatcher,
56+
Matcher<Double> totalTimeNanosMatcher) {
57+
await().atMost(Duration.ofSeconds(5))
58+
.until(() -> meterRegistry.get(latencyMeterName).functionTimer().count(), counterMatcher);
59+
await().atMost(Duration.ofSeconds(5))
60+
.until(() -> meterRegistry.get(latencyMeterName).functionTimer().totalTime(TimeUnit.NANOSECONDS),
61+
totalTimeNanosMatcher);
62+
}
63+
64+
}

build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def copyPropertyValueIfExists(sourcePropertyName, targetPropertyName) {
2121

2222
allprojects {
2323
group = 'eu.xenit.alfred.telemetry'
24-
version = '0.7.0'
24+
version = '0.7.1'
2525

2626
boolean isRelease = ci.branch?.startsWith("release")
2727
if (!isRelease) {

0 commit comments

Comments
 (0)