package org.stagemonitor.core.metrics.metrics2; import com.codahale.metrics.Clock; import com.codahale.metrics.Counter; import com.codahale.metrics.Gauge; import com.codahale.metrics.Histogram; import com.codahale.metrics.Meter; import com.codahale.metrics.Timer; import org.junit.Before; import org.junit.Test; import org.stagemonitor.core.CorePlugin; import org.stagemonitor.core.util.HttpClient; import java.util.Collections; import java.util.concurrent.TimeUnit; import static java.lang.String.format; import static java.util.Collections.singletonList; import static java.util.Collections.singletonMap; import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.stagemonitor.core.metrics.MetricsReporterTestHelper.counter; import static org.stagemonitor.core.metrics.MetricsReporterTestHelper.gauge; import static org.stagemonitor.core.metrics.MetricsReporterTestHelper.histogram; import static org.stagemonitor.core.metrics.MetricsReporterTestHelper.meter; import static org.stagemonitor.core.metrics.MetricsReporterTestHelper.metricNameMap; import static org.stagemonitor.core.metrics.MetricsReporterTestHelper.timer; import static org.stagemonitor.core.metrics.metrics2.MetricName.name; public class InfluxDbReporterTest { private static final TimeUnit DURATION_UNIT = TimeUnit.MICROSECONDS; private InfluxDbReporter influxDbReporter; private HttpClient httpClient; private long timestamp; @Before public void setUp() throws Exception { httpClient = mock(HttpClient.class); Clock clock = mock(Clock.class); timestamp = System.currentTimeMillis(); when(clock.getTime()).thenReturn(timestamp); final CorePlugin corePlugin = mock(CorePlugin.class); when(corePlugin.getInfluxDbUrl()).thenReturn("http://localhost:8086"); when(corePlugin.getInfluxDbDb()).thenReturn("stm"); influxDbReporter = InfluxDbReporter.forRegistry(new Metric2Registry(), corePlugin) .convertRatesTo(TimeUnit.SECONDS) .convertDurationsTo(DURATION_UNIT) .globalTags(singletonMap("app", "test")) .httpClient(httpClient) .clock(clock) .build(); } @Test public void testReportGauges() throws Exception { influxDbReporter.reportMetrics( metricNameMap(name("cpu_usage").type("user").tag("core", "1").build(), gauge(3)), metricNameMap(Counter.class), metricNameMap(Histogram.class), metricNameMap(Meter.class), metricNameMap(Timer.class)); verify(httpClient).send(eq("POST"), eq("http://localhost:8086/write?precision=ms&db=stm"), eq(singletonList(format("cpu_usage,core=1,type=user,app=test value=3 %d", timestamp)))); } @Test public void testReportNullGauge() throws Exception { influxDbReporter.reportMetrics( metricNameMap(name("cpu_usage").type("user").tag("core", "1").build(), gauge(null)), metricNameMap(Counter.class), metricNameMap(Histogram.class), metricNameMap(Meter.class), metricNameMap(Timer.class)); verify(httpClient).send(eq("POST"), eq("http://localhost:8086/write?precision=ms&db=stm"), eq(Collections.emptyList())); } @Test public void testReportBooleanGauge() throws Exception { influxDbReporter.reportMetrics( metricNameMap(name("gauge").build(), gauge(true)), metricNameMap(Counter.class), metricNameMap(Histogram.class), metricNameMap(Meter.class), metricNameMap(Timer.class)); verify(httpClient).send(eq("POST"), eq("http://localhost:8086/write?precision=ms&db=stm"), eq(singletonList(format("gauge,app=test value_boolean=true %d", timestamp)))); } @Test public void testReportStringGauge() throws Exception { influxDbReporter.reportMetrics( metricNameMap(name("gauge").build(), gauge("foo")), metricNameMap(Counter.class), metricNameMap(Histogram.class), metricNameMap(Meter.class), metricNameMap(Timer.class)); verify(httpClient).send(eq("POST"), eq("http://localhost:8086/write?precision=ms&db=stm"), eq(singletonList(format("gauge,app=test value_string=\"foo\" %d", timestamp)))); } @Test public void testReportGaugesExponent() throws Exception { influxDbReporter.reportMetrics( metricNameMap(name("cpu_usage").type("user").tag("core", "1").build(), gauge(1e-8)), metricNameMap(Counter.class), metricNameMap(Histogram.class), metricNameMap(Meter.class), metricNameMap(Timer.class)); verify(httpClient).send(eq("POST"), eq("http://localhost:8086/write?precision=ms&db=stm"), eq(singletonList(format("cpu_usage,core=1,type=user,app=test value=1.0e-8 %d", timestamp)))); } @Test public void testReportCounters() throws Exception { influxDbReporter.reportMetrics( metricNameMap(Gauge.class), metricNameMap(name("web_sessions").build(), counter(123)), metricNameMap(Histogram.class), metricNameMap(Meter.class), metricNameMap(Timer.class)); verify(httpClient).send(eq("POST"), eq("http://localhost:8086/write?precision=ms&db=stm"), eq(singletonList(format("web_sessions,app=test count=123i %d", timestamp)))); } @Test public void testReportHistograms() throws Exception { influxDbReporter.reportMetrics( metricNameMap(Gauge.class), metricNameMap(Counter.class), metricNameMap(name("histogram").build(), histogram(400)), metricNameMap(Meter.class), metricNameMap(Timer.class)); verify(httpClient).send(eq("POST"), eq("http://localhost:8086/write?precision=ms&db=stm"), eq(singletonList(format("histogram,app=test count=1i,min=400,max=200,mean=400.0,p50=600.0,std=500.0,p25=0.0,p75=700.0,p95=800.0,p98=900.0,p99=1000.0,p999=1100.0 %d", timestamp)))); } @Test public void testReportMeters() throws Exception { influxDbReporter.reportMetrics( metricNameMap(Gauge.class), metricNameMap(Counter.class), metricNameMap(Histogram.class), metricNameMap(name("meter").build(), meter(10)), metricNameMap(Timer.class)); verify(httpClient).send(eq("POST"), eq("http://localhost:8086/write?precision=ms&db=stm"), eq(singletonList(format("meter,app=test count=10i,m1_rate=3.0,m5_rate=4.0,m15_rate=5.0,mean_rate=2.0 %d", timestamp)))); } @Test public void testReportTimers() throws Exception { influxDbReporter.reportMetrics( metricNameMap(Gauge.class), metricNameMap(Counter.class), metricNameMap(Histogram.class), metricNameMap(Meter.class), metricNameMap(name("response_time").build(), timer(400))); verify(httpClient).send(eq("POST"), eq("http://localhost:8086/write?precision=ms&db=stm"), eq(singletonList(format("response_time,app=test count=1i,m1_rate=3.0,m5_rate=4.0,m15_rate=5.0,mean_rate=2.0,min=0.4,max=0.2,mean=0.4,p50=0.6,std=0.5,p25=0.0,p75=0.7000000000000001,p95=0.8,p98=0.9,p99=1.0,p999=1.1 %d", timestamp)))); } @Test public void testGetInfluxDbStringOrderedTags() throws Exception { assertEquals("cpu_usage,core=1,level=user", InfluxDbReporter.getInfluxDbLineProtocolString(name("cpu_usage").tag("level", "user").tag("core", "1").build())); } @Test public void testGetInfluxDbStringWhiteSpace() throws Exception { assertEquals("cpu\\ usage,level=soft\\ irq", InfluxDbReporter.getInfluxDbLineProtocolString(name("cpu usage").tag("level", "soft irq").build())); } @Test public void testGetInfluxDbStringNoTags() throws Exception { assertEquals("cpu_usage", InfluxDbReporter.getInfluxDbLineProtocolString(name("cpu_usage").build())); } @Test public void testGetInfluxDbStringAllEscapingAndQuotingBehavior() throws Exception { assertEquals("\"measurement\\ with\\ quotes\",tag\\ key\\ with\\ spaces=tag\\,value\\,with\"commas\"", InfluxDbReporter.getInfluxDbLineProtocolString(name("\"measurement with quotes\"").tag("tag key with spaces", "tag,value,with\"commas\"").build())); } }