package io.dropwizard.metrics;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.CharBuffer;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
public class CsvReporterTest {
@Rule public final TemporaryFolder folder = new TemporaryFolder();
private final MetricRegistry registry = mock(MetricRegistry.class);
private final Clock clock = mock(Clock.class);
private File dataDirectory;
private CsvReporter reporter;
private Map<String,String> testTags;
@Before
public void setUp() throws Exception {
when(clock.getTime()).thenReturn(19910191000L);
this.dataDirectory = folder.newFolder();
this.reporter = CsvReporter.forRegistry(registry)
.formatFor(Locale.US)
.convertRatesTo(TimeUnit.SECONDS)
.convertDurationsTo(TimeUnit.MILLISECONDS)
.withClock(clock)
.filter(MetricFilter.ALL)
.build(dataDirectory);
this.testTags = new HashMap<>();
this.testTags.put("t1", "tv1");
this.testTags.put("k2", "k3");
}
@Test
public void reportsGaugeValues() throws Exception {
final Gauge gauge = mock(Gauge.class);
when(gauge.getValue()).thenReturn(1);
reporter.report(map("gauge", testTags, gauge),
this.<Counter>map(),
this.<Histogram>map(),
this.<Meter>map(),
this.<Timer>map());
assertThat(fileContents("gauge.k2.k3.t1.tv1.csv"))
.isEqualTo(csv(
"t,value",
"19910191,1"
));
}
@Test
public void reportsCounterValues() throws Exception {
final Counter counter = mock(Counter.class);
when(counter.getCount()).thenReturn(100L);
reporter.report(this.<Gauge>map(),
map("test.counter", testTags, counter),
this.<Histogram>map(),
this.<Meter>map(),
this.<Timer>map());
assertThat(fileContents("test.counter.k2.k3.t1.tv1.csv"))
.isEqualTo(csv(
"t,count",
"19910191,100"
));
}
@Test
public void reportsHistogramValues() 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(),
map("test.histogram", testTags, histogram),
this.<Meter>map(),
this.<Timer>map());
assertThat(fileContents("test.histogram.k2.k3.t1.tv1.csv"))
.isEqualTo(csv(
"t,count,max,mean,min,stddev,p50,p75,p95,p98,p99,p999",
"19910191,1,2,3.000000,4,5.000000,6.000000,7.000000,8.000000,9.000000,10.000000,11.000000"
));
}
@Test
public void reportsMeterValues() throws Exception {
final Meter meter = mock(Meter.class);
when(meter.getCount()).thenReturn(1L);
when(meter.getMeanRate()).thenReturn(2.0);
when(meter.getOneMinuteRate()).thenReturn(3.0);
when(meter.getFiveMinuteRate()).thenReturn(4.0);
when(meter.getFifteenMinuteRate()).thenReturn(5.0);
reporter.report(this.<Gauge>map(),
this.<Counter>map(),
this.<Histogram>map(),
map("test.meter",testTags, meter),
this.<Timer>map());
assertThat(fileContents("test.meter.k2.k3.t1.tv1.csv"))
.isEqualTo(csv(
"t,count,mean_rate,m1_rate,m5_rate,m15_rate,rate_unit",
"19910191,1,2.000000,3.000000,4.000000,5.000000,events/second"
));
}
@Test
public void reportsTimerValues() 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("test.another.timer", testTags, timer));
assertThat(fileContents("test.another.timer.k2.k3.t1.tv1.csv"))
.isEqualTo(csv(
"t,count,max,mean,min,stddev,p50,p75,p95,p98,p99,p999,mean_rate,m1_rate,m5_rate,m15_rate,rate_unit,duration_unit",
"19910191,1,100.000000,200.000000,300.000000,400.000000,500.000000,600.000000,700.000000,800.000000,900.000000,1000.000000,2.000000,3.000000,4.000000,5.000000,calls/second,milliseconds"
));
}
@Test
public void testCsvFileProviderIsUsed() {
CsvFileProvider fileProvider = mock(CsvFileProvider.class);
when(fileProvider.getFile(dataDirectory, new MetricName("gauge",testTags))).thenReturn(new File(dataDirectory, "guage.csv"));
CsvReporter reporter = CsvReporter.forRegistry(registry)
.withCsvFileProvider(fileProvider)
.build(dataDirectory);
final Gauge gauge = mock(Gauge.class);
when(gauge.getValue()).thenReturn(1);
reporter.report(map("gauge", testTags, gauge),
this.<Counter>map(),
this.<Histogram>map(),
this.<Meter>map(),
this.<Timer>map());
verify(fileProvider).getFile(dataDirectory, new MetricName("gauge",testTags));
}
private String csv(String... lines) {
final StringBuilder builder = new StringBuilder();
for (String line : lines) {
builder.append(line).append(String.format("%n"));
}
return builder.toString();
}
private String fileContents(String filename) throws IOException {
final StringBuilder builder = new StringBuilder();
final FileInputStream input = new FileInputStream(new File(dataDirectory, filename));
try {
final InputStreamReader reader = new InputStreamReader(input);
final BufferedReader bufferedReader = new BufferedReader(reader);
final CharBuffer buf = CharBuffer.allocate(1024);
while (bufferedReader.read(buf) != -1) {
buf.flip();
builder.append(buf);
buf.clear();
}
} finally {
input.close();
}
return builder.toString();
}
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;
}
}