package io.dropwizard.metrics.graphite;
import io.dropwizard.metrics.Clock;
import io.dropwizard.metrics.Counter;
import io.dropwizard.metrics.Gauge;
import io.dropwizard.metrics.Histogram;
import io.dropwizard.metrics.Meter;
import io.dropwizard.metrics.MetricFilter;
import io.dropwizard.metrics.MetricRegistry;
import io.dropwizard.metrics.Snapshot;
import io.dropwizard.metrics.Timer;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InOrder;
import org.python.antlr.PythonParser.test_return;
import io.dropwizard.metrics.*;
import java.io.IOException;
import java.net.UnknownHostException;
import java.util.Collections;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;
import static org.mockito.Mockito.*;
public class GraphiteReporterTest {
private final long timestamp = 1000198;
private final Clock clock = mock(Clock.class);
private final Graphite graphite = mock(Graphite.class);
private final MetricRegistry registry = mock(MetricRegistry.class);
private final Map<String,String> testTags = Collections.singletonMap("t1", "t2");
private final GraphiteReporter reporter = GraphiteReporter.forRegistry(registry)
.withClock(clock)
.prefixedWith("prefix")
.convertRatesTo(TimeUnit.SECONDS)
.convertDurationsTo(TimeUnit.MILLISECONDS)
.filter(MetricFilter.ALL)
.build(graphite);
@Before
public void setUp() throws Exception {
when(clock.getTime()).thenReturn(timestamp * 1000);
}
@Test
public void doesNotReportStringGaugeValues() throws Exception {
reporter.report(map("gauge", testTags, gauge("value")),
this.<Counter>map(),
this.<Histogram>map(),
this.<Meter>map(),
this.<Timer>map());
final InOrder inOrder = inOrder(graphite);
inOrder.verify(graphite).isConnected();
inOrder.verify(graphite).connect();
inOrder.verify(graphite, never()).send("prefix.gauge", "value", timestamp);
inOrder.verify(graphite).flush();
verifyNoMoreInteractions(graphite);
}
@Test
public void reportsByteGaugeValues() throws Exception {
reporter.report(map("gauge", testTags, gauge((byte) 1)),
this.<Counter>map(),
this.<Histogram>map(),
this.<Meter>map(),
this.<Timer>map());
final InOrder inOrder = inOrder(graphite);
inOrder.verify(graphite).isConnected();
inOrder.verify(graphite).connect();
inOrder.verify(graphite).send("prefix.gauge", "1", timestamp);
inOrder.verify(graphite).flush();
verifyNoMoreInteractions(graphite);
}
@Test
public void reportsShortGaugeValues() throws Exception {
reporter.report(map("gauge", testTags, gauge((short) 1)),
this.<Counter>map(),
this.<Histogram>map(),
this.<Meter>map(),
this.<Timer>map());
final InOrder inOrder = inOrder(graphite);
inOrder.verify(graphite).isConnected();
inOrder.verify(graphite).connect();
inOrder.verify(graphite).send("prefix.gauge", "1", timestamp);
inOrder.verify(graphite).flush();
verifyNoMoreInteractions(graphite);
}
@Test
public void reportsIntegerGaugeValues() throws Exception {
reporter.report(map("gauge", testTags, gauge(1)),
this.<Counter>map(),
this.<Histogram>map(),
this.<Meter>map(),
this.<Timer>map());
final InOrder inOrder = inOrder(graphite);
inOrder.verify(graphite).isConnected();
inOrder.verify(graphite).connect();
inOrder.verify(graphite).send("prefix.gauge", "1", timestamp);
inOrder.verify(graphite).flush();
verifyNoMoreInteractions(graphite);
}
@Test
public void reportsLongGaugeValues() throws Exception {
reporter.report(map("gauge", testTags, gauge(1L)),
this.<Counter>map(),
this.<Histogram>map(),
this.<Meter>map(),
this.<Timer>map());
final InOrder inOrder = inOrder(graphite);
inOrder.verify(graphite).isConnected();
inOrder.verify(graphite).connect();
inOrder.verify(graphite).send("prefix.gauge", "1", timestamp);
inOrder.verify(graphite).flush();
verifyNoMoreInteractions(graphite);
}
@Test
public void reportsFloatGaugeValues() throws Exception {
reporter.report(map("gauge", testTags, gauge(1.1f)),
this.<Counter>map(),
this.<Histogram>map(),
this.<Meter>map(),
this.<Timer>map());
final InOrder inOrder = inOrder(graphite);
inOrder.verify(graphite).isConnected();
inOrder.verify(graphite).connect();
inOrder.verify(graphite).send("prefix.gauge", "1.10", timestamp);
inOrder.verify(graphite).flush();
verifyNoMoreInteractions(graphite);
}
@Test
public void reportsDoubleGaugeValues() throws Exception {
reporter.report(map("gauge", testTags, gauge(1.1)),
this.<Counter>map(),
this.<Histogram>map(),
this.<Meter>map(),
this.<Timer>map());
final InOrder inOrder = inOrder(graphite);
inOrder.verify(graphite).isConnected();
inOrder.verify(graphite).connect();
inOrder.verify(graphite).send("prefix.gauge", "1.10", timestamp);
inOrder.verify(graphite).flush();
verifyNoMoreInteractions(graphite);
}
@Test
public void reportsBooleanGaugeValues() throws Exception {
reporter.report(map("gauge", testTags, gauge(true)),
this.<Counter>map(),
this.<Histogram>map(),
this.<Meter>map(),
this.<Timer>map());
reporter.report(map("gauge", testTags, gauge(false)),
this.<Counter>map(),
this.<Histogram>map(),
this.<Meter>map(),
this.<Timer>map());
final InOrder inOrder = inOrder(graphite);
inOrder.verify(graphite).isConnected();
inOrder.verify(graphite).connect();
inOrder.verify(graphite).send("prefix.gauge", "1", timestamp);
inOrder.verify(graphite).flush();
inOrder.verify(graphite).isConnected();
inOrder.verify(graphite).connect();
inOrder.verify(graphite).send("prefix.gauge", "0", timestamp);
inOrder.verify(graphite).flush();
verifyNoMoreInteractions(graphite);
}
@Test
public void reportsCounters() throws Exception {
final Counter counter = mock(Counter.class);
when(counter.getCount()).thenReturn(100L);
reporter.report(this.<Gauge>map(),
this.<Counter>map("counter", testTags, counter),
this.<Histogram>map(),
this.<Meter>map(),
this.<Timer>map());
final InOrder inOrder = inOrder(graphite);
inOrder.verify(graphite).isConnected();
inOrder.verify(graphite).connect();
inOrder.verify(graphite).send("prefix.counter.count", "100", timestamp);
inOrder.verify(graphite).flush();
verifyNoMoreInteractions(graphite);
}
@Test
public void reportsHistograms() throws Exception {
final Histogram histogram = mock(Histogram.class);
when(histogram.getCount()).thenReturn(1L);
final Snapshot snapshot = mock(Snapshot.class);
when(snapshot.getMax()).thenReturn(2L);
when(snapshot.getMean()).thenReturn(3.0);
when(snapshot.getMin()).thenReturn(4L);
when(snapshot.getStdDev()).thenReturn(5.0);
when(snapshot.getMedian()).thenReturn(6.0);
when(snapshot.get75thPercentile()).thenReturn(7.0);
when(snapshot.get95thPercentile()).thenReturn(8.0);
when(snapshot.get98thPercentile()).thenReturn(9.0);
when(snapshot.get99thPercentile()).thenReturn(10.0);
when(snapshot.get999thPercentile()).thenReturn(11.0);
when(histogram.getSnapshot()).thenReturn(snapshot);
reporter.report(this.<Gauge>map(),
this.<Counter>map(),
this.<Histogram>map("histogram", testTags, histogram),
this.<Meter>map(),
this.<Timer>map());
final InOrder inOrder = inOrder(graphite);
inOrder.verify(graphite).isConnected();
inOrder.verify(graphite).connect();
inOrder.verify(graphite).send("prefix.histogram.count", "1", timestamp);
inOrder.verify(graphite).send("prefix.histogram.max", "2", timestamp);
inOrder.verify(graphite).send("prefix.histogram.mean", "3.00", timestamp);
inOrder.verify(graphite).send("prefix.histogram.min", "4", timestamp);
inOrder.verify(graphite).send("prefix.histogram.stddev", "5.00", timestamp);
inOrder.verify(graphite).send("prefix.histogram.p50", "6.00", timestamp);
inOrder.verify(graphite).send("prefix.histogram.p75", "7.00", timestamp);
inOrder.verify(graphite).send("prefix.histogram.p95", "8.00", timestamp);
inOrder.verify(graphite).send("prefix.histogram.p98", "9.00", timestamp);
inOrder.verify(graphite).send("prefix.histogram.p99", "10.00", timestamp);
inOrder.verify(graphite).send("prefix.histogram.p999", "11.00", timestamp);
inOrder.verify(graphite).flush();
verifyNoMoreInteractions(graphite);
}
@Test
public void reportsMeters() throws Exception {
final Meter meter = mock(Meter.class);
when(meter.getCount()).thenReturn(1L);
when(meter.getOneMinuteRate()).thenReturn(2.0);
when(meter.getFiveMinuteRate()).thenReturn(3.0);
when(meter.getFifteenMinuteRate()).thenReturn(4.0);
when(meter.getMeanRate()).thenReturn(5.0);
reporter.report(this.<Gauge>map(),
this.<Counter>map(),
this.<Histogram>map(),
this.<Meter>map("meter", testTags, meter),
this.<Timer>map());
final InOrder inOrder = inOrder(graphite);
inOrder.verify(graphite).isConnected();
inOrder.verify(graphite).connect();
inOrder.verify(graphite).send("prefix.meter.count", "1", timestamp);
inOrder.verify(graphite).send("prefix.meter.m1_rate", "2.00", timestamp);
inOrder.verify(graphite).send("prefix.meter.m5_rate", "3.00", timestamp);
inOrder.verify(graphite).send("prefix.meter.m15_rate", "4.00", timestamp);
inOrder.verify(graphite).send("prefix.meter.mean_rate", "5.00", timestamp);
inOrder.verify(graphite).flush();
verifyNoMoreInteractions(graphite);
}
@Test
public void reportsTimers() throws Exception {
final Timer timer = mock(Timer.class);
when(timer.getCount()).thenReturn(1L);
when(timer.getMeanRate()).thenReturn(2.0);
when(timer.getOneMinuteRate()).thenReturn(3.0);
when(timer.getFiveMinuteRate()).thenReturn(4.0);
when(timer.getFifteenMinuteRate()).thenReturn(5.0);
final Snapshot snapshot = mock(Snapshot.class);
when(snapshot.getMax()).thenReturn(TimeUnit.MILLISECONDS.toNanos(100));
when(snapshot.getMean()).thenReturn((double) TimeUnit.MILLISECONDS.toNanos(200));
when(snapshot.getMin()).thenReturn(TimeUnit.MILLISECONDS.toNanos(300));
when(snapshot.getStdDev()).thenReturn((double) TimeUnit.MILLISECONDS.toNanos(400));
when(snapshot.getMedian()).thenReturn((double) TimeUnit.MILLISECONDS.toNanos(500));
when(snapshot.get75thPercentile()).thenReturn((double) TimeUnit.MILLISECONDS.toNanos(600));
when(snapshot.get95thPercentile()).thenReturn((double) TimeUnit.MILLISECONDS.toNanos(700));
when(snapshot.get98thPercentile()).thenReturn((double) TimeUnit.MILLISECONDS.toNanos(800));
when(snapshot.get99thPercentile()).thenReturn((double) TimeUnit.MILLISECONDS.toNanos(900));
when(snapshot.get999thPercentile()).thenReturn((double) TimeUnit.MILLISECONDS
.toNanos(1000));
when(timer.getSnapshot()).thenReturn(snapshot);
reporter.report(this.<Gauge>map(),
this.<Counter>map(),
this.<Histogram>map(),
this.<Meter>map(),
map("timer", testTags, timer));
final InOrder inOrder = inOrder(graphite);
inOrder.verify(graphite).isConnected();
inOrder.verify(graphite).connect();
inOrder.verify(graphite).send("prefix.timer.max", "100.00", timestamp);
inOrder.verify(graphite).send("prefix.timer.mean", "200.00", timestamp);
inOrder.verify(graphite).send("prefix.timer.min", "300.00", timestamp);
inOrder.verify(graphite).send("prefix.timer.stddev", "400.00", timestamp);
inOrder.verify(graphite).send("prefix.timer.p50", "500.00", timestamp);
inOrder.verify(graphite).send("prefix.timer.p75", "600.00", timestamp);
inOrder.verify(graphite).send("prefix.timer.p95", "700.00", timestamp);
inOrder.verify(graphite).send("prefix.timer.p98", "800.00", timestamp);
inOrder.verify(graphite).send("prefix.timer.p99", "900.00", timestamp);
inOrder.verify(graphite).send("prefix.timer.p999", "1000.00", timestamp);
inOrder.verify(graphite).send("prefix.timer.count", "1", timestamp);
inOrder.verify(graphite).send("prefix.timer.m1_rate", "3.00", timestamp);
inOrder.verify(graphite).send("prefix.timer.m5_rate", "4.00", timestamp);
inOrder.verify(graphite).send("prefix.timer.m15_rate", "5.00", timestamp);
inOrder.verify(graphite).send("prefix.timer.mean_rate", "2.00", timestamp);
inOrder.verify(graphite).flush();
verifyNoMoreInteractions(graphite);
}
@Test
public void closesConnectionIfGraphiteIsUnavailable() throws Exception {
doThrow(new UnknownHostException("UNKNOWN-HOST")).when(graphite).connect();
reporter.report(map("gauge", testTags, gauge(1)),
this.<Counter>map(),
this.<Histogram>map(),
this.<Meter>map(),
this.<Timer>map());
final InOrder inOrder = inOrder(graphite);
inOrder.verify(graphite).isConnected();
inOrder.verify(graphite).connect();
inOrder.verify(graphite).close();
verifyNoMoreInteractions(graphite);
}
@Test
public void closesConnectionIfAnUnexpectedExceptionOccurs() throws Exception {
final Gauge gauge = mock(Gauge.class);
when(gauge.getValue()).thenThrow(new RuntimeException("kaboom"));
reporter.report(map("gauge", testTags, gauge),
this.<Counter>map(),
this.<Histogram>map(),
this.<Meter>map(),
this.<Timer>map());
final InOrder inOrder = inOrder(graphite);
inOrder.verify(graphite).isConnected();
inOrder.verify(graphite).connect();
inOrder.verify(graphite).close();
verifyNoMoreInteractions(graphite);
}
@Test
public void closesConnectionOnReporterStop() throws Exception {
reporter.stop();
verify(graphite).close();
verifyNoMoreInteractions(graphite);
}
@Test
public void testNameFormatterIsUsed() throws IllegalStateException, IOException {
GraphiteReporter formatReporter = GraphiteReporter.forRegistry(registry)
.withClock(clock)
.prefixedWith("prefix")
.convertRatesTo(TimeUnit.SECONDS)
.convertDurationsTo(TimeUnit.MILLISECONDS)
.withMetricNameFormatter(MetricNameFormatter.APPEND_TAG_VALUES)
.filter(MetricFilter.ALL)
.build(graphite);
final Counter counter = mock(Counter.class);
when(counter.getCount()).thenReturn(100L);
formatReporter.report(this.<Gauge>map(),
this.<Counter>map("counter", testTags, counter),
this.<Histogram>map(),
this.<Meter>map(),
this.<Timer>map());
final InOrder inOrder = inOrder(graphite);
inOrder.verify(graphite).isConnected();
inOrder.verify(graphite).connect();
inOrder.verify(graphite).send("prefix.counter.t2.count", "100", timestamp);
inOrder.verify(graphite).flush();
verifyNoMoreInteractions(graphite);
}
private <T> SortedMap<MetricName, T> map() {
return new TreeMap<>();
}
private <T> SortedMap<MetricName, T> map(String name, Map<String,String> tags, T metric) {
final TreeMap<MetricName, T> map = new TreeMap<>();
map.put(new MetricName(name,tags), metric);
return map;
}
private <T> Gauge gauge(T value) {
final Gauge gauge = mock(Gauge.class);
when(gauge.getValue()).thenReturn(value);
return gauge;
}
}