Skip to content

Commit 9fd3833

Browse files
committed
Refactored MetricsDefinition to use a MetricBuilder and be based off a super class
1 parent 6b97f76 commit 9fd3833

File tree

10 files changed

+263
-85
lines changed

10 files changed

+263
-85
lines changed

gradle.properties

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# The --add-exports flags work around a bug with spotless and JDK 17
2+
# https://github.com/diffplug/spotless/issues/834
3+
org.gradle.jvmargs=-Xmx2g \
4+
--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \
5+
--add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \
6+
--add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED \
7+
--add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \
8+
--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED

src/main/java/software/amazon/cloudwatchlogs/emf/model/MetricDefinition.java renamed to src/main/java/software/amazon/cloudwatchlogs/emf/model/Metric.java

Lines changed: 35 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -21,65 +21,66 @@
2121
import com.fasterxml.jackson.annotation.JsonProperty;
2222
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
2323
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
24-
import java.util.ArrayList;
25-
import java.util.Arrays;
26-
import java.util.List;
27-
import lombok.AllArgsConstructor;
2824
import lombok.Getter;
29-
import lombok.NonNull;
30-
import lombok.Setter;
3125
import software.amazon.cloudwatchlogs.emf.serializers.StorageResolutionFilter;
3226
import software.amazon.cloudwatchlogs.emf.serializers.StorageResolutionSerializer;
3327
import software.amazon.cloudwatchlogs.emf.serializers.UnitDeserializer;
3428
import software.amazon.cloudwatchlogs.emf.serializers.UnitSerializer;
3529

36-
/** Represents the MetricDefinition of the EMF schema. */
37-
@AllArgsConstructor
38-
class MetricDefinition {
39-
@NonNull
30+
/** Abstract immutable (except for name) class that all Metrics are based on. */
31+
public abstract class Metric {
4032
@Getter
4133
@JsonProperty("Name")
42-
private String name;
34+
protected String name;
4335

4436
@Getter
4537
@JsonProperty("Unit")
4638
@JsonSerialize(using = UnitSerializer.class)
4739
@JsonDeserialize(using = UnitDeserializer.class)
48-
private Unit unit;
40+
protected Unit unit;
4941

5042
@Getter
51-
@Setter
5243
@JsonProperty("StorageResolution")
5344
@JsonInclude(
5445
value = JsonInclude.Include.CUSTOM,
5546
valueFilter =
5647
StorageResolutionFilter.class) // Do not serialize when valueFilter is true
5748
@JsonSerialize(using = StorageResolutionSerializer.class)
58-
public StorageResolution storageResolution;
49+
protected StorageResolution storageResolution;
5950

60-
@JsonIgnore @NonNull @Getter private List<Double> values;
51+
@JsonIgnore @Getter protected Object values;
6152

62-
MetricDefinition(String name) {
63-
this(name, Unit.NONE, StorageResolution.STANDARD, new ArrayList<>());
53+
/**
54+
* Change the name of this metric. Should only be used within this package in MetricContext when
55+
* recieving an unnamed metric from a user.
56+
*
57+
* @param name The new metric name.
58+
*/
59+
protected void setName(String name) {
60+
if (name == null) {
61+
throw new NullPointerException("Metric name cannot be null");
62+
}
63+
this.name = name;
6464
}
6565

66-
MetricDefinition(String name, double value) {
67-
this(name, Unit.NONE, StorageResolution.STANDARD, value);
68-
}
69-
70-
MetricDefinition(String name, Unit unit, double value) {
71-
this(name, unit, StorageResolution.STANDARD, new ArrayList<>(Arrays.asList(value)));
72-
}
66+
/**
67+
* Creates a Metric with the first {@code size} values of the current metric
68+
*
69+
* @param size the maximim size of the returned metric's values
70+
* @return a Metric with the first {@code size} values of the current metric.
71+
*/
72+
protected abstract Metric getMetricValuesUnderSize(int size);
7373

74-
MetricDefinition(String name, StorageResolution storageResolution, double value) {
75-
this(name, Unit.NONE, storageResolution, new ArrayList<>(Arrays.asList(value)));
76-
}
74+
/**
75+
* Creates a Metric all metrics after the first {@code size} values of the current metric. If
76+
* there are less than {@code size} values, null is returned.
77+
*
78+
* @param size the maximim size of the returned metric's values
79+
* @return a Metric with the all metrics after the first {@code size} values of the current
80+
* metric. If there are less than {@code size} values, null is returned.
81+
*/
82+
protected abstract Metric getMetricValuesOverSize(int size);
7783

78-
MetricDefinition(String name, Unit unit, StorageResolution storageResolution, double value) {
79-
this(name, unit, storageResolution, new ArrayList<>(Arrays.asList(value)));
80-
}
81-
82-
void addValue(double value) {
83-
values.add(value);
84-
}
84+
/** @return a simplified representation of the values of this metric. */
85+
protected abstract Object getSimplifiedValues();
8586
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package software.amazon.cloudwatchlogs.emf.model;
18+
19+
/** Interface that allows metrics to be built from. */
20+
interface MetricBuilder {
21+
22+
/**
23+
* Adds a value to the metric.
24+
*
25+
* @param value the value to be added to this metric
26+
*/
27+
void addValue(double value);
28+
29+
/**
30+
* Builds the metric.
31+
*
32+
* @return the built metric
33+
*/
34+
Metric build();
35+
}
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package software.amazon.cloudwatchlogs.emf.model;
18+
19+
import com.fasterxml.jackson.annotation.JsonIgnore;
20+
import java.util.ArrayList;
21+
import java.util.Arrays;
22+
import java.util.List;
23+
import lombok.Getter;
24+
import lombok.NonNull;
25+
26+
/** Represents the MetricDefinition of the EMF schema. */
27+
class MetricDefinition extends Metric {
28+
@JsonIgnore @NonNull @Getter protected List<Double> values;
29+
30+
MetricDefinition(Unit unit, StorageResolution storageResolution, List<Double> values) {
31+
this.unit = unit;
32+
this.storageResolution = storageResolution;
33+
this.values = values;
34+
}
35+
36+
MetricDefinition(
37+
String name, Unit unit, StorageResolution storageResolution, List<Double> values) {
38+
this.unit = unit;
39+
this.storageResolution = storageResolution;
40+
this.values = values;
41+
this.name = name;
42+
}
43+
44+
MetricDefinition(String name, Unit unit, StorageResolution storageResolution, Double value) {
45+
this.unit = unit;
46+
this.storageResolution = storageResolution;
47+
this.values = Arrays.asList(value);
48+
this.name = name;
49+
}
50+
51+
@Override
52+
protected Metric getMetricValuesUnderSize(int size) {
53+
List<Double> subList = values.subList(0, size > values.size() ? values.size() : size);
54+
return new MetricDefinition(name, unit, storageResolution, subList);
55+
}
56+
57+
@Override
58+
protected Metric getMetricValuesOverSize(int size) {
59+
if (size > values.size()) {
60+
return null;
61+
}
62+
List<Double> subList = values.subList(size, values.size());
63+
return new MetricDefinition(name, unit, storageResolution, subList);
64+
}
65+
66+
/**
67+
* @return the values of this metric, simplified to a double instead of a list if there is only
68+
* one value
69+
*/
70+
@Override
71+
protected Object getSimplifiedValues() {
72+
return values.size() == 1 ? values.get(0) : values;
73+
}
74+
}
75+
76+
/** Builds MetricDefinition */
77+
public class MetricDefinitionBuilder extends MetricDefinition implements MetricBuilder {
78+
79+
MetricDefinitionBuilder(Unit unit, StorageResolution storageResolution, List<Double> values) {
80+
super(unit, storageResolution, values);
81+
}
82+
83+
protected MetricDefinitionBuilder(
84+
String Name, Unit unit, StorageResolution storageResolution, Double value) {
85+
this(unit, storageResolution, Arrays.asList(value));
86+
setName(name);
87+
}
88+
89+
MetricDefinitionBuilder(Unit unit, StorageResolution storageResolution) {
90+
this(unit, storageResolution, new ArrayList<>());
91+
}
92+
93+
MetricDefinitionBuilder() {
94+
this(Unit.NONE, StorageResolution.STANDARD, new ArrayList<>());
95+
}
96+
97+
MetricDefinitionBuilder(double value) {
98+
this(Unit.NONE, StorageResolution.STANDARD, value);
99+
}
100+
101+
MetricDefinitionBuilder(Unit unit, double value) {
102+
this(unit, StorageResolution.STANDARD, new ArrayList<>(Arrays.asList(value)));
103+
}
104+
105+
MetricDefinitionBuilder(StorageResolution storageResolution, double value) {
106+
this(Unit.NONE, storageResolution, new ArrayList<>(Arrays.asList(value)));
107+
}
108+
109+
MetricDefinitionBuilder(Unit unit, StorageResolution storageResolution, double value) {
110+
this(unit, storageResolution, new ArrayList<>(Arrays.asList(value)));
111+
}
112+
113+
/** @return a built version of this metric. */
114+
public MetricDefinition build() {
115+
return (MetricDefinition) this;
116+
}
117+
118+
/** @param value a value to add to the metric. */
119+
@Override
120+
public void addValue(double value) {
121+
this.values.add(value);
122+
}
123+
}

src/main/java/software/amazon/cloudwatchlogs/emf/model/MetricDirective.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class MetricDirective {
3232
@JsonProperty("Namespace")
3333
private String namespace;
3434

35-
@JsonIgnore @Setter @Getter @With private Map<String, MetricDefinition> metrics;
35+
@JsonIgnore @Setter @Getter @With private Map<String, Metric> metrics;
3636

3737
@JsonIgnore
3838
@Getter(AccessLevel.PROTECTED)
@@ -85,16 +85,22 @@ void putMetric(String key, double value, Unit unit, StorageResolution storageRes
8585
metrics.compute(
8686
key,
8787
(k, v) -> {
88-
if (v == null) return new MetricDefinition(key, unit, storageResolution, value);
89-
else {
90-
v.addValue(value);
88+
if (v == null) {
89+
MetricDefinitionBuilder tmp =
90+
new MetricDefinitionBuilder(unit, storageResolution, value);
91+
tmp.setName(key);
92+
return (Metric) tmp;
93+
} else if (v instanceof MetricBuilder) {
94+
((MetricBuilder) v).addValue(value);
9195
return v;
96+
} else {
97+
throw new IllegalStateException("Metric already exists and is Immuatble");
9298
}
9399
});
94100
}
95101

96102
@JsonProperty("Metrics")
97-
Collection<MetricDefinition> getAllMetrics() {
103+
Collection<Metric> getAllMetrics() {
98104
return metrics.values();
99105
}
100106

src/main/java/software/amazon/cloudwatchlogs/emf/model/MetricsContext.java

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -323,40 +323,29 @@ public List<String> serialize() throws JsonProcessingException {
323323
return Arrays.asList(this.rootNode.serialize());
324324
} else {
325325
List<RootNode> nodes = new ArrayList<>();
326-
Map<String, MetricDefinition> metrics = new HashMap<>();
327-
Queue<MetricDefinition> metricDefinitions =
328-
new LinkedList<>(rootNode.metrics().values());
329-
while (!metricDefinitions.isEmpty()) {
330-
MetricDefinition metric = metricDefinitions.poll();
326+
Map<String, Metric> metrics = new HashMap<>();
327+
Queue<Metric> metricQueue = new LinkedList<>(rootNode.metrics().values());
328+
while (!metricQueue.isEmpty()) {
329+
Metric metric = metricQueue.poll();
331330

332331
if (metrics.size() == Constants.MAX_METRICS_PER_EVENT
333332
|| metrics.containsKey(metric.getName())) {
334333
nodes.add(buildRootNode(metrics));
335334
metrics = new HashMap<>();
336335
}
337336

338-
if (metric.getValues().size() <= Constants.MAX_DATAPOINTS_PER_METRIC) {
339-
metrics.put(metric.getName(), metric);
340-
} else {
341-
metrics.put(
342-
metric.getName(),
343-
new MetricDefinition(
344-
metric.getName(),
345-
metric.getUnit(),
346-
metric.getStorageResolution(),
347-
metric.getValues()
348-
.subList(0, Constants.MAX_DATAPOINTS_PER_METRIC)));
349-
metricDefinitions.offer(
350-
new MetricDefinition(
351-
metric.getName(),
352-
metric.getUnit(),
353-
metric.getStorageResolution(),
354-
metric.getValues()
355-
.subList(
356-
Constants.MAX_DATAPOINTS_PER_METRIC,
357-
metric.getValues().size())));
337+
Metric overSizeMetric =
338+
metric.getMetricValuesOverSize(Constants.MAX_DATAPOINTS_PER_METRIC);
339+
Metric underSizeMetric =
340+
metric.getMetricValuesUnderSize(Constants.MAX_DATAPOINTS_PER_METRIC);
341+
342+
metrics.put(metric.getName(), underSizeMetric);
343+
344+
if (overSizeMetric != null) {
345+
metricQueue.offer(overSizeMetric);
358346
}
359347
}
348+
360349
if (!metrics.isEmpty()) {
361350
nodes.add(buildRootNode(metrics));
362351
}
@@ -368,7 +357,7 @@ public List<String> serialize() throws JsonProcessingException {
368357
}
369358
}
370359

371-
private RootNode buildRootNode(Map<String, MetricDefinition> metrics) {
360+
private RootNode buildRootNode(Map<String, Metric> metrics) {
372361
Metadata metadata = rootNode.getAws();
373362
MetricDirective md = metadata.getCloudWatchMetrics().get(0);
374363
Metadata clonedMetadata =
@@ -379,6 +368,8 @@ private RootNode buildRootNode(Map<String, MetricDefinition> metrics) {
379368
private boolean anyMetricWithTooManyDataPoints(RootNode node) {
380369
return node.metrics().values().stream()
381370
.anyMatch(
382-
metric -> metric.getValues().size() > Constants.MAX_DATAPOINTS_PER_METRIC);
371+
metric ->
372+
metric.getMetricValuesOverSize(Constants.MAX_DATAPOINTS_PER_METRIC)
373+
!= null);
383374
}
384375
}

0 commit comments

Comments
 (0)