org.hawkular.metrics.dropwizard.HawkularReporterTest.java Source code

Java tutorial

Introduction

Here is the source code for org.hawkular.metrics.dropwizard.HawkularReporterTest.java

Source

/*
 * Copyright 2014-2017 Red Hat, Inc. and/or its affiliates
 * and other contributors as indicated by the @author tags.
 *
 * 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
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * 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 org.hawkular.metrics.dropwizard;

import static java.util.stream.Collectors.toMap;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Pattern;
import java.util.stream.StreamSupport;

import org.apache.commons.lang3.tuple.Pair;
import org.assertj.core.api.iterable.Extractor;
import org.assertj.core.util.Lists;
import org.hawkular.metrics.client.common.http.HawkularHttpClient;
import org.hawkular.metrics.client.common.http.HawkularHttpResponse;
import org.json.JSONArray;
import org.json.JSONObject;
import org.junit.Test;

import com.codahale.metrics.Counter;
import com.codahale.metrics.Gauge;
import com.codahale.metrics.Histogram;
import com.codahale.metrics.Meter;
import com.codahale.metrics.MetricRegistry;

/**
 * @author Joel Takvorian
 */
public class HawkularReporterTest {

    private final MetricRegistry registry = new MetricRegistry();
    private final Extractor<Object, String> idFromRoot = e -> ((JSONObject) e).getString("id");
    private final Extractor<Object, Integer> valueFromDataPoints = e -> ((JSONObject) e).getInt("value");
    private final Extractor<Object, Integer> valueFromRoot = e -> valueFromDataPoints
            .extract(((JSONObject) e).getJSONArray("dataPoints").get(0));
    private final Extractor<Object, Double> dValueFromDataPoints = e -> ((JSONObject) e).getDouble("value");
    private final Extractor<Object, Double> dValueFromRoot = e -> dValueFromDataPoints
            .extract(((JSONObject) e).getJSONArray("dataPoints").get(0));
    private final HttpClientMock client = new HttpClientMock();

    @Test
    public void shouldReportSimpleCounterWithoutTag() {
        HawkularReporter reporter = HawkularReporter.builder(registry, "unit-test").useHttpClient(uri -> client)
                .build();

        final Counter counter = registry.counter("my.counter");
        counter.inc();
        reporter.report();

        assertThat(client.getMetricsRestCalls()).hasSize(1);
        JSONObject metrics = new JSONObject(client.getMetricsRestCalls().get(0));
        assertThat(metrics.keySet()).containsExactly("counters");
        JSONArray json = metrics.getJSONArray("counters");
        assertThat(json).extracting(idFromRoot).containsExactly("my.counter");
        assertThat(json).extracting(valueFromRoot).containsExactly(1);
        assertThat(client.getTagsRestCalls()).isEmpty();
    }

    @Test
    public void shouldReportCountersWithTags() {
        HawkularReporter reporter = HawkularReporter.builder(registry, "unit-test").useHttpClient(uri -> client)
                .globalTags(Collections.singletonMap("global-tag", "abc")).perMetricTags(Collections
                        .singletonMap("my.second.counter", Collections.singletonMap("metric-tag", "def")))
                .build();

        final Counter counter1 = registry.counter("my.first.counter");
        final Counter counter2 = registry.counter("my.second.counter");
        counter1.inc();
        counter2.inc();
        reporter.report();

        assertThat(client.getMetricsRestCalls()).hasSize(1);
        JSONObject metrics = new JSONObject(client.getMetricsRestCalls().get(0));
        assertThat(metrics.keySet()).containsExactly("counters");
        JSONArray json = metrics.getJSONArray("counters");
        assertThat(json).extracting(idFromRoot).containsOnly("my.first.counter", "my.second.counter");
        assertThat(json).extracting(valueFromRoot).containsExactly(1, 1);

        assertThat(client.getTagsRestCalls()).containsOnly(
                Pair.of("/counters/my.first.counter/tags", "{\"global-tag\":\"abc\"}"),
                Pair.of("/counters/my.second.counter/tags", "{\"global-tag\":\"abc\",\"metric-tag\":\"def\"}"));
    }

    @Test
    public void shouldReportHistogram() {
        HawkularReporter reporter = HawkularReporter.builder(registry, "unit-test").useHttpClient(uri -> client)
                .build();

        final Histogram histogram = registry.histogram("my.histogram");
        histogram.update(3);
        histogram.update(8);
        histogram.update(7);
        histogram.update(1);
        histogram.update(8);
        histogram.update(4);
        reporter.report();

        assertThat(client.getMetricsRestCalls()).hasSize(1);
        JSONObject metrics = new JSONObject(client.getMetricsRestCalls().get(0));
        assertThat(metrics.keySet()).containsOnly("counters", "gauges");
        JSONArray countersJson = metrics.getJSONArray("counters");
        assertThat(countersJson).extracting(idFromRoot).containsExactly("my.histogram.count");
        assertThat(countersJson).extracting(valueFromRoot).containsExactly(6);

        JSONArray gaugesJson = metrics.getJSONArray("gauges");
        Map<String, Integer> values = StreamSupport.stream(gaugesJson.spliterator(), false)
                .collect(toMap(idFromRoot::extract, valueFromRoot::extract));
        // Note: we extract int values here for simplicity, but actual values are double. The goal is not to test
        // Dropwizard algorithm for metrics generation, so we don't bother with accuracy.
        assertThat(values).containsOnly(entry("my.histogram.mean", 5), entry("my.histogram.median", 7),
                entry("my.histogram.stddev", 2), entry("my.histogram.75perc", 8), entry("my.histogram.95perc", 8),
                entry("my.histogram.98perc", 8), entry("my.histogram.99perc", 8), entry("my.histogram.999perc", 8));

        assertThat(client.getTagsRestCalls()).containsOnly(
                Pair.of("/counters/my.histogram.count/tags", "{\"histogram\":\"count\"}"),
                Pair.of("/gauges/my.histogram.mean/tags", "{\"histogram\":\"mean\"}"),
                Pair.of("/gauges/my.histogram.min/tags", "{\"histogram\":\"min\"}"),
                Pair.of("/gauges/my.histogram.max/tags", "{\"histogram\":\"max\"}"),
                Pair.of("/gauges/my.histogram.stddev/tags", "{\"histogram\":\"stddev\"}"),
                Pair.of("/gauges/my.histogram.median/tags", "{\"histogram\":\"median\"}"),
                Pair.of("/gauges/my.histogram.75perc/tags", "{\"histogram\":\"75perc\"}"),
                Pair.of("/gauges/my.histogram.95perc/tags", "{\"histogram\":\"95perc\"}"),
                Pair.of("/gauges/my.histogram.98perc/tags", "{\"histogram\":\"98perc\"}"),
                Pair.of("/gauges/my.histogram.99perc/tags", "{\"histogram\":\"99perc\"}"),
                Pair.of("/gauges/my.histogram.999perc/tags", "{\"histogram\":\"999perc\"}"));
    }

    @Test
    public void shouldReportPartialHistogram() {
        HawkularReporter reporter = HawkularReporter.builder(registry, "unit-test")
                .setMetricComposition("my.histogram", Lists.newArrayList("mean", "median", "stddev"))
                .useHttpClient(uri -> client).build();

        final Histogram histogram = registry.histogram("my.histogram");
        histogram.update(3);
        reporter.report();

        assertThat(client.getMetricsRestCalls()).hasSize(1);
        JSONObject metrics = new JSONObject(client.getMetricsRestCalls().get(0));
        assertThat(metrics.keySet()).containsOnly("gauges");

        JSONArray gaugesJson = metrics.getJSONArray("gauges");
        Map<String, Integer> values = StreamSupport.stream(gaugesJson.spliterator(), false)
                .collect(toMap(idFromRoot::extract, valueFromRoot::extract));
        // Note: we extract int values here for simplicity, but actual values are double. The goal is not to test
        // Dropwizard algorithm for metrics generation, so we don't bother with accuracy.
        assertThat(values).containsOnly(entry("my.histogram.mean", 3), entry("my.histogram.median", 3),
                entry("my.histogram.stddev", 0));

        assertThat(client.getTagsRestCalls()).containsOnly(
                Pair.of("/gauges/my.histogram.mean/tags", "{\"histogram\":\"mean\"}"),
                Pair.of("/gauges/my.histogram.stddev/tags", "{\"histogram\":\"stddev\"}"),
                Pair.of("/gauges/my.histogram.median/tags", "{\"histogram\":\"median\"}"));
    }

    @Test
    public void shouldReportPartialMetersWithRegex() {
        HawkularReporter reporter = HawkularReporter.builder(registry, "unit-test").useHttpClient(uri -> client)
                .setRegexMetricComposition(Pattern.compile("meter\\.partial\\..+"),
                        Lists.newArrayList("count", "meanrt"))
                .build();

        final Meter m1 = registry.meter("meter.partial.1");
        final Meter m2 = registry.meter("meter.partial.2");
        final Meter m3 = registry.meter("meter.full.3");
        m1.mark();
        m2.mark();
        m3.mark();
        reporter.report();

        assertThat(client.getMetricsRestCalls()).hasSize(1);
        JSONObject metrics = new JSONObject(client.getMetricsRestCalls().get(0));
        assertThat(metrics.keySet()).containsOnly("counters", "gauges");
        JSONArray counters = metrics.getJSONArray("counters");
        assertThat(counters).extracting(idFromRoot).containsOnly("meter.partial.1.count", "meter.partial.2.count",
                "meter.full.3.count");
        assertThat(counters).extracting(valueFromRoot).containsExactly(1, 1, 1);

        JSONArray gauges = metrics.getJSONArray("gauges");
        assertThat(gauges).extracting(idFromRoot).containsOnly("meter.partial.1.meanrt", "meter.partial.2.meanrt",
                "meter.full.3.1minrt", "meter.full.3.5minrt", "meter.full.3.15minrt", "meter.full.3.meanrt");
    }

    @Test
    public void shouldCreateRegexTags() {
        HawkularReporter reporter = HawkularReporter.builder(registry, "unit-test").useHttpClient(uri -> client)
                .addRegexTag(Pattern.compile("my\\..*"), "owner", "me")
                .addMetricTag("my.first.counter", "type", "counter").build();

        assertThat(reporter.getTagsForMetrics("my.first.gauge")).containsOnly(entry("owner", "me"));
        assertThat(reporter.getTagsForMetrics("my.first.counter")).containsOnly(entry("owner", "me"),
                entry("type", "counter"));
        assertThat(reporter.getTagsForMetrics("your.first.gauge")).isEmpty();
    }

    @Test
    public void shouldCreateRegexTagsFromString() {
        HawkularReporter reporter = HawkularReporter.builder(registry, "unit-test").useHttpClient(uri -> client)
                .addMetricTag("/my\\..*/", "owner", "me").addMetricTag("my.first.counter", "type", "counter")
                .build();

        assertThat(reporter.getTagsForMetrics("my.first.gauge")).containsOnly(entry("owner", "me"));
        assertThat(reporter.getTagsForMetrics("my.first.counter")).containsOnly(entry("owner", "me"),
                entry("type", "counter"));
        assertThat(reporter.getTagsForMetrics("your.first.gauge")).isEmpty();
    }

    @Test
    public void shouldDefaultBehaviourBeListedLast() {
        HawkularReporter reporter = HawkularReporter.builder(registry, "unit-test").useHttpClient(uri -> client)
                .setMetricComposition("meter.1", Lists.newArrayList("count", "meanrt", "1minrt"))
                .setRegexMetricComposition(Pattern.compile("meter\\.2"),
                        Lists.newArrayList("count", "meanrt", "15minrt"))
                // Here is the default behaviour => every regex beyond this point will be ignored
                .setRegexMetricComposition(Pattern.compile(".*"), Lists.newArrayList("count", "meanrt"))
                .setRegexMetricComposition(Pattern.compile("meter\\.3"),
                        Lists.newArrayList("count", "meanrt", "15minrt"))
                .build();

        Optional<Collection<String>> parts = reporter.getAllowedParts("meter.1");
        assertThat(parts).hasValueSatisfying(col -> assertThat(col).containsOnly("count", "meanrt", "1minrt"));

        parts = reporter.getAllowedParts("meter.2");
        assertThat(parts).hasValueSatisfying(col -> assertThat(col).containsOnly("count", "meanrt", "15minrt"));

        parts = reporter.getAllowedParts("meter.3");
        assertThat(parts).hasValueSatisfying(col -> assertThat(col).containsOnly("count", "meanrt"));
    }

    @Test
    public void shouldReportDoubleGauge() {
        HawkularReporter reporter = HawkularReporter.builder(registry, "unit-test").useHttpClient(uri -> client)
                .build();

        final Gauge<Double> gauge = () -> 1.5d;
        registry.register("gauge.double", gauge);
        reporter.report();

        assertThat(client.getMetricsRestCalls()).hasSize(1);
        JSONObject metrics = new JSONObject(client.getMetricsRestCalls().get(0));
        assertThat(metrics.keySet()).containsOnly("gauges");

        JSONArray gaugesJson = metrics.getJSONArray("gauges");
        Map<String, Double> values = StreamSupport.stream(gaugesJson.spliterator(), false)
                .collect(toMap(idFromRoot::extract, dValueFromRoot::extract));
        assertThat(values).containsOnly(entry("gauge.double", 1.5d));
    }

    @Test
    public void shouldNotFailOnInfinityOrNaNGauge() {
        HawkularReporter reporter = HawkularReporter.builder(registry, "unit-test").useHttpClient(uri -> client)
                .build();

        final Gauge<Double> g1 = () -> Double.POSITIVE_INFINITY;
        final Gauge<Double> g2 = () -> Double.NaN;
        registry.register("gauge.infinity", g1);
        registry.register("gauge.nan", g2);
        reporter.report();

        assertThat(client.getMetricsRestCalls()).hasSize(0);
        // Infinity and NaN are not supported in Hawkular
    }

    @Test
    public void shouldReportBigDecimalGauge() {
        HawkularReporter reporter = HawkularReporter.builder(registry, "unit-test").useHttpClient(uri -> client)
                .build();

        final Gauge<BigDecimal> gauge = () -> new BigDecimal("1.5");
        registry.register("gauge.bigd", gauge);
        reporter.report();

        assertThat(client.getMetricsRestCalls()).hasSize(1);
        JSONObject metrics = new JSONObject(client.getMetricsRestCalls().get(0));
        assertThat(metrics.keySet()).containsOnly("gauges");

        JSONArray gaugesJson = metrics.getJSONArray("gauges");
        Map<String, Double> values = StreamSupport.stream(gaugesJson.spliterator(), false)
                .collect(toMap(idFromRoot::extract, dValueFromRoot::extract));
        assertThat(values).containsOnly(entry("gauge.bigd", 1.5d));
    }

    @Test
    public void shouldReportIntegerGauges() {
        HawkularReporter reporter = HawkularReporter.builder(registry, "unit-test").useHttpClient(uri -> client)
                .build();

        final Gauge<Integer> gauge = () -> 1;
        registry.register("gauge.integer", gauge);
        reporter.report();

        assertThat(client.getMetricsRestCalls()).hasSize(1);
        JSONObject metrics = new JSONObject(client.getMetricsRestCalls().get(0));
        assertThat(metrics.keySet()).containsOnly("gauges");

        JSONArray gaugesJson = metrics.getJSONArray("gauges");
        Map<String, Double> values = StreamSupport.stream(gaugesJson.spliterator(), false)
                .collect(toMap(idFromRoot::extract, dValueFromRoot::extract));
        assertThat(values).containsOnly(entry("gauge.integer", 1d));
    }

    @Test
    public void shouldReportLongGauges() {
        HawkularReporter reporter = HawkularReporter.builder(registry, "unit-test").useHttpClient(uri -> client)
                .build();

        final Gauge<Long> gauge = () -> 101L;
        registry.register("gauge.long", gauge);
        reporter.report();

        assertThat(client.getMetricsRestCalls()).hasSize(1);
        JSONObject metrics = new JSONObject(client.getMetricsRestCalls().get(0));
        assertThat(metrics.keySet()).containsOnly("gauges");

        JSONArray gaugesJson = metrics.getJSONArray("gauges");
        Map<String, Double> values = StreamSupport.stream(gaugesJson.spliterator(), false)
                .collect(toMap(idFromRoot::extract, dValueFromRoot::extract));
        assertThat(values).containsOnly(entry("gauge.long", 101d));
    }

    @Test
    public void shouldReportBigIntegerGauge() {
        HawkularReporter reporter = HawkularReporter.builder(registry, "unit-test").useHttpClient(uri -> client)
                .build();

        final Gauge<BigInteger> gauge = () -> new BigInteger("2");
        registry.register("gauge.bigi", gauge);
        reporter.report();

        assertThat(client.getMetricsRestCalls()).hasSize(1);
        JSONObject metrics = new JSONObject(client.getMetricsRestCalls().get(0));
        assertThat(metrics.keySet()).containsOnly("gauges");

        JSONArray gaugesJson = metrics.getJSONArray("gauges");
        Map<String, Double> values = StreamSupport.stream(gaugesJson.spliterator(), false)
                .collect(toMap(idFromRoot::extract, dValueFromRoot::extract));
        assertThat(values).containsOnly(entry("gauge.bigi", 2d));
    }

    private static class HttpClientMock implements HawkularHttpClient {
        private List<String> metricsRestCalls = new ArrayList<>();
        private List<Pair<String, String>> tagsRestCalls = new ArrayList<>();

        @Override
        public void addHeaders(Map<String, String> headers) {
        }

        @Override
        public HawkularHttpResponse postMetrics(String jsonBody) {
            metricsRestCalls.add(jsonBody);
            return null;
        }

        @Override
        public HawkularHttpResponse putTags(String type, String metricName, String jsonBody) {
            tagsRestCalls.add(Pair.of("/" + type + "/" + metricName + "/tags", jsonBody));
            return null;
        }

        @Override
        public void setFailoverOptions(Optional<Long> failoverCacheDuration,
                Optional<Integer> failoverCacheMaxSize) {
        }

        @Override
        public void manageFailover() {
        }

        List<String> getMetricsRestCalls() {
            return metricsRestCalls;
        }

        List<Pair<String, String>> getTagsRestCalls() {
            return tagsRestCalls;
        }
    }
}