/** * Copyright 2017 VMware, 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> * https://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 io.micrometer.humio; import com.github.tomakehurst.wiremock.WireMockServer; import io.micrometer.core.instrument.FunctionCounter; import io.micrometer.core.instrument.Gauge; import io.micrometer.core.instrument.Measurement; import io.micrometer.core.instrument.Meter; import io.micrometer.core.instrument.MockClock; import io.micrometer.core.instrument.Statistic; import io.micrometer.core.instrument.Tags; import io.micrometer.core.instrument.TimeGauge; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import ru.lanwen.wiremock.ext.WiremockResolver; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import static com.github.tomakehurst.wiremock.client.WireMock.*; import static org.assertj.core.api.Assertions.assertThat; /** * Tests for {@link HumioMeterRegistry}. * * @author Martin Westergaard Lassen * @author Jon Schneider * @author Johnny Lim */ @ExtendWith(WiremockResolver.class) class HumioMeterRegistryTest { private final HumioConfig config = HumioConfig.DEFAULT; private final MockClock clock = new MockClock(); private final HumioMeterRegistry meterRegistry = new HumioMeterRegistry(config, clock); @Test void writeTimer(@WiremockResolver.Wiremock WireMockServer server) { HumioMeterRegistry registry = humioMeterRegistry(server); registry.timer("my.timer", "status", "success"); server.stubFor(any(anyUrl())); registry.publish(); server.verify(postRequestedFor(urlMatching("/api/v1/ingest/humio-structured")) .withRequestBody(equalTo("[{\"events\": [{\"timestamp\":\"1970-01-01T00:00:00.001Z\",\"attributes\":{\"name\":\"my_timer\",\"count\":0,\"sum\":0,\"avg\":0,\"max\":0,\"status\":\"success\"}}]}]"))); } @Test void datasourceTags(@WiremockResolver.Wiremock WireMockServer server) { HumioMeterRegistry registry = humioMeterRegistry(server, "name", "micrometer"); registry.counter("my.counter").increment(); server.stubFor(any(anyUrl())); registry.publish(); server.verify(postRequestedFor(urlMatching("/api/v1/ingest/humio-structured")) .withRequestBody(containing("\"tags\":{\"name\": \"micrometer\"}"))); } @Test void writeGauge() { meterRegistry.gauge("my.gauge", 1d); Gauge gauge = meterRegistry.find("my.gauge").gauge(); assertThat(createBatch().writeGauge(gauge)).isNotNull(); } private HumioMeterRegistry.Batch createBatch() { return meterRegistry.new Batch(clock.wallTime()); } @Test void writeGaugeShouldDropNanValue() { meterRegistry.gauge("my.gauge", Double.NaN); Gauge gauge = meterRegistry.find("my.gauge").gauge(); assertThat(createBatch().writeGauge(gauge)).isNull(); } @Test void writeGaugeShouldDropPositiveInfiniteValue() { meterRegistry.gauge("my.gauge", Double.POSITIVE_INFINITY); Gauge gauge = meterRegistry.find("my.gauge").gauge(); assertThat(createBatch().writeGauge(gauge)).isNull(); } @Test void writeGaugeShouldDropNegativeInfiniteValue() { meterRegistry.gauge("my.gauge", Double.NEGATIVE_INFINITY); Gauge gauge = meterRegistry.find("my.gauge").gauge(); assertThat(createBatch().writeGauge(gauge)).isNull(); } @Test void writeTimeGauge() { AtomicReference<Double> obj = new AtomicReference<>(1d); meterRegistry.more().timeGauge("my.timeGauge", Tags.empty(), obj, TimeUnit.SECONDS, AtomicReference::get); TimeGauge timeGauge = meterRegistry.find("my.timeGauge").timeGauge(); assertThat(createBatch().writeGauge(timeGauge)).isNotNull(); } @Test void writeTimeGaugeShouldDropNanValue() { AtomicReference<Double> obj = new AtomicReference<>(Double.NaN); meterRegistry.more().timeGauge("my.timeGauge", Tags.empty(), obj, TimeUnit.SECONDS, AtomicReference::get); TimeGauge timeGauge = meterRegistry.find("my.timeGauge").timeGauge(); assertThat(createBatch().writeGauge(timeGauge)).isNull(); } @Test void writeTimeGaugeShouldDropPositiveInfiniteValue() { AtomicReference<Double> obj = new AtomicReference<>(Double.POSITIVE_INFINITY); meterRegistry.more().timeGauge("my.timeGauge", Tags.empty(), obj, TimeUnit.SECONDS, AtomicReference::get); TimeGauge timeGauge = meterRegistry.find("my.timeGauge").timeGauge(); assertThat(createBatch().writeGauge(timeGauge)).isNull(); } @Test void writeTimeGaugeShouldDropNegativeInfiniteValue() { AtomicReference<Double> obj = new AtomicReference<>(Double.NEGATIVE_INFINITY); meterRegistry.more().timeGauge("my.timeGauge", Tags.empty(), obj, TimeUnit.SECONDS, AtomicReference::get); TimeGauge timeGauge = meterRegistry.find("my.timeGauge").timeGauge(); assertThat(createBatch().writeGauge(timeGauge)).isNull(); } @Test void writeFunctionCounter() { FunctionCounter counter = FunctionCounter.builder("myCounter", 1d, Number::doubleValue).register(meterRegistry); clock.add(config.step()); assertThat(createBatch().writeFunctionCounter(counter)).isNotNull(); } @Test void writeFunctionCounterShouldDropPositiveInfiniteValue() { FunctionCounter counter = FunctionCounter.builder("myCounter", Double.POSITIVE_INFINITY, Number::doubleValue).register(meterRegistry); clock.add(config.step()); assertThat(createBatch().writeFunctionCounter(counter)).isNull(); } @Test void writeFunctionCounterShouldDropNegativeInfiniteValue() { FunctionCounter counter = FunctionCounter.builder("myCounter", Double.NEGATIVE_INFINITY, Number::doubleValue).register(meterRegistry); clock.add(config.step()); assertThat(createBatch().writeFunctionCounter(counter)).isNull(); } @Test void writeMeterWhenCustomMeterHasOnlyNonFiniteValuesShouldNotBeWritten() { Measurement measurement1 = new Measurement(() -> Double.POSITIVE_INFINITY, Statistic.VALUE); Measurement measurement2 = new Measurement(() -> Double.NEGATIVE_INFINITY, Statistic.VALUE); Measurement measurement3 = new Measurement(() -> Double.NaN, Statistic.VALUE); List<Measurement> measurements = Arrays.asList(measurement1, measurement2, measurement3); Meter meter = Meter.builder("my.meter", Meter.Type.GAUGE, measurements).register(this.meterRegistry); assertThat(createBatch().writeMeter(meter)).isNull(); } @Test void writeMeterWhenCustomMeterHasMixedFiniteAndNonFiniteValuesShouldSkipOnlyNonFiniteValues() { Measurement measurement1 = new Measurement(() -> Double.POSITIVE_INFINITY, Statistic.VALUE); Measurement measurement2 = new Measurement(() -> Double.NEGATIVE_INFINITY, Statistic.VALUE); Measurement measurement3 = new Measurement(() -> Double.NaN, Statistic.VALUE); Measurement measurement4 = new Measurement(() -> 1d, Statistic.VALUE); Measurement measurement5 = new Measurement(() -> 2d, Statistic.VALUE); List<Measurement> measurements = Arrays.asList(measurement1, measurement2, measurement3, measurement4, measurement5); Meter meter = Meter.builder("my.meter", Meter.Type.GAUGE, measurements).register(this.meterRegistry); assertThat(createBatch().writeMeter(meter)) .isEqualTo("{\"timestamp\":\"1970-01-01T00:00:00.001Z\",\"attributes\":{\"name\":\"my_meter\",\"value\":1,\"value\":2}}"); } private HumioMeterRegistry humioMeterRegistry(WireMockServer server, String... tags) { return new HumioMeterRegistry(new HumioConfig() { @Override public String get(String key) { return null; } @Override public String uri() { return server.baseUrl(); } @Override public Map<String, String> tags() { Map<String, String> tagMap = new HashMap<>(); for (int i = 0; i < tags.length; i += 2) { tagMap.put(tags[i], tags[i + 1]); } return tagMap; } }, clock); } }