From 52663a6bf5fe54975e27341c20c3ad97703b1a4d Mon Sep 17 00:00:00 2001 From: Tian Baoqiang Date: Mon, 26 Jun 2017 21:44:02 +0800 Subject: [PATCH] BAEL-397: netflix servo intro (#2159) --- metrics/pom.xml | 6 + .../metrics/servo/MetricAnnotationTest.java | 56 +++++ .../metrics/servo/MetricObserverTest.java | 70 ++++++ .../metrics/servo/MetricPollerTest.java | 50 ++++ .../metrics/servo/MetricTestBase.java | 40 ++++ .../metrics/servo/MetricTypeTest.java | 221 ++++++++++++++++++ 6 files changed, 443 insertions(+) create mode 100644 metrics/src/test/java/com/baeldung/metrics/servo/MetricAnnotationTest.java create mode 100644 metrics/src/test/java/com/baeldung/metrics/servo/MetricObserverTest.java create mode 100644 metrics/src/test/java/com/baeldung/metrics/servo/MetricPollerTest.java create mode 100644 metrics/src/test/java/com/baeldung/metrics/servo/MetricTestBase.java create mode 100644 metrics/src/test/java/com/baeldung/metrics/servo/MetricTypeTest.java diff --git a/metrics/pom.xml b/metrics/pom.xml index 1053c66ff5..794c53b157 100644 --- a/metrics/pom.xml +++ b/metrics/pom.xml @@ -15,6 +15,7 @@ 3.1.2 3.1.0 + 0.12.16 @@ -43,6 +44,11 @@ javax.servlet-api ${dep.ver.servlet} + + com.netflix.servo + servo-core + ${netflix.servo.ver} + diff --git a/metrics/src/test/java/com/baeldung/metrics/servo/MetricAnnotationTest.java b/metrics/src/test/java/com/baeldung/metrics/servo/MetricAnnotationTest.java new file mode 100644 index 0000000000..3d6a73912f --- /dev/null +++ b/metrics/src/test/java/com/baeldung/metrics/servo/MetricAnnotationTest.java @@ -0,0 +1,56 @@ +package com.baeldung.metrics.servo; + +import com.netflix.servo.Metric; +import com.netflix.servo.annotations.DataSourceType; +import com.netflix.servo.annotations.Monitor; +import com.netflix.servo.annotations.MonitorTags; +import com.netflix.servo.monitor.Monitors; +import com.netflix.servo.tag.BasicTag; +import com.netflix.servo.tag.BasicTagList; +import com.netflix.servo.tag.TagList; +import org.junit.Test; + +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +import static com.google.common.collect.Lists.newArrayList; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.hamcrest.CoreMatchers.hasItem; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +/** + * @author aiet + */ +public class MetricAnnotationTest extends MetricTestBase { + + @Monitor(name = "integerCounter", type = DataSourceType.COUNTER, description = "Total number of update operations.") + private final AtomicInteger updateCount = new AtomicInteger(0); + + @MonitorTags private TagList tags = new BasicTagList(newArrayList(new BasicTag("tag-key", "tag-value"))); + + @Test + public void givenAnnotatedMonitor_whenUpdated_thenDataCollected() throws Exception { + Monitors.registerObject("testObject", this); + assertTrue(Monitors.isObjectRegistered("testObject", this)); + + updateCount.incrementAndGet(); + updateCount.incrementAndGet(); + SECONDS.sleep(1); + + List> metrics = observer.getObservations(); + System.out.println(metrics); + assertThat(metrics, hasSize(greaterThanOrEqualTo(1))); + + Iterator> metricIterator = metrics.iterator(); + //skip first empty observation + metricIterator.next(); + while (metricIterator.hasNext()) { + assertThat(metricIterator.next(), hasItem(hasProperty("config", hasProperty("name", is("integerCounter"))))); + } + + } +} diff --git a/metrics/src/test/java/com/baeldung/metrics/servo/MetricObserverTest.java b/metrics/src/test/java/com/baeldung/metrics/servo/MetricObserverTest.java new file mode 100644 index 0000000000..14d3c2646f --- /dev/null +++ b/metrics/src/test/java/com/baeldung/metrics/servo/MetricObserverTest.java @@ -0,0 +1,70 @@ +package com.baeldung.metrics.servo; + +import com.netflix.servo.DefaultMonitorRegistry; +import com.netflix.servo.Metric; +import com.netflix.servo.monitor.BasicGauge; +import com.netflix.servo.monitor.DynamicCounter; +import com.netflix.servo.monitor.Gauge; +import com.netflix.servo.monitor.MonitorConfig; +import org.junit.Test; + +import java.util.Iterator; +import java.util.List; + +import static com.netflix.servo.annotations.DataSourceType.GAUGE; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; + +/** + * @author aiet + */ +public class MetricObserverTest extends MetricTestBase { + + @Test + public void givenMetrics_whenRegister_thenMonitored() throws InterruptedException { + Gauge gauge = new BasicGauge<>(MonitorConfig + .builder("test") + .build(), () -> 2.32); + assertEquals(2.32, gauge.getValue(), 0.01); + + DefaultMonitorRegistry + .getInstance() + .register(gauge); + + for (int i = 0; i < 2; i++) { + SECONDS.sleep(1); + } + + List> metrics = observer.getObservations(); + assertThat(metrics, hasSize(greaterThanOrEqualTo(2))); + + Iterator> metricIterator = metrics.iterator(); + //skip first empty observation + metricIterator.next(); + while (metricIterator.hasNext()) { + assertThat(metricIterator.next(), hasItem(allOf(hasProperty("config", hasProperty("tags", hasItem(GAUGE))), hasProperty("value", is(2.32))))); + } + + } + + @Test + public void givenMetrics_whenRegisterDynamically_thenMonitored() throws Exception { + for (int i = 0; i < 2; i++) { + DynamicCounter.increment("monitor-name", "tag-key", "tag-value"); + SECONDS.sleep(1); + } + + List> metrics = observer.getObservations(); + assertThat(metrics, hasSize(greaterThanOrEqualTo(2))); + + Iterator> metricIterator = metrics.iterator(); + //skip first empty observation + metricIterator.next(); + while (metricIterator.hasNext()) { + assertThat(metricIterator.next(), hasItem(hasProperty("value", greaterThanOrEqualTo(1.0)))); + } + } + +} diff --git a/metrics/src/test/java/com/baeldung/metrics/servo/MetricPollerTest.java b/metrics/src/test/java/com/baeldung/metrics/servo/MetricPollerTest.java new file mode 100644 index 0000000000..4a9a77efde --- /dev/null +++ b/metrics/src/test/java/com/baeldung/metrics/servo/MetricPollerTest.java @@ -0,0 +1,50 @@ +package com.baeldung.metrics.servo; + +import com.netflix.servo.Metric; +import com.netflix.servo.publish.*; +import org.junit.Test; + +import java.util.List; + +import static java.util.concurrent.TimeUnit.SECONDS; +import static java.util.stream.Collectors.toList; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertThat; + +/** + * @author aiet + */ +public class MetricPollerTest { + + @Test + public void givenJvmPoller_whenMonitor_thenDataCollected() throws Exception { + MemoryMetricObserver observer = new MemoryMetricObserver(); + PollRunnable pollRunnable = new PollRunnable(new JvmMetricPoller(), new BasicMetricFilter(true), observer); + PollScheduler + .getInstance() + .start(); + PollScheduler + .getInstance() + .addPoller(pollRunnable, 1, SECONDS); + + SECONDS.sleep(1); + + PollScheduler + .getInstance() + .stop(); + List> metrics = observer.getObservations(); + assertThat(metrics, hasSize(greaterThanOrEqualTo(1))); + + List args = metrics + .stream() + .filter(m -> !m.isEmpty()) + .flatMap(ms -> ms + .stream() + .map(m -> m + .getConfig() + .getName())) + .collect(toList()); + assertThat(args, hasItems("loadedClassCount", "initUsage", "maxUsage", "threadCount")); + } + +} diff --git a/metrics/src/test/java/com/baeldung/metrics/servo/MetricTestBase.java b/metrics/src/test/java/com/baeldung/metrics/servo/MetricTestBase.java new file mode 100644 index 0000000000..86a9d201e8 --- /dev/null +++ b/metrics/src/test/java/com/baeldung/metrics/servo/MetricTestBase.java @@ -0,0 +1,40 @@ +package com.baeldung.metrics.servo; + +import com.netflix.servo.publish.*; +import org.junit.After; +import org.junit.Before; + +import static java.util.concurrent.TimeUnit.SECONDS; + +/** + * @author aiet + */ +abstract class MetricTestBase { + + MemoryMetricObserver observer; + + @Before + public void prepareScheduler() { + System.setProperty("servo.pollers", "1000"); + observer = new MemoryMetricObserver(); + PollScheduler + .getInstance() + .start(); + MetricFilter metricFilter = new BasicMetricFilter(true); + PollRunnable task = new PollRunnable(new MonitorRegistryMetricPoller(), metricFilter, observer); + PollScheduler + .getInstance() + .addPoller(task, 1, SECONDS); + } + + @After + public void stopScheduler() { + if (PollScheduler + .getInstance() + .isStarted()) { + PollScheduler + .getInstance() + .stop(); + } + } +} diff --git a/metrics/src/test/java/com/baeldung/metrics/servo/MetricTypeTest.java b/metrics/src/test/java/com/baeldung/metrics/servo/MetricTypeTest.java new file mode 100644 index 0000000000..9f7b6bb6f3 --- /dev/null +++ b/metrics/src/test/java/com/baeldung/metrics/servo/MetricTypeTest.java @@ -0,0 +1,221 @@ +package com.baeldung.metrics.servo; + +import com.netflix.servo.monitor.*; +import com.netflix.servo.stats.StatsConfig; +import org.junit.Ignore; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; + +/** + * Unit test for simple App. + */ +public class MetricTypeTest { + + @Test + public void givenDefaultCounter_whenManipulate_thenCountValid() { + Counter counter = Monitors.newCounter("test"); + assertEquals("counter should start with 0", 0, counter + .getValue() + .intValue()); + counter.increment(); + assertEquals("counter should have increased by 1", 1, counter + .getValue() + .intValue()); + counter.increment(-1); + assertEquals("counter should have decreased by 1", 0, counter + .getValue() + .intValue()); + } + + @Test + public void givenBasicCounter_whenManipulate_thenCountValid() { + Counter counter = new BasicCounter(MonitorConfig + .builder("test") + .build()); + assertEquals("counter should start with 0", 0, counter + .getValue() + .intValue()); + counter.increment(); + assertEquals("counter should have increased by 1", 1, counter + .getValue() + .intValue()); + counter.increment(-1); + assertEquals("counter should have decreased by 1", 0, counter + .getValue() + .intValue()); + } + + @Ignore + @Test + public void givenStepCounter_whenManipulate_thenRateValid() throws Exception { + System.setProperty("servo.pollers", "1000"); + Counter counter = new StepCounter(MonitorConfig + .builder("test") + .build()); + assertEquals("counter should start with rate 0.0", 0.0, counter.getValue()); + + counter.increment(); + SECONDS.sleep(1); + + assertEquals("counter rate should have increased to 1.0", 1.0, counter.getValue()); + } + + @Test + public void givenPeakRateCounter_whenManipulate_thenPeakRateReturn() throws Exception { + Counter counter = new PeakRateCounter(MonitorConfig + .builder("test") + .build()); + assertEquals("counter should start with 0", 0, counter + .getValue() + .intValue()); + + counter.increment(); + SECONDS.sleep(1); + counter.increment(); + counter.increment(); + + assertEquals("peak rate should have be 2", 2, counter + .getValue() + .intValue()); + } + + @Test + public void givenTimer_whenExecuteTask_thenTimerUpdated() throws Exception { + BasicTimer timer = new BasicTimer(MonitorConfig + .builder("test") + .build(), SECONDS); + + Stopwatch stopwatch = timer.start(); + SECONDS.sleep(1); + timer.record(2, SECONDS); + stopwatch.stop(); + + assertEquals("timer should count 1 second", 1, timer + .getValue() + .intValue()); + assertEquals("timer should count 3 seconds in total", 3.0, timer.getTotalTime(), 0.01); + assertEquals("timer should record 2 updates", 2, timer + .getCount() + .intValue()); + + assertEquals("timer should have max 2", 2, timer.getMax(), 0.01); + } + + @Test + public void givenBucketTimer_whenRecord_thenStatsCalculated() throws Exception { + BucketTimer timer = new BucketTimer(MonitorConfig + .builder("test") + .build(), new BucketConfig.Builder() + .withBuckets(new long[] { 2L, 5L }) + .withTimeUnit(SECONDS) + .build(), SECONDS); + timer.record(3); + timer.record(6); + + assertEquals("timer should count 9 seconds in total", 9, timer + .getTotalTime() + .intValue()); + + final Map metricMap = new HashMap<>(3); + timer + .getMonitors() + .stream() + .filter(monitor -> monitor + .getConfig() + .getTags() + .containsKey("servo.bucket")) + .forEach(monitor -> metricMap.put(getMonitorTagValue(monitor, "servo.bucket"), (Long) monitor.getValue())); + + assertThat(metricMap, allOf(hasEntry("bucket=2s", 0L), hasEntry("bucket=5s", 1L), hasEntry("bucket=overflow", 1L))); + } + + private static String getMonitorTagValue(Monitor monitor, String tagKey) { + return monitor + .getConfig() + .getTags() + .getTag(tagKey) + .getValue(); + } + + @Test + public void givenStatsTimer_whenExecuteTask_thenStatsCalculated() throws Exception { + System.setProperty("netflix.servo", "1000"); + StatsTimer timer = new StatsTimer(MonitorConfig + .builder("test") + .build(), new StatsConfig.Builder() + .withComputeFrequencyMillis(2000) + .withPercentiles(new double[] { 99.0, 95.0, 90.0 }) + .withPublishMax(true) + .withPublishMin(true) + .withPublishCount(true) + .withPublishMean(true) + .withPublishStdDev(true) + .withPublishVariance(true) + .build(), SECONDS); + + Stopwatch stopwatch = timer.start(); + SECONDS.sleep(1); + timer.record(3, SECONDS); + stopwatch.stop(); + + stopwatch = timer.start(); + timer.record(6, SECONDS); + SECONDS.sleep(2); + stopwatch.stop(); + + assertEquals("timer should count 12 seconds in total", 12, timer.getTotalTime()); + assertEquals("timer should count 12 seconds in total", 12, timer.getTotalMeasurement()); + assertEquals("timer should record 4 updates", 4, timer.getCount()); + assertEquals("stats timer value time-cost/update should be 2", 3, timer + .getValue() + .intValue()); + + final Map metricMap = new HashMap<>(10); + timer + .getMonitors() + .forEach(monitor -> metricMap.put(getMonitorTagValue(monitor, "statistic"), (Number) monitor.getValue())); + + assertThat(metricMap.keySet(), containsInAnyOrder("count", "totalTime", "max", "min", "variance", "stdDev", "avg", "percentile_99", "percentile_95", "percentile_90")); + } + + @Test + public void givenGauge_whenCall_thenValueReturned() { + Gauge gauge = new BasicGauge<>(MonitorConfig + .builder("test") + .build(), () -> 2.32); + assertEquals(2.32, gauge.getValue(), 0.01); + } + + @Test + public void givenMaxGauge_whenUpdateMultipleTimes_thenMaxReturned() { + MaxGauge gauge = new MaxGauge(MonitorConfig + .builder("test") + .build()); + assertEquals(0, gauge + .getValue() + .intValue()); + + gauge.update(4); + assertEquals(4, gauge.getCurrentValue(0)); + + gauge.update(1); + assertEquals(4, gauge.getCurrentValue(0)); + } + + @Test + public void givenInformationalMonitor_whenRecord_thenInformationCollected() throws Exception { + BasicInformational informational = new BasicInformational(MonitorConfig + .builder("test") + .build()); + informational.setValue("information collected"); + assertEquals("information collected", informational.getValue()); + } + +}