Skip to content

Commit c5d5f60

Browse files
committed
Added Statistic Set
1 parent 9fd3833 commit c5d5f60

File tree

9 files changed

+643
-20
lines changed

9 files changed

+643
-20
lines changed

src/main/java/software/amazon/cloudwatchlogs/emf/logger/MetricsLogger.java

Lines changed: 81 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.concurrent.CompletableFuture;
2121
import java.util.concurrent.locks.ReentrantReadWriteLock;
2222
import java.util.function.Supplier;
23+
2324
import lombok.Getter;
2425
import lombok.Setter;
2526
import lombok.extern.slf4j.Slf4j;
@@ -30,11 +31,13 @@
3031
import software.amazon.cloudwatchlogs.emf.exception.InvalidMetricException;
3132
import software.amazon.cloudwatchlogs.emf.exception.InvalidNamespaceException;
3233
import software.amazon.cloudwatchlogs.emf.exception.InvalidTimestampException;
34+
import software.amazon.cloudwatchlogs.emf.model.AggregationType;
3335
import software.amazon.cloudwatchlogs.emf.model.DimensionSet;
3436
import software.amazon.cloudwatchlogs.emf.model.MetricsContext;
3537
import software.amazon.cloudwatchlogs.emf.model.StorageResolution;
3638
import software.amazon.cloudwatchlogs.emf.model.Unit;
3739
import software.amazon.cloudwatchlogs.emf.sinks.ISink;
40+
import software.amazon.cloudwatchlogs.emf.model.AggregationType;
3841

3942
/**
4043
* A metrics logger. Use this interface to publish logs to CloudWatch Logs and extract metrics to
@@ -45,6 +48,7 @@ public class MetricsLogger {
4548
private MetricsContext context;
4649
private CompletableFuture<Environment> environmentFuture;
4750
private EnvironmentProvider environmentProvider;
51+
@Getter @Setter private volatile AggregationType defaultAggregationType = AggregationType.NONE;
4852
/**
4953
* This lock is used to create an internal sync context for flush() method in multi-threaded
5054
* situations. Flush() acquires write lock, other methods (accessing mutable shared data with
@@ -198,11 +202,11 @@ public MetricsLogger resetDimensions(boolean useDefault) {
198202
* @throws InvalidMetricException if the metric is invalid
199203
*/
200204
public MetricsLogger putMetric(
201-
String key, double value, Unit unit, StorageResolution storageResolution)
205+
String key, double value, Unit unit, StorageResolution storageResolution, AggregationType aggregationType)
202206
throws InvalidMetricException {
203207
rwl.readLock().lock();
204208
try {
205-
this.context.putMetric(key, value, unit, storageResolution);
209+
this.context.putMetric(key, value, unit, storageResolution, aggregationType);
206210
return this;
207211
} finally {
208212
rwl.readLock().unlock();
@@ -257,7 +261,81 @@ public MetricsLogger putMetric(String key, double value, Unit unit)
257261
* @throws InvalidMetricException if the metric is invalid
258262
*/
259263
public MetricsLogger putMetric(String key, double value) throws InvalidMetricException {
260-
this.putMetric(key, value, Unit.NONE, StorageResolution.STANDARD);
264+
this.putMetric(key, value, Unit.NONE, StorageResolution.STANDARD, AggregationType.NONE);
265+
return this;
266+
}
267+
268+
/**
269+
* Put a metric value. This value will be emitted to CloudWatch Metrics asynchronously and does
270+
* not contribute to your account TPS limits. The value will also be available in your
271+
* CloudWatch Logs
272+
*
273+
* @param key is the name of the metric
274+
* @param value is the value of the metric
275+
* @param unit is the unit of the metric value
276+
* @param storageResolution is the resolution of the metric
277+
* @see <a
278+
* href="https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/publishingMetrics.html#high-resolution-metrics">CloudWatch
279+
* High Resolution Metrics</a>
280+
* @return the current logger
281+
* @throws InvalidMetricException if the metric is invalid
282+
*/
283+
public MetricsLogger putMetric(
284+
String key, double value, Unit unit, StorageResolution storageResolution)
285+
throws InvalidMetricException {
286+
this.putMetric(key, value, Unit.NONE, storageResolution, AggregationType.NONE);
287+
return this;
288+
}
289+
290+
/**
291+
* Put a metric value. This value will be emitted to CloudWatch Metrics asynchronously and does
292+
* not contribute to your account TPS limits. The value will also be available in your
293+
* CloudWatch Logs
294+
*
295+
* @param key is the name of the metric
296+
* @param value is the value of the metric
297+
* @param storageResolution is the resolution of the metric
298+
* @see <a
299+
* href="https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/publishingMetrics.html#high-resolution-metrics">CloudWatch
300+
* High Resolution Metrics</a>
301+
* @return the current logger
302+
* @throws InvalidMetricException if the metric is invalid
303+
*/
304+
public MetricsLogger putMetric(String key, double value, StorageResolution storageResolution, AggregationType aggregationType)
305+
throws InvalidMetricException {
306+
this.putMetric(key, value, Unit.NONE, storageResolution, aggregationType);
307+
return this;
308+
}
309+
310+
/**
311+
* Put a metric value. This value will be emitted to CloudWatch Metrics asynchronously and does
312+
* not contribute to your account TPS limits. The value will also be available in your
313+
* CloudWatch Logs
314+
*
315+
* @param key is the name of the metric
316+
* @param value is the value of the metric
317+
* @param unit is the unit of the metric value
318+
* @return the current logger
319+
* @throws InvalidMetricException if the metric is invalid
320+
*/
321+
public MetricsLogger putMetric(String key, double value, Unit unit, AggregationType aggregationType)
322+
throws InvalidMetricException {
323+
this.putMetric(key, value, unit, StorageResolution.STANDARD, aggregationType);
324+
return this;
325+
}
326+
327+
/**
328+
* Put a metric value. This value will be emitted to CloudWatch Metrics asynchronously and does
329+
* not contribute to your account TPS limits. The value will also be available in your
330+
* CloudWatch Logs
331+
*
332+
* @param key the name of the metric
333+
* @param value the value of the metric
334+
* @return the current logger
335+
* @throws InvalidMetricException if the metric is invalid
336+
*/
337+
public MetricsLogger putMetric(String key, double value, AggregationType aggregationType) throws InvalidMetricException {
338+
this.putMetric(key, value, Unit.NONE, StorageResolution.STANDARD, aggregationType);
261339
return this;
262340
}
263341

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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+
public enum AggregationType {
20+
NONE(60),
21+
STATISTIC_SET(1),
22+
UNKNOWN_TO_SDK_VERSION(-1);
23+
24+
private final int value;
25+
26+
AggregationType(final int newValue) {
27+
value = newValue;
28+
}
29+
30+
public int getValue() {
31+
return this.value;
32+
}
33+
}

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.fasterxml.jackson.annotation.JsonProperty;
2222
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
2323
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
24+
2425
import lombok.Getter;
2526
import software.amazon.cloudwatchlogs.emf.serializers.StorageResolutionFilter;
2627
import software.amazon.cloudwatchlogs.emf.serializers.StorageResolutionSerializer;
@@ -82,5 +83,7 @@ protected void setName(String name) {
8283
protected abstract Metric getMetricValuesOverSize(int size);
8384

8485
/** @return a simplified representation of the values of this metric. */
85-
protected abstract Object getSimplifiedValues();
86+
protected Object getSimplifiedValues() {
87+
return values;
88+
}
8689
}

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

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -68,28 +68,45 @@ void putDimensionSet(DimensionSet dimensionSet) {
6868

6969
// Helper method for testing putMetric()
7070
void putMetric(String key, double value) {
71-
putMetric(key, value, Unit.NONE, StorageResolution.STANDARD);
71+
putMetric(key, value, Unit.NONE, StorageResolution.STANDARD, AggregationType.NONE);
7272
}
7373

7474
// Helper method for testing putMetric()
7575
void putMetric(String key, double value, Unit unit) {
76-
putMetric(key, value, unit, StorageResolution.STANDARD);
76+
putMetric(key, value, unit, StorageResolution.STANDARD, AggregationType.NONE);
7777
}
7878

7979
// Helper method for testing serialization
8080
void putMetric(String key, double value, StorageResolution storageResolution) {
81-
putMetric(key, value, Unit.NONE, storageResolution);
81+
putMetric(key, value, Unit.NONE, storageResolution, AggregationType.NONE);
8282
}
8383

84-
void putMetric(String key, double value, Unit unit, StorageResolution storageResolution) {
84+
void putMetric(
85+
String key,
86+
double value,
87+
Unit unit,
88+
StorageResolution storageResolution,
89+
AggregationType aggregationType) {
8590
metrics.compute(
8691
key,
8792
(k, v) -> {
8893
if (v == null) {
89-
MetricDefinitionBuilder tmp =
90-
new MetricDefinitionBuilder(unit, storageResolution, value);
91-
tmp.setName(key);
92-
return (Metric) tmp;
94+
Metric metric;
95+
switch (aggregationType) {
96+
case STATISTIC_SET:
97+
StatisticSetBuilder statisticSet =
98+
new StatisticSetBuilder(unit, storageResolution);
99+
statisticSet.addValue(value);
100+
metric = statisticSet;
101+
break;
102+
case NONE:
103+
default:
104+
metric =
105+
new MetricDefinitionBuilder(unit, storageResolution, value);
106+
break;
107+
}
108+
metric.setName(key);
109+
return (Metric) metric;
93110
} else if (v instanceof MetricBuilder) {
94111
((MetricBuilder) v).addValue(value);
95112
return v;

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

Lines changed: 101 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ public class MetricsContext {
4343
private MetricDirective metricDirective;
4444
private final Map<String, StorageResolution> metricNameAndResolutionMap =
4545
new ConcurrentHashMap<>();
46+
private final Map<String, AggregationType> metricNameAndAggregationMap =
47+
new ConcurrentHashMap<>();
4648

4749
public MetricsContext() {
4850
this(new RootNode());
@@ -112,6 +114,40 @@ public boolean hasDefaultDimensions() {
112114
return !getDefaultDimensions().getDimensionKeys().isEmpty();
113115
}
114116

117+
/**
118+
* Add a metric measurement to the context. Multiple calls using the same key will be stored as
119+
* an array of scalar values.
120+
*
121+
* <pre>{@code
122+
* metricContext.putMetric("Latency", 100, Unit.MILLISECONDS, StorageResolution.HIGH, AggregationType.NONE)
123+
* }</pre>
124+
*
125+
* @param key Name of the metric
126+
* @param value Value of the metric
127+
* @param unit The unit of the metric
128+
* @param storageResolution The resolution of the metric
129+
* @throws InvalidMetricException if the metric is invalid
130+
*/
131+
public void putMetric(
132+
String key,
133+
double value,
134+
Unit unit,
135+
StorageResolution storageResolution,
136+
AggregationType aggregationType)
137+
throws InvalidMetricException {
138+
Validator.validateMetric(
139+
key,
140+
value,
141+
unit,
142+
storageResolution,
143+
aggregationType,
144+
metricNameAndResolutionMap,
145+
metricNameAndAggregationMap);
146+
metricDirective.putMetric(key, value, unit, storageResolution, aggregationType);
147+
metricNameAndResolutionMap.put(key, storageResolution);
148+
metricNameAndAggregationMap.put(key, aggregationType);
149+
}
150+
115151
/**
116152
* Add a metric measurement to the context. Multiple calls using the same key will be stored as
117153
* an array of scalar values.
@@ -128,10 +164,9 @@ public boolean hasDefaultDimensions() {
128164
*/
129165
public void putMetric(String key, double value, Unit unit, StorageResolution storageResolution)
130166
throws InvalidMetricException {
131-
Validator.validateMetric(key, value, unit, storageResolution, metricNameAndResolutionMap);
132-
metricDirective.putMetric(key, value, unit, storageResolution);
133-
metricNameAndResolutionMap.put(key, storageResolution);
167+
putMetric(key, value, unit, storageResolution, AggregationType.NONE);
134168
}
169+
135170
/**
136171
* Add a metric measurement to the context with a storage resolution but without a unit.
137172
* Multiple calls using the same key will be stored as an array of scalar values.
@@ -147,7 +182,7 @@ public void putMetric(String key, double value, Unit unit, StorageResolution sto
147182
*/
148183
public void putMetric(String key, double value, StorageResolution storageResolution)
149184
throws InvalidMetricException {
150-
putMetric(key, value, Unit.NONE, storageResolution);
185+
putMetric(key, value, Unit.NONE, storageResolution, AggregationType.NONE);
151186
}
152187

153188
/**
@@ -164,7 +199,67 @@ public void putMetric(String key, double value, StorageResolution storageResolut
164199
* @throws InvalidMetricException if the metric is invalid
165200
*/
166201
public void putMetric(String key, double value, Unit unit) throws InvalidMetricException {
167-
putMetric(key, value, unit, StorageResolution.STANDARD);
202+
putMetric(key, value, unit, StorageResolution.STANDARD, AggregationType.NONE);
203+
}
204+
205+
/**
206+
* Add a metric measurement to the context without a unit Multiple calls using the same key will
207+
* be stored as an array of scalar values.
208+
*
209+
* <pre>{@code
210+
* metricContext.putMetric("Count", 10, AggregationType.NONE)
211+
* }</pre>
212+
*
213+
* @param key Name of the metric
214+
* @param value Value of the metric
215+
* @param aggregationType The aggregation type of the metric
216+
* @throws InvalidMetricException if the metric is invalid
217+
*/
218+
public void putMetric(String key, double value, AggregationType aggregationType)
219+
throws InvalidMetricException {
220+
putMetric(key, value, Unit.NONE, StorageResolution.STANDARD, aggregationType);
221+
}
222+
223+
/**
224+
* Add a metric measurement to the context with a storage resolution but without a unit.
225+
* Multiple calls using the same key will be stored as an array of scalar values.
226+
*
227+
* <pre>{@code
228+
* metricContext.putMetric("Latency", 100, StorageResolution.HIGH, AggregationType.NONE)
229+
* }</pre>
230+
*
231+
* @param key Name of the metric
232+
* @param value Value of the metric
233+
* @param storageResolution The resolution of the metric
234+
* @param aggregationType The aggregation type of the metric
235+
* @throws InvalidMetricException if the metric is invalid
236+
*/
237+
public void putMetric(
238+
String key,
239+
double value,
240+
StorageResolution storageResolution,
241+
AggregationType aggregationType)
242+
throws InvalidMetricException {
243+
putMetric(key, value, Unit.NONE, storageResolution, aggregationType);
244+
}
245+
246+
/**
247+
* Add a metric measurement to the context without a storage resolution. Multiple calls using
248+
* the same key will be stored as an array of scalar values.
249+
*
250+
* <pre>{@code
251+
* metricContext.putMetric("Latency", 100, Unit.MILLISECONDS, AggregationType.NONE)
252+
* }</pre>
253+
*
254+
* @param key Name of the metric
255+
* @param value Value of the metric
256+
* @param unit The unit of the metric
257+
* @param aggregationType The aggregation type of the metric
258+
* @throws InvalidMetricException if the metric is invalid
259+
*/
260+
public void putMetric(String key, double value, Unit unit, AggregationType aggregationType)
261+
throws InvalidMetricException {
262+
putMetric(key, value, unit, StorageResolution.STANDARD, aggregationType);
168263
}
169264

170265
/**
@@ -180,7 +275,7 @@ public void putMetric(String key, double value, Unit unit) throws InvalidMetricE
180275
* @throws InvalidMetricException if the metric is invalid
181276
*/
182277
public void putMetric(String key, double value) throws InvalidMetricException {
183-
putMetric(key, value, Unit.NONE, StorageResolution.STANDARD);
278+
putMetric(key, value, Unit.NONE, StorageResolution.STANDARD, AggregationType.NONE);
184279
}
185280

186281
/**

0 commit comments

Comments
 (0)