diff --git a/src/main/java/software/amazon/cloudwatchlogs/emf/model/Metric.java b/src/main/java/software/amazon/cloudwatchlogs/emf/model/Metric.java new file mode 100644 index 00000000..9923fb92 --- /dev/null +++ b/src/main/java/software/amazon/cloudwatchlogs/emf/model/Metric.java @@ -0,0 +1,124 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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 software.amazon.cloudwatchlogs.emf.model; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NonNull; +import lombok.Setter; +import software.amazon.cloudwatchlogs.emf.serializers.StorageResolutionFilter; +import software.amazon.cloudwatchlogs.emf.serializers.StorageResolutionSerializer; +import software.amazon.cloudwatchlogs.emf.serializers.UnitDeserializer; +import software.amazon.cloudwatchlogs.emf.serializers.UnitSerializer; + +/** Abstract immutable (except for name) class that all Metrics are based on. */ +@Getter +public abstract class Metric { + @JsonProperty("Name") + @Setter(AccessLevel.PROTECTED) + @NonNull + protected String name; + + @JsonProperty("Unit") + @JsonSerialize(using = UnitSerializer.class) + @JsonDeserialize(using = UnitDeserializer.class) + protected Unit unit; + + @JsonProperty("StorageResolution") + @JsonInclude( + value = JsonInclude.Include.CUSTOM, + valueFilter = + StorageResolutionFilter.class) // Do not serialize when valueFilter is true + @JsonSerialize(using = StorageResolutionSerializer.class) + protected StorageResolution storageResolution; + + @JsonIgnore @Getter protected V values; + + /** @return the values of this metric formatted to be flushed */ + protected Object getFormattedValues() { + return this.getValues(); + } + + /** + * Creates a Metric with the first {@code size} values of the current metric + * + * @param size the maximum size of the returned metric's values + * @return a Metric with the first {@code size} values of the current metric. + */ + protected abstract Metric getMetricValuesUnderSize(int size); + + /** + * Creates a Metric all metrics after the first {@code size} values of the current metric. If + * there are less than {@code size} values, null is returned. + * + * @param size the maximum size of the returned metric's values + * @return a Metric with the all metrics after the first {@code size} values of the current + * metric. If there are less than {@code size} values, null is returned. + */ + protected abstract Metric getMetricValuesOverSize(int size); + + public abstract static class MetricBuilder> extends Metric { + + protected abstract T getThis(); + + /** + * Adds a value to the metric. + * + * @param value the value to be added to this metric + */ + abstract T addValue(double value); + + /** + * Builds the metric. + * + * @return the built metric + */ + abstract Metric build(); + + protected T name(@NonNull String name) { + this.name = name; + return getThis(); + } + + public T unit(Unit unit) { + this.unit = unit; + return getThis(); + } + + public T storageResolution(StorageResolution storageResolution) { + this.storageResolution = storageResolution; + return getThis(); + } + + protected Metric getMetricValuesOverSize(int size) { + return build().getMetricValuesOverSize(size); + } + + protected Metric getMetricValuesUnderSize(int size) { + return build().getMetricValuesUnderSize(size); + } + + protected Object getFormattedValues() { + return build().getFormattedValues(); + } + } +} diff --git a/src/main/java/software/amazon/cloudwatchlogs/emf/model/MetricDefinition.java b/src/main/java/software/amazon/cloudwatchlogs/emf/model/MetricDefinition.java index 957da0d3..7db9a14f 100644 --- a/src/main/java/software/amazon/cloudwatchlogs/emf/model/MetricDefinition.java +++ b/src/main/java/software/amazon/cloudwatchlogs/emf/model/MetricDefinition.java @@ -16,70 +16,101 @@ package software.amazon.cloudwatchlogs.emf.model; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; -import lombok.AllArgsConstructor; -import lombok.Getter; import lombok.NonNull; -import lombok.Setter; -import software.amazon.cloudwatchlogs.emf.serializers.StorageResolutionFilter; -import software.amazon.cloudwatchlogs.emf.serializers.StorageResolutionSerializer; -import software.amazon.cloudwatchlogs.emf.serializers.UnitDeserializer; -import software.amazon.cloudwatchlogs.emf.serializers.UnitSerializer; /** Represents the MetricDefinition of the EMF schema. */ -@AllArgsConstructor -class MetricDefinition { - @NonNull - @Getter - @JsonProperty("Name") - private String name; +public class MetricDefinition extends Metric> { - @Getter - @JsonProperty("Unit") - @JsonSerialize(using = UnitSerializer.class) - @JsonDeserialize(using = UnitDeserializer.class) - private Unit unit; - - @Getter - @Setter - @JsonProperty("StorageResolution") - @JsonInclude( - value = JsonInclude.Include.CUSTOM, - valueFilter = - StorageResolutionFilter.class) // Do not serialize when valueFilter is true - @JsonSerialize(using = StorageResolutionSerializer.class) - public StorageResolution storageResolution; - - @JsonIgnore @NonNull @Getter private List values; + private MetricDefinition( + @NonNull String name, + Unit unit, + StorageResolution storageResolution, + List values) { + this.unit = unit; + this.storageResolution = storageResolution; + this.values = values; + this.name = name; + } - MetricDefinition(String name) { - this(name, Unit.NONE, StorageResolution.STANDARD, new ArrayList<>()); + MetricDefinition(Unit unit, StorageResolution storageResolution, List values) { + this.unit = unit; + this.storageResolution = storageResolution; + this.values = values; } - MetricDefinition(String name, double value) { - this(name, Unit.NONE, StorageResolution.STANDARD, value); + @Override + protected Metric getMetricValuesUnderSize(int size) { + List subList = values.subList(0, Math.min(values.size(), size)); + MetricDefinition metric = + MetricDefinition.builder() + .unit(unit) + .storageResolution(storageResolution) + .values(subList) + .build(); + metric.setName(name); + return metric; } - MetricDefinition(String name, Unit unit, double value) { - this(name, unit, StorageResolution.STANDARD, new ArrayList<>(Arrays.asList(value))); + @Override + protected Metric getMetricValuesOverSize(int size) { + if (size > values.size()) { + return null; + } + List subList = values.subList(size, values.size()); + MetricDefinition metric = + MetricDefinition.builder() + .name(name) + .unit(unit) + .storageResolution(storageResolution) + .values(subList) + .build(); + return metric; } - MetricDefinition(String name, StorageResolution storageResolution, double value) { - this(name, Unit.NONE, storageResolution, new ArrayList<>(Arrays.asList(value))); + public static MetricDefinitionBuilder builder() { + return new MetricDefinitionBuilder(); } - MetricDefinition(String name, Unit unit, StorageResolution storageResolution, double value) { - this(name, unit, storageResolution, new ArrayList<>(Arrays.asList(value))); + /** + * @return the values of this metric, simplified to a double instead of a list if there is only + * one value + */ + @Override + protected Object getFormattedValues() { + return values.size() == 1 ? values.get(0) : values; } - void addValue(double value) { - values.add(value); + public static class MetricDefinitionBuilder + extends Metric.MetricBuilder, MetricDefinitionBuilder> { + + @Override + protected MetricDefinitionBuilder getThis() { + return this; + } + + public MetricDefinitionBuilder() { + this.values = new ArrayList<>(); + } + + @Override + public MetricDefinitionBuilder addValue(double value) { + this.values.add(value); + return this; + } + + public MetricDefinitionBuilder values(@NonNull List values) { + this.values = values; + return this; + } + + @Override + public MetricDefinition build() { + if (name == null) { + return new MetricDefinition(unit, storageResolution, values); + } + return new MetricDefinition(name, unit, storageResolution, values); + } } } diff --git a/src/main/java/software/amazon/cloudwatchlogs/emf/model/MetricDirective.java b/src/main/java/software/amazon/cloudwatchlogs/emf/model/MetricDirective.java index 80ebb95a..09446e58 100644 --- a/src/main/java/software/amazon/cloudwatchlogs/emf/model/MetricDirective.java +++ b/src/main/java/software/amazon/cloudwatchlogs/emf/model/MetricDirective.java @@ -23,6 +23,7 @@ import java.util.stream.Collectors; import lombok.*; import software.amazon.cloudwatchlogs.emf.exception.DimensionSetExceededException; +import software.amazon.cloudwatchlogs.emf.exception.InvalidMetricException; /** Represents the MetricDirective part of the EMF schema. */ @AllArgsConstructor @@ -32,7 +33,7 @@ class MetricDirective { @JsonProperty("Namespace") private String namespace; - @JsonIgnore @Setter @Getter @With private Map metrics; + @JsonIgnore @Setter @Getter @With private Map metrics; @JsonIgnore @Getter(AccessLevel.PROTECTED) @@ -85,16 +86,28 @@ void putMetric(String key, double value, Unit unit, StorageResolution storageRes metrics.compute( key, (k, v) -> { - if (v == null) return new MetricDefinition(key, unit, storageResolution, value); - else { - v.addValue(value); + if (v == null) { + MetricDefinition.MetricDefinitionBuilder builder = + MetricDefinition.builder() + .name(k) + .unit(unit) + .storageResolution(storageResolution) + .addValue(value); + return builder; + } else if (v instanceof Metric.MetricBuilder) { + ((Metric.MetricBuilder) v).addValue(value); return v; + } else { + throw new InvalidMetricException( + String.format( + "New metrics cannot be put to the name: \"%s\", because it has been set to an immutable metric type.", + k)); } }); } @JsonProperty("Metrics") - Collection getAllMetrics() { + Collection getAllMetrics() { return metrics.values(); } diff --git a/src/main/java/software/amazon/cloudwatchlogs/emf/model/MetricsContext.java b/src/main/java/software/amazon/cloudwatchlogs/emf/model/MetricsContext.java index 32280487..7edf6652 100644 --- a/src/main/java/software/amazon/cloudwatchlogs/emf/model/MetricsContext.java +++ b/src/main/java/software/amazon/cloudwatchlogs/emf/model/MetricsContext.java @@ -323,11 +323,10 @@ public List serialize() throws JsonProcessingException { return Arrays.asList(this.rootNode.serialize()); } else { List nodes = new ArrayList<>(); - Map metrics = new HashMap<>(); - Queue metricDefinitions = - new LinkedList<>(rootNode.metrics().values()); - while (!metricDefinitions.isEmpty()) { - MetricDefinition metric = metricDefinitions.poll(); + Map metrics = new HashMap<>(); + Queue metricQueue = new LinkedList<>(rootNode.metrics().values()); + while (!metricQueue.isEmpty()) { + Metric metric = metricQueue.poll(); if (metrics.size() == Constants.MAX_METRICS_PER_EVENT || metrics.containsKey(metric.getName())) { @@ -335,28 +334,18 @@ public List serialize() throws JsonProcessingException { metrics = new HashMap<>(); } - if (metric.getValues().size() <= Constants.MAX_DATAPOINTS_PER_METRIC) { - metrics.put(metric.getName(), metric); - } else { - metrics.put( - metric.getName(), - new MetricDefinition( - metric.getName(), - metric.getUnit(), - metric.getStorageResolution(), - metric.getValues() - .subList(0, Constants.MAX_DATAPOINTS_PER_METRIC))); - metricDefinitions.offer( - new MetricDefinition( - metric.getName(), - metric.getUnit(), - metric.getStorageResolution(), - metric.getValues() - .subList( - Constants.MAX_DATAPOINTS_PER_METRIC, - metric.getValues().size()))); + Metric overSizeMetric = + metric.getMetricValuesOverSize(Constants.MAX_DATAPOINTS_PER_METRIC); + Metric underSizeMetric = + metric.getMetricValuesUnderSize(Constants.MAX_DATAPOINTS_PER_METRIC); + + metrics.put(metric.getName(), underSizeMetric); + + if (overSizeMetric != null) { + metricQueue.offer(overSizeMetric); } } + if (!metrics.isEmpty()) { nodes.add(buildRootNode(metrics)); } @@ -368,7 +357,7 @@ public List serialize() throws JsonProcessingException { } } - private RootNode buildRootNode(Map metrics) { + private RootNode buildRootNode(Map metrics) { Metadata metadata = rootNode.getAws(); MetricDirective md = metadata.getCloudWatchMetrics().get(0); Metadata clonedMetadata = @@ -379,6 +368,8 @@ private RootNode buildRootNode(Map metrics) { private boolean anyMetricWithTooManyDataPoints(RootNode node) { return node.metrics().values().stream() .anyMatch( - metric -> metric.getValues().size() > Constants.MAX_DATAPOINTS_PER_METRIC); + metric -> + metric.getMetricValuesOverSize(Constants.MAX_DATAPOINTS_PER_METRIC) + != null); } } diff --git a/src/main/java/software/amazon/cloudwatchlogs/emf/model/RootNode.java b/src/main/java/software/amazon/cloudwatchlogs/emf/model/RootNode.java index 0559746b..1de12aa6 100644 --- a/src/main/java/software/amazon/cloudwatchlogs/emf/model/RootNode.java +++ b/src/main/java/software/amazon/cloudwatchlogs/emf/model/RootNode.java @@ -23,7 +23,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import lombok.AllArgsConstructor; @@ -66,9 +65,8 @@ Map getTargetMembers() throws DimensionSetExceededException { targetMembers.putAll(properties); targetMembers.putAll(getDimensions()); for (MetricDirective metricDirective : aws.getCloudWatchMetrics()) { - for (MetricDefinition metric : metricDirective.getMetrics().values()) { - List values = metric.getValues(); - targetMembers.put(metric.getName(), values.size() == 1 ? values.get(0) : values); + for (Metric metric : metricDirective.getMetrics().values()) { + targetMembers.put(metric.getName(), metric.getFormattedValues()); } } return targetMembers; @@ -85,7 +83,7 @@ Map getDimensions() throws DimensionSetExceededException { return dimensions; } - Map metrics() { + Map metrics() { return aws.getCloudWatchMetrics().get(0).getMetrics(); } diff --git a/src/test/java/software/amazon/cloudwatchlogs/emf/model/MetricDefinitionTest.java b/src/test/java/software/amazon/cloudwatchlogs/emf/model/MetricDefinitionTest.java index 25c3d43a..1bfd902c 100644 --- a/src/test/java/software/amazon/cloudwatchlogs/emf/model/MetricDefinitionTest.java +++ b/src/test/java/software/amazon/cloudwatchlogs/emf/model/MetricDefinitionTest.java @@ -24,11 +24,12 @@ import java.util.Collections; import org.junit.Test; -public class MetricDefinitionTest { +class MetricDefinitionTest { @Test(expected = NullPointerException.class) public void testThrowExceptionIfNameIsNull() { - new MetricDefinition(null); + MetricDefinition.MetricDefinitionBuilder builder = MetricDefinition.builder(); + builder.setName(null); } @Test @@ -36,7 +37,11 @@ public void testSerializeMetricDefinitionWithoutUnitWithHighStorageResolution() throws JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper(); MetricDefinition metricDefinition = - new MetricDefinition("Time", StorageResolution.HIGH, 10); + MetricDefinition.builder() + .storageResolution(StorageResolution.HIGH) + .addValue(10) + .name("Time") + .build(); String metricString = objectMapper.writeValueAsString(metricDefinition); assertEquals("{\"Name\":\"Time\",\"Unit\":\"None\",\"StorageResolution\":1}", metricString); @@ -46,7 +51,12 @@ public void testSerializeMetricDefinitionWithoutUnitWithHighStorageResolution() public void testSerializeMetricDefinitionWithUnitWithoutStorageResolution() throws JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper(); - MetricDefinition metricDefinition = new MetricDefinition("Time", Unit.MILLISECONDS, 10); + MetricDefinition metricDefinition = + MetricDefinition.builder() + .unit(Unit.MILLISECONDS) + .addValue(10) + .name("Time") + .build(); String metricString = objectMapper.writeValueAsString(metricDefinition); assertEquals("{\"Name\":\"Time\",\"Unit\":\"Milliseconds\"}", metricString); @@ -57,7 +67,11 @@ public void testSerializeMetricDefinitionWithoutUnitWithStandardStorageResolutio throws JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper(); MetricDefinition metricDefinition = - new MetricDefinition("Time", StorageResolution.STANDARD, 10); + MetricDefinition.builder() + .storageResolution(StorageResolution.STANDARD) + .addValue(10) + .name("Time") + .build(); String metricString = objectMapper.writeValueAsString(metricDefinition); assertEquals("{\"Name\":\"Time\",\"Unit\":\"None\"}", metricString); @@ -66,7 +80,7 @@ public void testSerializeMetricDefinitionWithoutUnitWithStandardStorageResolutio @Test public void testSerializeMetricDefinitionWithoutUnit() throws JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper(); - MetricDefinition metricDefinition = new MetricDefinition("Time"); + MetricDefinition metricDefinition = MetricDefinition.builder().name("Time").build(); String metricString = objectMapper.writeValueAsString(metricDefinition); assertEquals("{\"Name\":\"Time\",\"Unit\":\"None\"}", metricString); @@ -76,7 +90,12 @@ public void testSerializeMetricDefinitionWithoutUnit() throws JsonProcessingExce public void testSerializeMetricDefinition() throws JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper(); MetricDefinition metricDefinition = - new MetricDefinition("Time", Unit.MILLISECONDS, StorageResolution.HIGH, 10); + MetricDefinition.builder() + .unit(Unit.MILLISECONDS) + .storageResolution(StorageResolution.HIGH) + .addValue(10) + .name("Time") + .build(); String metricString = objectMapper.writeValueAsString(metricDefinition); assertEquals( @@ -86,10 +105,11 @@ public void testSerializeMetricDefinition() throws JsonProcessingException { @Test public void testAddValue() { - MetricDefinition md = new MetricDefinition("Time", Unit.MICROSECONDS, 10); - assertEquals(Collections.singletonList(10d), md.getValues()); + MetricDefinition.MetricDefinitionBuilder builder = + MetricDefinition.builder().unit(Unit.MILLISECONDS).addValue(10).addValue(20); + assertEquals(Collections.singletonList(10d), builder.getValues()); - md.addValue(20); - assertEquals(Arrays.asList(10d, 20d), md.getValues()); + builder.addValue(20); + assertEquals(Arrays.asList(10d, 20d), builder.getValues()); } } diff --git a/src/test/java/software/amazon/cloudwatchlogs/emf/model/MetricDirectiveTest.java b/src/test/java/software/amazon/cloudwatchlogs/emf/model/MetricDirectiveTest.java index 9c095c50..c1c2f8f8 100644 --- a/src/test/java/software/amazon/cloudwatchlogs/emf/model/MetricDirectiveTest.java +++ b/src/test/java/software/amazon/cloudwatchlogs/emf/model/MetricDirectiveTest.java @@ -71,7 +71,10 @@ void testPutSameMetricMultipleTimes() { metricDirective.putMetric("Time", 20); Assertions.assertEquals(1, metricDirective.getAllMetrics().size()); - MetricDefinition[] mds = metricDirective.getAllMetrics().toArray(new MetricDefinition[0]); + MetricDefinition.MetricDefinitionBuilder[] mds = + metricDirective + .getAllMetrics() + .toArray(new MetricDefinition.MetricDefinitionBuilder[0]); Assertions.assertEquals(Arrays.asList(10d, 20d), mds[0].getValues()); } diff --git a/src/test/java/software/amazon/cloudwatchlogs/emf/model/MetricDirectiveThreadSafetyTest.java b/src/test/java/software/amazon/cloudwatchlogs/emf/model/MetricDirectiveThreadSafetyTest.java index 28cd1b08..c716a173 100644 --- a/src/test/java/software/amazon/cloudwatchlogs/emf/model/MetricDirectiveThreadSafetyTest.java +++ b/src/test/java/software/amazon/cloudwatchlogs/emf/model/MetricDirectiveThreadSafetyTest.java @@ -3,6 +3,7 @@ import static org.junit.Assert.assertEquals; import java.util.Collections; +import java.util.List; import org.junit.After; import org.junit.Test; @@ -50,7 +51,10 @@ public void testConcurrentPutMetricWithDifferentKey() throws InterruptedExceptio assertEquals(metricDirective.getAllMetrics().size(), N_THREAD * N_PUT_METRIC); for (int i = 0; i < N_THREAD * N_PUT_METRIC; i++) { assertEquals( - metricDirective.getMetrics().get("Metric-" + i).getValues().get(0), i, 1e-5); + ((List) metricDirective.getMetrics().get("Metric-" + i).getValues()) + .get(0), + i, + 1e-5); } } @@ -86,10 +90,11 @@ public void testConcurrentPutMetricWithSameKey() throws InterruptedException { } assertEquals(1, metricDirective.getAllMetrics().size()); - MetricDefinition md = metricDirective.getAllMetrics().toArray(new MetricDefinition[0])[0]; - Collections.sort(md.getValues()); + Metric md = metricDirective.getAllMetrics().toArray(new Metric[0])[0]; + List values = (List) md.getValues(); + Collections.sort(values); for (int i = 0; i < N_THREAD * N_PUT_METRIC; i++) { - assertEquals(md.getValues().get(i), i, 1e-5); + assertEquals(values.get(i), i, 1e-5); } } diff --git a/src/test/java/software/amazon/cloudwatchlogs/emf/model/MetricsContextTest.java b/src/test/java/software/amazon/cloudwatchlogs/emf/model/MetricsContextTest.java index 4cffe824..4191fdef 100644 --- a/src/test/java/software/amazon/cloudwatchlogs/emf/model/MetricsContextTest.java +++ b/src/test/java/software/amazon/cloudwatchlogs/emf/model/MetricsContextTest.java @@ -48,8 +48,8 @@ void testSerializeLessThan100Metrics() throws JsonProcessingException, InvalidMe List metrics = parseMetrics(events.get(0)); Assertions.assertEquals(metrics.size(), metricCount); - for (MetricDefinition metric : metrics) { - MetricDefinition originalMetric = mc.getRootNode().metrics().get(metric.getName()); + for (Metric metric : metrics) { + Metric originalMetric = mc.getRootNode().metrics().get(metric.getName()); Assertions.assertEquals(originalMetric.getName(), metric.getName()); Assertions.assertEquals(originalMetric.getUnit(), metric.getUnit()); } @@ -73,8 +73,9 @@ void testSerializeMoreThen100Metrics() throws JsonProcessingException, InvalidMe allMetrics.addAll(parseMetrics(event)); } Assertions.assertEquals(metricCount, allMetrics.size()); - for (MetricDefinition metric : allMetrics) { - MetricDefinition originalMetric = mc.getRootNode().metrics().get(metric.getName()); + for (Metric metric : allMetrics) { + Metric originalMetric = mc.getRootNode().metrics().get(metric.getName()); + Assertions.assertEquals(originalMetric.getName(), metric.getName()); Assertions.assertEquals(originalMetric.getUnit(), metric.getUnit()); } @@ -202,10 +203,20 @@ private ArrayList parseMetrics(String event) throws JsonProces Object value = rootNode.get(name); if (value instanceof ArrayList) { metricDefinitions.add( - new MetricDefinition( - name, unit, StorageResolution.STANDARD, (ArrayList) value)); + MetricDefinition.builder() + .name(name) + .unit(unit) + .storageResolution(StorageResolution.STANDARD) + .values((ArrayList) value) + .build()); } else { - metricDefinitions.add(new MetricDefinition(name, unit, (double) value)); + metricDefinitions.add( + MetricDefinition.builder() + .name(name) + .unit(unit) + .storageResolution(StorageResolution.STANDARD) + .addValue((double) value) + .build()); } } return metricDefinitions;