From 5c07b9255e0fd39ecab3c0a64eb16fa2c92b6d36 Mon Sep 17 00:00:00 2001 From: Valerij Fredriksen Date: Mon, 17 Jun 2019 12:01:05 +0200 Subject: MetricReceiver -> Metrics --- .../yahoo/vespa/hosted/dockerapi/DockerImpl.java | 10 +- .../hosted/dockerapi/metrics/MetricReceiver.java | 128 --------------------- .../vespa/hosted/dockerapi/metrics/Metrics.java | 128 +++++++++++++++++++++ .../vespa/hosted/dockerapi/DockerImplTest.java | 6 +- .../dockerapi/metrics/MetricReceiverTest.java | 99 ---------------- .../hosted/dockerapi/metrics/MetricsTest.java | 99 ++++++++++++++++ 6 files changed, 235 insertions(+), 235 deletions(-) delete mode 100644 docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/metrics/MetricReceiver.java create mode 100644 docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/metrics/Metrics.java delete mode 100644 docker-api/src/test/java/com/yahoo/vespa/hosted/dockerapi/metrics/MetricReceiverTest.java create mode 100644 docker-api/src/test/java/com/yahoo/vespa/hosted/dockerapi/metrics/MetricsTest.java (limited to 'docker-api') diff --git a/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/DockerImpl.java b/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/DockerImpl.java index 707961fa3b3..b8714d96ccb 100644 --- a/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/DockerImpl.java +++ b/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/DockerImpl.java @@ -27,7 +27,7 @@ import com.yahoo.vespa.hosted.dockerapi.exception.ContainerNotFoundException; import com.yahoo.vespa.hosted.dockerapi.exception.DockerException; import com.yahoo.vespa.hosted.dockerapi.exception.DockerExecTimeoutException; import com.yahoo.vespa.hosted.dockerapi.metrics.Counter; -import com.yahoo.vespa.hosted.dockerapi.metrics.MetricReceiver; +import com.yahoo.vespa.hosted.dockerapi.metrics.Metrics; import java.io.ByteArrayOutputStream; import java.time.Duration; @@ -58,15 +58,15 @@ public class DockerImpl implements Docker { private final Counter numberOfDockerApiFails; @Inject - public DockerImpl(MetricReceiver metricReceiver) { - this(createDockerClient(), metricReceiver); + public DockerImpl(Metrics metrics) { + this(createDockerClient(), metrics); } - DockerImpl(DockerClient dockerClient, MetricReceiver metricReceiver) { + DockerImpl(DockerClient dockerClient, Metrics metrics) { this.dockerClient = dockerClient; this.dockerImageGC = new DockerImageGarbageCollector(this); - numberOfDockerApiFails = metricReceiver.declareCounter("docker.api_fails"); + numberOfDockerApiFails = metrics.declareCounter("docker.api_fails"); } @Override diff --git a/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/metrics/MetricReceiver.java b/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/metrics/MetricReceiver.java deleted file mode 100644 index 234ccba3859..00000000000 --- a/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/metrics/MetricReceiver.java +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.hosted.dockerapi.metrics; - -import com.google.inject.Inject; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; - -/** - * Stores the latest metric for the given application, name, dimension triplet in memory - * - * @author freva - */ -public class MetricReceiver { - // Application names used - public static final String APPLICATION_HOST = "vespa.host"; - public static final String APPLICATION_NODE = "vespa.node"; - - private final Object monitor = new Object(); - private final Map> metrics = new HashMap<>(); - - @Inject - public MetricReceiver() { } - - /** - * Creates a counter metric under vespa.host application, with no dimensions and default dimension type - * See {@link #declareCounter(String, String, Dimensions, DimensionType)} - */ - public Counter declareCounter(String name) { - return declareCounter(name, Dimensions.NONE); - } - - /** - * Creates a counter metric under vespa.host application, with the given dimensions and default dimension type - * See {@link #declareCounter(String, String, Dimensions, DimensionType)} - */ - public Counter declareCounter(String name, Dimensions dimensions) { - return declareCounter(APPLICATION_HOST, name, dimensions, DimensionType.DEFAULT); - } - - /** Creates a counter metric. This method is idempotent. */ - public Counter declareCounter(String application, String name, Dimensions dimensions, DimensionType type) { - synchronized (monitor) { - return (Counter) getOrCreateApplicationMetrics(application, type) - .computeIfAbsent(dimensions, d -> new HashMap<>()) - .computeIfAbsent(name, n -> new Counter()); - } - } - - /** - * Creates a gauge metric under vespa.host application, with no dimensions and default dimension type - * See {@link #declareGauge(String, String, Dimensions, DimensionType)} - */ - public Gauge declareGauge(String name) { - return declareGauge(name, Dimensions.NONE); - } - - /** - * Creates a gauge metric under vespa.host application, with the given dimensions and default dimension type - * See {@link #declareGauge(String, String, Dimensions, DimensionType)} - */ - public Gauge declareGauge(String name, Dimensions dimensions) { - return declareGauge(APPLICATION_HOST, name, dimensions, DimensionType.DEFAULT); - } - - /** Creates a gauge metric. This method is idempotent */ - public Gauge declareGauge(String application, String name, Dimensions dimensions, DimensionType type) { - synchronized (monitor) { - return (Gauge) getOrCreateApplicationMetrics(application, type) - .computeIfAbsent(dimensions, d -> new HashMap<>()) - .computeIfAbsent(name, n -> new Gauge()); - } - } - - public List getDefaultMetrics() { - return getMetricsByType(DimensionType.DEFAULT); - } - - public List getMetricsByType(DimensionType type) { - synchronized (monitor) { - List dimensionMetrics = new ArrayList<>(); - metrics.getOrDefault(type, Map.of()) - .forEach((application, applicationMetrics) -> applicationMetrics.metricsByDimensions().entrySet().stream() - .map(entry -> new DimensionMetrics(application, entry.getKey(), - entry.getValue().entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, value -> value.getValue().getValue())))) - .forEach(dimensionMetrics::add)); - return dimensionMetrics; - } - } - - public void deleteMetricByDimension(String name, Dimensions dimensionsToRemove, DimensionType type) { - synchronized (monitor) { - Optional.ofNullable(metrics.get(type)) - .map(m -> m.get(name)) - .map(ApplicationMetrics::metricsByDimensions) - .ifPresent(m -> m.remove(dimensionsToRemove)); - } - } - - Map> getOrCreateApplicationMetrics(String application, DimensionType type) { - return metrics.computeIfAbsent(type, m -> new HashMap<>()) - .computeIfAbsent(application, app -> new ApplicationMetrics()) - .metricsByDimensions(); - } - - // "Application" is the monitoring application, not Vespa application - private static class ApplicationMetrics { - private final Map> metricsByDimensions = new LinkedHashMap<>(); - - Map> metricsByDimensions() { - return metricsByDimensions; - } - } - - // Used to distinguish whether metrics have been populated with all tag vaules - public enum DimensionType { - /** Default metrics get added default dimensions set in check config */ - DEFAULT, - - /** Pretagged metrics will only get the dimensions explicitly set when creating the counter/gauge */ - PRETAGGED - } -} diff --git a/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/metrics/Metrics.java b/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/metrics/Metrics.java new file mode 100644 index 00000000000..f9b169f0a93 --- /dev/null +++ b/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/metrics/Metrics.java @@ -0,0 +1,128 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.dockerapi.metrics; + +import com.google.inject.Inject; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * Stores the latest metric for the given application, name, dimension triplet in memory + * + * @author freva + */ +public class Metrics { + // Application names used + public static final String APPLICATION_HOST = "vespa.host"; + public static final String APPLICATION_NODE = "vespa.node"; + + private final Object monitor = new Object(); + private final Map> metrics = new HashMap<>(); + + @Inject + public Metrics() { } + + /** + * Creates a counter metric under vespa.host application, with no dimensions and default dimension type + * See {@link #declareCounter(String, String, Dimensions, DimensionType)} + */ + public Counter declareCounter(String name) { + return declareCounter(name, Dimensions.NONE); + } + + /** + * Creates a counter metric under vespa.host application, with the given dimensions and default dimension type + * See {@link #declareCounter(String, String, Dimensions, DimensionType)} + */ + public Counter declareCounter(String name, Dimensions dimensions) { + return declareCounter(APPLICATION_HOST, name, dimensions, DimensionType.DEFAULT); + } + + /** Creates a counter metric. This method is idempotent. */ + public Counter declareCounter(String application, String name, Dimensions dimensions, DimensionType type) { + synchronized (monitor) { + return (Counter) getOrCreateApplicationMetrics(application, type) + .computeIfAbsent(dimensions, d -> new HashMap<>()) + .computeIfAbsent(name, n -> new Counter()); + } + } + + /** + * Creates a gauge metric under vespa.host application, with no dimensions and default dimension type + * See {@link #declareGauge(String, String, Dimensions, DimensionType)} + */ + public Gauge declareGauge(String name) { + return declareGauge(name, Dimensions.NONE); + } + + /** + * Creates a gauge metric under vespa.host application, with the given dimensions and default dimension type + * See {@link #declareGauge(String, String, Dimensions, DimensionType)} + */ + public Gauge declareGauge(String name, Dimensions dimensions) { + return declareGauge(APPLICATION_HOST, name, dimensions, DimensionType.DEFAULT); + } + + /** Creates a gauge metric. This method is idempotent */ + public Gauge declareGauge(String application, String name, Dimensions dimensions, DimensionType type) { + synchronized (monitor) { + return (Gauge) getOrCreateApplicationMetrics(application, type) + .computeIfAbsent(dimensions, d -> new HashMap<>()) + .computeIfAbsent(name, n -> new Gauge()); + } + } + + public List getDefaultMetrics() { + return getMetricsByType(DimensionType.DEFAULT); + } + + public List getMetricsByType(DimensionType type) { + synchronized (monitor) { + List dimensionMetrics = new ArrayList<>(); + metrics.getOrDefault(type, Map.of()) + .forEach((application, applicationMetrics) -> applicationMetrics.metricsByDimensions().entrySet().stream() + .map(entry -> new DimensionMetrics(application, entry.getKey(), + entry.getValue().entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, value -> value.getValue().getValue())))) + .forEach(dimensionMetrics::add)); + return dimensionMetrics; + } + } + + public void deleteMetricByDimension(String name, Dimensions dimensionsToRemove, DimensionType type) { + synchronized (monitor) { + Optional.ofNullable(metrics.get(type)) + .map(m -> m.get(name)) + .map(ApplicationMetrics::metricsByDimensions) + .ifPresent(m -> m.remove(dimensionsToRemove)); + } + } + + Map> getOrCreateApplicationMetrics(String application, DimensionType type) { + return metrics.computeIfAbsent(type, m -> new HashMap<>()) + .computeIfAbsent(application, app -> new ApplicationMetrics()) + .metricsByDimensions(); + } + + // "Application" is the monitoring application, not Vespa application + private static class ApplicationMetrics { + private final Map> metricsByDimensions = new LinkedHashMap<>(); + + Map> metricsByDimensions() { + return metricsByDimensions; + } + } + + // Used to distinguish whether metrics have been populated with all tag vaules + public enum DimensionType { + /** Default metrics get added default dimensions set in check config */ + DEFAULT, + + /** Pretagged metrics will only get the dimensions explicitly set when creating the counter/gauge */ + PRETAGGED + } +} diff --git a/docker-api/src/test/java/com/yahoo/vespa/hosted/dockerapi/DockerImplTest.java b/docker-api/src/test/java/com/yahoo/vespa/hosted/dockerapi/DockerImplTest.java index 81aa5b05ad6..4843d8f9685 100644 --- a/docker-api/src/test/java/com/yahoo/vespa/hosted/dockerapi/DockerImplTest.java +++ b/docker-api/src/test/java/com/yahoo/vespa/hosted/dockerapi/DockerImplTest.java @@ -14,7 +14,7 @@ import com.github.dockerjava.api.command.PullImageCmd; import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.core.command.ExecStartResultCallback; import com.yahoo.config.provision.DockerImage; -import com.yahoo.vespa.hosted.dockerapi.metrics.MetricReceiver; +import com.yahoo.vespa.hosted.dockerapi.metrics.Metrics; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Matchers; @@ -36,8 +36,8 @@ import static org.mockito.Mockito.when; public class DockerImplTest { private final DockerClient dockerClient = mock(DockerClient.class); - private final MetricReceiver metricReceiver = new MetricReceiver(); - private final DockerImpl docker = new DockerImpl(dockerClient, metricReceiver); + private final Metrics metrics = new Metrics(); + private final DockerImpl docker = new DockerImpl(dockerClient, metrics); @Test public void testExecuteCompletes() { diff --git a/docker-api/src/test/java/com/yahoo/vespa/hosted/dockerapi/metrics/MetricReceiverTest.java b/docker-api/src/test/java/com/yahoo/vespa/hosted/dockerapi/metrics/MetricReceiverTest.java deleted file mode 100644 index 40b7dfa6878..00000000000 --- a/docker-api/src/test/java/com/yahoo/vespa/hosted/dockerapi/metrics/MetricReceiverTest.java +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.hosted.dockerapi.metrics; - -import org.junit.Test; - -import java.util.Map; -import java.util.stream.Collectors; - -import static com.yahoo.vespa.hosted.dockerapi.metrics.MetricReceiver.APPLICATION_HOST; -import static com.yahoo.vespa.hosted.dockerapi.metrics.MetricReceiver.DimensionType.DEFAULT; -import static org.junit.Assert.assertEquals; - -/** - * @author freva - */ -public class MetricReceiverTest { - private static final Dimensions hostDimension = new Dimensions.Builder().add("host", "abc.yahoo.com").build(); - private final MetricReceiver metricReceiver = new MetricReceiver(); - - @Test - public void testDefaultValue() { - metricReceiver.declareCounter("some.name", hostDimension); - - assertEquals(getMetricsForDimension(hostDimension).get("some.name"), 0L); - } - - @Test - public void testSimpleIncrementMetric() { - Counter counter = metricReceiver.declareCounter("a_counter.value", hostDimension); - - counter.add(5); - counter.add(8); - - Map latestMetrics = getMetricsForDimension(hostDimension); - assertEquals("Expected only 1 metric value to be set", 1, latestMetrics.size()); - assertEquals(latestMetrics.get("a_counter.value"), 13L); // 5 + 8 - } - - @Test - public void testSimpleGauge() { - Gauge gauge = metricReceiver.declareGauge("test.gauge", hostDimension); - - gauge.sample(42); - gauge.sample(-342.23); - - Map latestMetrics = getMetricsForDimension(hostDimension); - assertEquals("Expected only 1 metric value to be set", 1, latestMetrics.size()); - assertEquals(latestMetrics.get("test.gauge"), -342.23); - } - - @Test - public void testRedeclaringSameGauge() { - Gauge gauge = metricReceiver.declareGauge("test.gauge", hostDimension); - gauge.sample(42); - - // Same as hostDimension, but new instance. - Dimensions newDimension = new Dimensions.Builder().add("host", "abc.yahoo.com").build(); - Gauge newGauge = metricReceiver.declareGauge("test.gauge", newDimension); - newGauge.sample(56); - - assertEquals(getMetricsForDimension(hostDimension).get("test.gauge"), 56.); - } - - @Test - public void testSameMetricNameButDifferentDimensions() { - Gauge gauge = metricReceiver.declareGauge("test.gauge", hostDimension); - gauge.sample(42); - - // Not the same as hostDimension. - Dimensions newDimension = new Dimensions.Builder().add("host", "abcd.yahoo.com").build(); - Gauge newGauge = metricReceiver.declareGauge("test.gauge", newDimension); - newGauge.sample(56); - - assertEquals(getMetricsForDimension(hostDimension).get("test.gauge"), 42.); - assertEquals(getMetricsForDimension(newDimension).get("test.gauge"), 56.); - } - - @Test - public void testDeletingMetric() { - metricReceiver.declareGauge("test.gauge", hostDimension); - - Dimensions differentDimension = new Dimensions.Builder().add("host", "abcd.yahoo.com").build(); - metricReceiver.declareGauge("test.gauge", differentDimension); - - assertEquals(2, metricReceiver.getMetricsByType(DEFAULT).size()); - metricReceiver.deleteMetricByDimension(APPLICATION_HOST, differentDimension, DEFAULT); - assertEquals(1, metricReceiver.getMetricsByType(DEFAULT).size()); - assertEquals(getMetricsForDimension(hostDimension).size(), 1); - assertEquals(getMetricsForDimension(differentDimension).size(), 0); - } - - private Map getMetricsForDimension(Dimensions dimensions) { - return metricReceiver.getOrCreateApplicationMetrics(APPLICATION_HOST, DEFAULT) - .getOrDefault(dimensions, Map.of()) - .entrySet() - .stream() - .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().getValue())); - } -} diff --git a/docker-api/src/test/java/com/yahoo/vespa/hosted/dockerapi/metrics/MetricsTest.java b/docker-api/src/test/java/com/yahoo/vespa/hosted/dockerapi/metrics/MetricsTest.java new file mode 100644 index 00000000000..fc153ee0562 --- /dev/null +++ b/docker-api/src/test/java/com/yahoo/vespa/hosted/dockerapi/metrics/MetricsTest.java @@ -0,0 +1,99 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.dockerapi.metrics; + +import org.junit.Test; + +import java.util.Map; +import java.util.stream.Collectors; + +import static com.yahoo.vespa.hosted.dockerapi.metrics.Metrics.APPLICATION_HOST; +import static com.yahoo.vespa.hosted.dockerapi.metrics.Metrics.DimensionType.DEFAULT; +import static org.junit.Assert.assertEquals; + +/** + * @author freva + */ +public class MetricsTest { + private static final Dimensions hostDimension = new Dimensions.Builder().add("host", "abc.yahoo.com").build(); + private final Metrics metrics = new Metrics(); + + @Test + public void testDefaultValue() { + metrics.declareCounter("some.name", hostDimension); + + assertEquals(getMetricsForDimension(hostDimension).get("some.name"), 0L); + } + + @Test + public void testSimpleIncrementMetric() { + Counter counter = metrics.declareCounter("a_counter.value", hostDimension); + + counter.add(5); + counter.add(8); + + Map latestMetrics = getMetricsForDimension(hostDimension); + assertEquals("Expected only 1 metric value to be set", 1, latestMetrics.size()); + assertEquals(latestMetrics.get("a_counter.value"), 13L); // 5 + 8 + } + + @Test + public void testSimpleGauge() { + Gauge gauge = metrics.declareGauge("test.gauge", hostDimension); + + gauge.sample(42); + gauge.sample(-342.23); + + Map latestMetrics = getMetricsForDimension(hostDimension); + assertEquals("Expected only 1 metric value to be set", 1, latestMetrics.size()); + assertEquals(latestMetrics.get("test.gauge"), -342.23); + } + + @Test + public void testRedeclaringSameGauge() { + Gauge gauge = metrics.declareGauge("test.gauge", hostDimension); + gauge.sample(42); + + // Same as hostDimension, but new instance. + Dimensions newDimension = new Dimensions.Builder().add("host", "abc.yahoo.com").build(); + Gauge newGauge = metrics.declareGauge("test.gauge", newDimension); + newGauge.sample(56); + + assertEquals(getMetricsForDimension(hostDimension).get("test.gauge"), 56.); + } + + @Test + public void testSameMetricNameButDifferentDimensions() { + Gauge gauge = metrics.declareGauge("test.gauge", hostDimension); + gauge.sample(42); + + // Not the same as hostDimension. + Dimensions newDimension = new Dimensions.Builder().add("host", "abcd.yahoo.com").build(); + Gauge newGauge = metrics.declareGauge("test.gauge", newDimension); + newGauge.sample(56); + + assertEquals(getMetricsForDimension(hostDimension).get("test.gauge"), 42.); + assertEquals(getMetricsForDimension(newDimension).get("test.gauge"), 56.); + } + + @Test + public void testDeletingMetric() { + metrics.declareGauge("test.gauge", hostDimension); + + Dimensions differentDimension = new Dimensions.Builder().add("host", "abcd.yahoo.com").build(); + metrics.declareGauge("test.gauge", differentDimension); + + assertEquals(2, metrics.getMetricsByType(DEFAULT).size()); + metrics.deleteMetricByDimension(APPLICATION_HOST, differentDimension, DEFAULT); + assertEquals(1, metrics.getMetricsByType(DEFAULT).size()); + assertEquals(getMetricsForDimension(hostDimension).size(), 1); + assertEquals(getMetricsForDimension(differentDimension).size(), 0); + } + + private Map getMetricsForDimension(Dimensions dimensions) { + return metrics.getOrCreateApplicationMetrics(APPLICATION_HOST, DEFAULT) + .getOrDefault(dimensions, Map.of()) + .entrySet() + .stream() + .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().getValue())); + } +} -- cgit v1.2.3