Skip to content

Commit beea181

Browse files
committed
additional tests for various monitor types
Adds tests for ContentualCounter, ContextualTimer, PeakRateCounter, and MinGauge. The PeakRateCounter and MinGauge are examples of custom meters.
1 parent 00eea64 commit beea181

File tree

3 files changed

+143
-7
lines changed

3 files changed

+143
-7
lines changed

servo-core/src/main/java/com/netflix/servo/DefaultMonitorRegistry.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
/**
2-
* Copyright 2013 Netflix, Inc.
1+
/*
2+
* Copyright 2011-2018 Netflix, Inc.
33
* <p/>
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -118,7 +118,7 @@ private static ObjectNameMapper getObjectNameMapper(Properties props) {
118118

119119
return mapper;
120120
}
121-
121+
122122
private static Properties loadProps() {
123123
String registryClassProp = System.getProperty(REGISTRY_CLASS_PROP);
124124
String registryNameProp = System.getProperty(REGISTRY_NAME_PROP);
@@ -150,6 +150,7 @@ public Collection<Monitor<?>> getRegisteredMonitors() {
150150
*/
151151
@Override
152152
public void register(Monitor<?> monitor) {
153+
SpectatorContext.register(monitor);
153154
registry.register(monitor);
154155
}
155156

@@ -158,6 +159,7 @@ public void register(Monitor<?> monitor) {
158159
*/
159160
@Override
160161
public void unregister(Monitor<?> monitor) {
162+
SpectatorContext.unregister(monitor);
161163
registry.unregister(monitor);
162164
}
163165

servo-core/src/main/java/com/netflix/servo/SpectatorContext.java

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,25 @@
1515
*/
1616
package com.netflix.servo;
1717

18+
import com.netflix.servo.monitor.CompositeMonitor;
19+
import com.netflix.servo.monitor.Monitor;
1820
import com.netflix.servo.monitor.MonitorConfig;
21+
import com.netflix.servo.monitor.SpectatorMonitor;
1922
import com.netflix.spectator.api.Counter;
2023
import com.netflix.spectator.api.DistributionSummary;
2124
import com.netflix.spectator.api.Gauge;
2225
import com.netflix.spectator.api.Id;
26+
import com.netflix.spectator.api.Measurement;
27+
import com.netflix.spectator.api.Meter;
2328
import com.netflix.spectator.api.NoopRegistry;
2429
import com.netflix.spectator.api.Registry;
2530
import com.netflix.spectator.api.Timer;
2631
import com.netflix.spectator.api.patterns.PolledMeter;
32+
import org.slf4j.Logger;
33+
import org.slf4j.LoggerFactory;
2734

35+
import java.util.ArrayList;
36+
import java.util.List;
2837
import java.util.concurrent.Executors;
2938
import java.util.concurrent.ScheduledExecutorService;
3039

@@ -47,6 +56,8 @@ private SpectatorContext() {
4756
}
4857
);
4958

59+
private static final Logger LOGGER = LoggerFactory.getLogger(SpectatorContext.class);
60+
5061
private static volatile Registry registry = new NoopRegistry();
5162

5263
/**
@@ -106,4 +117,65 @@ public static PolledMeter.Builder polledGauge(MonitorConfig config) {
106117
.withId(createId(config))
107118
.scheduleOn(GAUGE_POOL);
108119
}
120+
121+
/** Register a custom monitor. */
122+
public static void register(Monitor<?> monitor) {
123+
PolledMeter.monitorMeter(registry, new ServoMeter(monitor));
124+
}
125+
126+
/** Unregister a custom monitor. */
127+
public static void unregister(Monitor<?> monitor) {
128+
PolledMeter.remove(registry, createId(monitor.getConfig()));
129+
}
130+
131+
private static class ServoMeter implements Meter {
132+
133+
private final Id id;
134+
private final Monitor<?> monitor;
135+
136+
ServoMeter(Monitor<?> monitor) {
137+
this.id = createId(monitor.getConfig());
138+
this.monitor = monitor;
139+
}
140+
141+
@Override public Id id() {
142+
return id;
143+
}
144+
145+
private void addMeasurements(Monitor<?> m, List<Measurement> measurements) {
146+
// Skip any that will report directly
147+
if (!(m instanceof SpectatorMonitor)) {
148+
if (m instanceof CompositeMonitor<?>) {
149+
CompositeMonitor<?> cm = (CompositeMonitor<?>) m;
150+
for (Monitor<?> v : cm.getMonitors()) {
151+
addMeasurements(v, measurements);
152+
}
153+
} else {
154+
try {
155+
Object obj = m.getValue();
156+
if (obj instanceof Number) {
157+
double value = ((Number) obj).doubleValue();
158+
// timestamp will get ignored as the value will get forwarded to a gauge
159+
Measurement v = new Measurement(createId(m.getConfig()), 0L, value);
160+
measurements.add(v);
161+
}
162+
} catch (Throwable t) {
163+
LOGGER.warn("Exception while querying user defined gauge ({}), "
164+
+ "the value will be ignored. The owner of the user defined "
165+
+ "function should fix it to not propagate an exception.", m.getConfig(), t);
166+
}
167+
}
168+
}
169+
}
170+
171+
@Override public Iterable<Measurement> measure() {
172+
List<Measurement> measurements = new ArrayList<>();
173+
addMeasurements(monitor, measurements);
174+
return measurements;
175+
}
176+
177+
@Override public boolean hasExpired() {
178+
return false;
179+
}
180+
}
109181
}

servo-core/src/test/java/com/netflix/servo/monitor/SpectatorIntegrationTest.java

Lines changed: 66 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,15 @@
1515
*/
1616
package com.netflix.servo.monitor;
1717

18+
import com.netflix.servo.DefaultMonitorRegistry;
1819
import com.netflix.servo.SpectatorContext;
1920
import com.netflix.servo.annotations.DataSourceType;
2021
import com.netflix.servo.annotations.Monitor;
2122
import com.netflix.servo.stats.StatsConfig;
23+
import com.netflix.servo.tag.BasicTagList;
24+
import com.netflix.servo.tag.TagList;
2225
import com.netflix.servo.util.Clock;
26+
import com.netflix.servo.util.ManualClock;
2327
import com.netflix.spectator.api.DefaultRegistry;
2428
import com.netflix.spectator.api.Id;
2529
import com.netflix.spectator.api.Registry;
@@ -31,10 +35,6 @@
3135
import java.util.concurrent.TimeUnit;
3236

3337
import static org.testng.Assert.assertEquals;
34-
import static org.testng.Assert.assertFalse;
35-
import static org.testng.Assert.assertNotEquals;
36-
import static org.testng.Assert.assertNotNull;
37-
import static org.testng.Assert.assertTrue;
3838

3939
public class SpectatorIntegrationTest {
4040

@@ -104,6 +104,35 @@ public void testAnnotatedCounter() {
104104
assertEquals(1, registry.counter(id).count());
105105
}
106106

107+
@Test
108+
public void testContextualCounter() {
109+
TagList context = BasicTagList.of("a", "1");
110+
ContextualCounter c = new ContextualCounter(CONFIG, () -> context, BasicCounter::new);
111+
c.increment();
112+
Id id = ID.withTag("a", "1");
113+
assertEquals(1, registry.counter(id).count());
114+
}
115+
116+
@Test
117+
public void testPeakRateCounter() {
118+
PeakRateCounter c = new PeakRateCounter(CONFIG);
119+
DefaultMonitorRegistry.getInstance().register(c);
120+
c.increment();
121+
PolledMeter.update(registry);
122+
registry.stream().forEach(m -> System.out.println(m.id()));
123+
assertEquals(1.0, registry.gauge(ID.withTag("type", "GAUGE")).value());
124+
}
125+
126+
@Test
127+
public void testPeakRateCounterRemove() {
128+
PeakRateCounter c = new PeakRateCounter(CONFIG);
129+
DefaultMonitorRegistry.getInstance().register(c);
130+
DefaultMonitorRegistry.getInstance().unregister(c);
131+
c.increment();
132+
PolledMeter.update(registry);
133+
assertEquals(0, registry.stream().count());
134+
}
135+
107136
@Test
108137
public void testDoubleGauge() {
109138
DoubleGauge c = new DoubleGauge(CONFIG);
@@ -151,6 +180,27 @@ public void testDoubleMaxGauge() {
151180
assertEquals(42.0, registry.maxGauge(ID).value(), 1e-12);
152181
}
153182

183+
@Test
184+
public void testMinGauge() {
185+
ManualClock clock = new ManualClock(0);
186+
MinGauge g = new MinGauge(CONFIG, clock);
187+
DefaultMonitorRegistry.getInstance().register(g);
188+
g.update(42);
189+
clock.set(60000);
190+
PolledMeter.update(registry);
191+
assertEquals(42.0, registry.gauge(ID.withTag("type", "GAUGE")).value());
192+
}
193+
194+
@Test
195+
public void testMinGaugeRemove() {
196+
MinGauge g = new MinGauge(CONFIG);
197+
DefaultMonitorRegistry.getInstance().register(g);
198+
DefaultMonitorRegistry.getInstance().unregister(g);
199+
g.update(42);
200+
PolledMeter.update(registry);
201+
assertEquals(0, registry.stream().count());
202+
}
203+
154204
@Test
155205
public void testBasicDistributionSummaryRecord() {
156206
BasicDistributionSummary d = new BasicDistributionSummary(CONFIG);
@@ -227,6 +277,18 @@ public void testStatsTimerRecordMillis() {
227277
assertEquals(42.0, registry.gauge(id.withTag("statistic", "avg")).value(), 1e-12);
228278
}
229279

280+
@Test
281+
public void testContextualTimerRecordMillis() {
282+
TagList context = BasicTagList.of("a", "1");
283+
ContextualTimer d = new ContextualTimer(CONFIG, () -> context, BasicTimer::new);
284+
d.record(42, TimeUnit.NANOSECONDS);
285+
Id id = ID.withTag("unit", "MILLISECONDS").withTag("a", "1");
286+
assertEquals(1, registry.counter(id.withTag(Statistic.count)).count());
287+
assertEquals(42e-6, registry.counter(id.withTag(Statistic.totalTime)).actualCount(), 1e-12);
288+
assertEquals(42e-6 * 42e-6, registry.counter(id.withTag(Statistic.totalOfSquares)).actualCount(), 1e-12);
289+
assertEquals(42e-6, registry.maxGauge(id.withTag(Statistic.max)).value(), 1e-12);
290+
}
291+
230292
public static class AnnotateExample {
231293

232294
private long count = 0;

0 commit comments

Comments
 (0)