SpectatorIntegrationTest.java
/*
* Copyright 2011-2018 Netflix, Inc.
* <p/>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.netflix.servo.monitor;
import com.netflix.servo.DefaultMonitorRegistry;
import com.netflix.servo.SpectatorContext;
import com.netflix.servo.annotations.DataSourceType;
import com.netflix.servo.annotations.Monitor;
import com.netflix.servo.stats.StatsConfig;
import com.netflix.servo.tag.BasicTagList;
import com.netflix.servo.tag.TagList;
import com.netflix.servo.util.Clock;
import com.netflix.servo.util.ManualClock;
import com.netflix.spectator.api.BasicTag;
import com.netflix.spectator.api.DefaultRegistry;
import com.netflix.spectator.api.Id;
import com.netflix.spectator.api.Registry;
import com.netflix.spectator.api.Statistic;
import com.netflix.spectator.api.Tag;
import com.netflix.spectator.api.patterns.PolledMeter;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import static org.testng.Assert.assertEquals;
public class SpectatorIntegrationTest {
private static final MonitorConfig CONFIG = new MonitorConfig.Builder("test").build();
private static final Id ID = new DefaultRegistry()
.createId(CONFIG.getName())
.withTags(CONFIG.getTags().asMap());
private static final Tag COUNTER = new BasicTag("type", "COUNTER");
private Registry registry;
@BeforeMethod
public void before() {
DefaultMonitorRegistry.getInstance().getRegisteredMonitors().forEach(
m -> DefaultMonitorRegistry.getInstance().unregister(m)
);
registry = new DefaultRegistry();
SpectatorContext.setRegistry(registry);
}
private void register(com.netflix.servo.monitor.Monitor<?> monitor) {
DefaultMonitorRegistry.getInstance().register(monitor);
}
@Test
public void testUnregisteredBasicCounter() {
BasicCounter c = new BasicCounter(CONFIG);
assertEquals(0, registry.counters().count());
}
@Test
public void testUnregisteredBasicCounterIncrement() {
BasicCounter c = new BasicCounter(CONFIG);
c.increment();
assertEquals(1, registry.counters().count());
assertEquals(1, registry.counter("test").count());
}
@Test
public void testUnregisteredBasicTimer() {
BasicTimer t = new BasicTimer(CONFIG);
assertEquals(0, registry.timers().count());
}
@Test
public void testUnregisteredBasicTimerIncrement() {
BasicTimer t = new BasicTimer(CONFIG);
t.record(42, TimeUnit.MILLISECONDS);
Id id = registry.createId("test")
.withTag("unit", "MILLISECONDS");
assertEquals(3, registry.counters().count());
assertEquals(0, registry.timers().count());
assertEquals(1, registry.gauges().count());
assertEquals(0, registry.distributionSummaries().count());
assertEquals(1, registry.counter(id.withTag(Statistic.count)).count());
assertEquals(42, registry.counter(id.withTag(Statistic.totalTime)).count());
assertEquals(42 * 42, registry.counter(id.withTag(Statistic.totalOfSquares)).count());
assertEquals(42.0, registry.maxGauge(id.withTag(Statistic.max)).value());
}
@Test
public void testBasicCounterIncrement() {
BasicCounter c = new BasicCounter(CONFIG);
register(c);
c.increment();
assertEquals(1, registry.counter(ID).count());
}
@Test
public void testBasicCounterIncrementAmount() {
BasicCounter c = new BasicCounter(CONFIG);
register(c);
c.increment(42);
assertEquals(42, registry.counter(ID).count());
}
@Test
public void testStepCounterIncrement() {
StepCounter c = new StepCounter(CONFIG);
register(c);
c.increment();
assertEquals(1, registry.counter(ID).count());
}
@Test
public void testStepCounterIncrementAmount() {
StepCounter c = new StepCounter(CONFIG);
register(c);
c.increment(42);
assertEquals(42, registry.counter(ID).count());
}
@Test
public void testDynamicCounterIncrement() {
DynamicCounter.increment(CONFIG);
assertEquals(1, registry.counter(ID).count());
}
@Test
public void testDoubleCounterAdd() {
DoubleCounter c = new DoubleCounter(CONFIG, Clock.WALL);
register(c);
c.increment(0.2);
assertEquals(0.2, registry.counter(ID).actualCount());
}
@Test
public void testAnnotatedCounter() {
AnnotateExample ex = new AnnotateExample("foo");
PolledMeter.update(registry);
Id id = registry.createId("counter")
.withTag("class", "AnnotateExample")
.withTag("level", "INFO")
.withTag("id", "foo");
assertEquals(1, registry.counter(id).count());
}
@Test
public void testMemberCounter() {
AnnotateExample ex = new AnnotateExample("foo");
ex.update();
Id id = registry.createId("test")
.withTag("class", "AnnotateExample")
.withTag("id", "foo");
assertEquals(1, registry.counter(id).count());
}
@Test
public void testContextualCounter() {
TagList context = BasicTagList.of("a", "1");
ContextualCounter c = new ContextualCounter(CONFIG, () -> context, BasicCounter::new);
c.increment();
Id id = ID.withTag("a", "1");
assertEquals(1, registry.counter(id).count());
}
@Test
public void testContextualMemberCounter() {
ContextualExample c = new ContextualExample("foo");
c.update();
Id id = registry.createId("counter")
.withTag("a", "2")
.withTag("id", "foo")
.withTag("class", "ContextualExample");
assertEquals(1, registry.counter(id).count());
}
@Test
public void testCustomCompositeMemberCounter() {
CustomCompositeExample c = new CustomCompositeExample("foo");
c.update("2");
Id id = registry.createId("test").withTag("c", "2");
assertEquals(1, registry.counter(id).count());
}
@Test
public void testPeakRateCounter() {
PeakRateCounter c = new PeakRateCounter(CONFIG);
DefaultMonitorRegistry.getInstance().register(c);
c.increment();
PolledMeter.update(registry);
assertEquals(1.0, registry.gauge(ID).value());
}
@Test
public void testPeakRateCounterRemove() {
PeakRateCounter c = new PeakRateCounter(CONFIG);
DefaultMonitorRegistry.getInstance().register(c);
DefaultMonitorRegistry.getInstance().unregister(c);
c.increment();
PolledMeter.update(registry);
assertEquals(0, registry.stream().count());
}
@Test
public void testCustomCounter() {
CustomCounter c = new CustomCounter();
register(c);
c.increment();
PolledMeter.update(registry);
assertEquals(1, registry.counter(ID).count());
}
@Test
public void testDoubleGauge() {
DoubleGauge c = new DoubleGauge(CONFIG);
register(c);
c.set(42.0);
assertEquals(42.0, registry.gauge(ID).value(), 1e-12);
}
@Test
public void testNumberGauge() {
Number n = 42.0;
NumberGauge c = new NumberGauge(CONFIG, n);
register(c);
PolledMeter.update(registry);
assertEquals(42.0, registry.gauge(ID).value(), 1e-12);
}
@Test
public void testBasicGauge() {
BasicGauge<Double> c = new BasicGauge<>(CONFIG, () -> 42.0);
register(c);
PolledMeter.update(registry);
assertEquals(42.0, registry.gauge(ID).value(), 1e-12);
}
@Test
public void testAnnotatedGauge() {
AnnotateExample ex = new AnnotateExample("foo");
PolledMeter.update(registry);
Id id = registry.createId("gauge")
.withTag("class", "AnnotateExample")
.withTag("level", "INFO")
.withTag("id", "foo");
assertEquals(42.0, registry.gauge(id).value(), 1e-12);
}
@Test
public void testDynamicGauge() {
DynamicGauge.set(CONFIG, 42.0);
assertEquals(42.0, registry.gauge(ID).value(), 1e-12);
}
@Test
public void testDoubleMaxGauge() {
DoubleGauge c = new DoubleGauge(CONFIG);
register(c);
c.set(42.0);
assertEquals(42.0, registry.maxGauge(ID).value(), 1e-12);
}
@Test
public void testMinGauge() {
ManualClock clock = new ManualClock(0);
MinGauge g = new MinGauge(CONFIG, clock);
DefaultMonitorRegistry.getInstance().register(g);
g.update(42);
clock.set(60000);
PolledMeter.update(registry);
assertEquals(42.0, registry.gauge(ID).value());
}
@Test
public void testMinGaugeRemove() {
MinGauge g = new MinGauge(CONFIG);
DefaultMonitorRegistry.getInstance().register(g);
DefaultMonitorRegistry.getInstance().unregister(g);
g.update(42);
PolledMeter.update(registry);
assertEquals(0, registry.stream().count());
}
@Test
public void testBasicDistributionSummaryRecord() {
BasicDistributionSummary d = new BasicDistributionSummary(CONFIG);
register(d);
d.record(42);
assertEquals(1, registry.counter(ID.withTag(Statistic.count)).count());
assertEquals(42, registry.counter(ID.withTag(Statistic.totalAmount)).count());
assertEquals(42.0, registry.maxGauge(ID.withTag(Statistic.max)).value(), 1e-12);
}
@Test
public void testBasicTimerRecordMillis() {
BasicTimer d = new BasicTimer(CONFIG);
register(d);
d.record(42, TimeUnit.NANOSECONDS);
Id id = ID.withTag("unit", "MILLISECONDS");
assertEquals(1, registry.counter(id.withTag(Statistic.count)).count());
assertEquals(42e-6, registry.counter(id.withTag(Statistic.totalTime)).actualCount(), 1e-12);
assertEquals(42e-6 * 42e-6, registry.counter(id.withTag(Statistic.totalOfSquares)).actualCount(), 1e-12);
assertEquals(42e-6, registry.maxGauge(id.withTag(Statistic.max)).value(), 1e-12);
}
@Test
public void testBasicTimerRecordSeconds() {
BasicTimer d = new BasicTimer(CONFIG, TimeUnit.SECONDS);
register(d);
d.record(42, TimeUnit.NANOSECONDS);
Id id = ID.withTag("unit", "SECONDS");
assertEquals(1, registry.counter(id.withTag(Statistic.count)).count());
assertEquals(42e-9, registry.counter(id.withTag(Statistic.totalTime)).actualCount(), 1e-12);
assertEquals(42e-9 * 42e-9, registry.counter(id.withTag(Statistic.totalOfSquares)).actualCount(), 1e-12);
assertEquals(42e-9, registry.maxGauge(id.withTag(Statistic.max)).value(), 1e-12);
}
@Test
public void testDynamicTimerRecordSeconds() {
DynamicTimer.record(CONFIG, 42);
Id id = ID.withTag("unit", "MILLISECONDS");
assertEquals(1, registry.counter(id.withTag(Statistic.count)).count());
assertEquals(42, registry.counter(id.withTag(Statistic.totalTime)).actualCount(), 1e-12);
assertEquals(42 * 42, registry.counter(id.withTag(Statistic.totalOfSquares)).actualCount(), 1e-12);
assertEquals(42, registry.maxGauge(id.withTag(Statistic.max)).value(), 1e-12);
}
@Test
public void testBucketTimerRecordMillis() {
BucketConfig bc = new BucketConfig.Builder()
.withBuckets(new long[] {10L, 50L})
.withTimeUnit(TimeUnit.MILLISECONDS)
.build();
BucketTimer d = new BucketTimer(CONFIG, bc);
register(d);
d.record(42, TimeUnit.MILLISECONDS);
Id id = ID.withTag("unit", "MILLISECONDS");
assertEquals(1, registry.counter(id.withTag(Statistic.count).withTag("servo.bucket", "bucket=50ms")).count());
assertEquals(42.0, registry.counter(id.withTag(Statistic.totalTime)).actualCount(), 1e-12);
assertEquals(42.0, registry.maxGauge(id.withTag(Statistic.max)).value(), 1e-12);
}
@Test
public void testStatsTimerRecordMillis() {
StatsConfig sc = new StatsConfig.Builder()
.withPercentiles(new double[] {50.0, 95.0})
.withPublishCount(true)
.withPublishMax(true)
.withPublishMean(true)
.withSampleSize(10)
.build();
StatsTimer d = new StatsTimer(CONFIG, sc);
register(d);
d.record(42, TimeUnit.MILLISECONDS);
d.computeStats();
Id id = ID.withTag("unit", "MILLISECONDS");
assertEquals(1, registry.counter(id.withTag(Statistic.count)).count());
assertEquals(42.0, registry.counter(id.withTag(Statistic.totalTime)).actualCount(), 1e-12);
assertEquals(42.0, registry.maxGauge(id.withTag(Statistic.max)).value(), 1e-12);
assertEquals(42.0, registry.gauge(id.withTag("statistic", "percentile_50")).value(), 1e-12);
assertEquals(42.0, registry.gauge(id.withTag("statistic", "percentile_95")).value(), 1e-12);
assertEquals(42.0, registry.gauge(id.withTag("statistic", "avg")).value(), 1e-12);
}
@Test
public void testContextualTimerRecordMillis() {
TagList context = BasicTagList.of("a", "1");
ContextualTimer d = new ContextualTimer(CONFIG, () -> context, BasicTimer::new);
d.record(42, TimeUnit.NANOSECONDS);
Id id = ID.withTag("unit", "MILLISECONDS").withTag("a", "1");
assertEquals(1, registry.counter(id.withTag(Statistic.count)).count());
assertEquals(42e-6, registry.counter(id.withTag(Statistic.totalTime)).actualCount(), 1e-12);
assertEquals(42e-6 * 42e-6, registry.counter(id.withTag(Statistic.totalOfSquares)).actualCount(), 1e-12);
assertEquals(42e-6, registry.maxGauge(id.withTag(Statistic.max)).value(), 1e-12);
}
public static class AnnotateExample {
private long count = 0;
private final BasicCounter c = new BasicCounter(CONFIG);
public AnnotateExample(String id) {
Monitors.registerObject(id, this);
}
public void update() {
c.increment();
}
@Monitor(name = "gauge", type = DataSourceType.GAUGE)
private double gauge() {
return 42.0;
}
@Monitor(name = "counter", type = DataSourceType.COUNTER)
private long counter() {
return count++;
}
}
public static class ContextualExample {
private final TagList context = BasicTagList.of("a", "2");
private final ContextualCounter c = new ContextualCounter(
new MonitorConfig.Builder("counter").build(),
() -> context,
BasicCounter::new
);
private final ContextualTimer t = new ContextualTimer(
new MonitorConfig.Builder("timer").build(),
() -> context,
BasicTimer::new
);
public ContextualExample(String id) {
Monitors.registerObject(id, this);
}
public void update() {
c.increment();
t.record(42, TimeUnit.NANOSECONDS);
}
}
public static class CustomCompositeExample {
private final DynCounter c = new DynCounter(CONFIG);
public CustomCompositeExample(String id) {
Monitors.registerObject(id, this);
}
public void update(String v) {
c.increment(v);
}
}
public static class DynCounter extends AbstractMonitor<Long> implements CompositeMonitor<Long> {
private final Map<String, BasicCounter> counters = new HashMap<>();
private final MonitorConfig baseConfig;
public DynCounter(MonitorConfig baseConfig) {
super(baseConfig);
this.baseConfig = baseConfig;
}
public void increment(String value) {
counters.computeIfAbsent(value, v -> {
MonitorConfig c = baseConfig.withAdditionalTag(new com.netflix.servo.tag.BasicTag("c", v));
return new BasicCounter(c);
}).increment();
}
@Override
public List<com.netflix.servo.monitor.Monitor<?>> getMonitors() {
return new ArrayList<>(counters.values());
}
@Override
public Long getValue(int pollerIndex) {
return 0L;
}
}
public static class CustomCounter implements com.netflix.servo.monitor.Monitor<Long> {
private final MonitorConfig config = CONFIG.withAdditionalTag(DataSourceType.COUNTER);
private long value = 0L;
public void increment() {
++value;
}
@Override public Long getValue() {
return value;
}
@Override public Long getValue(int pollerIndex) {
return value;
}
@Override public MonitorConfig getConfig() {
return config;
}
}
}