Skip to content

Commit 083a4d8

Browse files
millemsdagnir
authored andcommitted
Updated metric publishing to address internal review comments.
Also fixed an issue where multiple parts of the SDK were ignoring the "alternate" request ID.
1 parent c4346d2 commit 083a4d8

File tree

50 files changed

+869
-368
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+869
-368
lines changed

core/aws-core/src/main/java/software/amazon/awssdk/awscore/eventstream/EventStreamAsyncResponseTransformer.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import static java.util.Collections.singletonList;
1919
import static software.amazon.awssdk.core.http.HttpResponseHandler.X_AMZN_REQUEST_ID_HEADER;
20+
import static software.amazon.awssdk.core.http.HttpResponseHandler.X_AMZN_REQUEST_ID_HEADERS;
2021
import static software.amazon.awssdk.core.http.HttpResponseHandler.X_AMZ_ID_2_HEADER;
2122
import static software.amazon.awssdk.utils.FunctionalUtils.runAndLogError;
2223

@@ -49,6 +50,7 @@
4950
import software.amazon.awssdk.http.SdkCancellationException;
5051
import software.amazon.awssdk.http.SdkHttpFullResponse;
5152
import software.amazon.awssdk.utils.BinaryUtils;
53+
import software.amazon.awssdk.utils.http.SdkHttpUtils;
5254
import software.amazon.eventstream.Message;
5355
import software.amazon.eventstream.MessageDecoder;
5456

@@ -193,9 +195,10 @@ public CompletableFuture<Void> prepare() {
193195
@Override
194196
public void onResponse(SdkResponse response) {
195197
if (response != null && response.sdkHttpResponse() != null) {
196-
this.requestId = response.sdkHttpResponse()
197-
.firstMatchingHeader(X_AMZN_REQUEST_ID_HEADER)
198-
.orElse(null);
198+
this.requestId = SdkHttpUtils.firstMatchingHeaderFromCollection(response.sdkHttpResponse().headers(),
199+
X_AMZN_REQUEST_ID_HEADERS)
200+
.orElse(null);
201+
199202
this.extendedRequestId = response.sdkHttpResponse()
200203
.firstMatchingHeader(X_AMZ_ID_2_HEADER)
201204
.orElse(null);
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.metrics;
17+
18+
import software.amazon.awssdk.annotations.SdkPublicApi;
19+
import software.amazon.awssdk.utils.Logger;
20+
21+
/**
22+
* An implementation of {@link MetricPublisher} that writes all published metrics to the logs at the INFO level under the
23+
* {@code software.amazon.awssdk.metrics.LoggingMetricPublisher} namespace.
24+
*/
25+
@SdkPublicApi
26+
public final class LoggingMetricPublisher implements MetricPublisher {
27+
private static final Logger LOGGER = Logger.loggerFor(LoggingMetricPublisher.class);
28+
29+
private LoggingMetricPublisher() {
30+
}
31+
32+
public static LoggingMetricPublisher create() {
33+
return new LoggingMetricPublisher();
34+
}
35+
36+
@Override
37+
public void publish(MetricCollection metricCollection) {
38+
LOGGER.info(() -> "Metrics published: " + metricCollection);
39+
}
40+
41+
@Override
42+
public void close() {
43+
}
44+
}

core/metrics-spi/src/main/java/software/amazon/awssdk/metrics/MetricCategory.java

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,33 +25,29 @@
2525
*/
2626
@SdkPublicApi
2727
public enum MetricCategory {
28-
2928
/**
30-
* All metrics defined by the SDK are classified under this category at a minimum. If the metrics feature is enabled
31-
* but the category to collect is not, only metrics that are classified under this category are collected by the SDK
29+
* Metrics collected by the core SDK are classified under this category.
3230
*/
33-
DEFAULT("Default"),
31+
CORE("Core"),
3432

3533
/**
3634
* Metrics collected at the http client level are classified under this category.
3735
*/
3836
HTTP_CLIENT("HttpClient"),
3937

4038
/**
41-
* Metrics specific to streaming, eventStream APIs are classified under this category.
39+
* Metrics specified by the customer should be classified under this category.
4240
*/
43-
STREAMING("Streaming"),
41+
CUSTOM("Custom"),
4442

4543
/**
4644
* This is an umbrella category (provided for convenience) that records metrics belonging to every category
4745
* defined in this enum. Clients who wish to collect lot of SDK metrics data should use this.
4846
* <p>
49-
* Note: Enabling this option is verbose and can be expensive based on the platform the metrics are uploaded to.
50-
* Please make sure you need all this data before using this category.
47+
* Note: Enabling this option along with {@link MetricLevel#TRACE} is verbose and can be expensive based on the platform
48+
* the metrics are uploaded to. Please make sure you need all this data before using this category.
5149
*/
52-
ALL("All")
53-
54-
;
50+
ALL("All");
5551

5652
private final String value;
5753

core/metrics-spi/src/main/java/software/amazon/awssdk/metrics/MetricCollection.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
import java.time.Instant;
1919
import java.util.List;
20+
import java.util.stream.Stream;
21+
import java.util.stream.StreamSupport;
2022
import software.amazon.awssdk.annotations.SdkPublicApi;
2123

2224
/**
@@ -29,6 +31,13 @@ public interface MetricCollection extends Iterable<MetricRecord<?>> {
2931
*/
3032
String name();
3133

34+
/**
35+
* Return a stream of records in this collection.
36+
*/
37+
default Stream<MetricRecord<?>> stream() {
38+
return StreamSupport.stream(spliterator(), false);
39+
}
40+
3241
/**
3342
* Return all the values of the given metric.
3443
*
@@ -43,6 +52,16 @@ public interface MetricCollection extends Iterable<MetricRecord<?>> {
4352
*/
4453
List<MetricCollection> children();
4554

55+
/**
56+
* Return all of the {@link #children()} with a specific name.
57+
*
58+
* @param name The name by which we will filter {@link #children()}.
59+
* @return The child metric collections that have the provided name.
60+
*/
61+
default Stream<MetricCollection> childrenWithName(String name) {
62+
return children().stream().filter(c -> c.name().equals(name));
63+
}
64+
4665
/**
4766
* @return The time at which this collection was created.
4867
*/
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
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+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.metrics;
17+
18+
import software.amazon.awssdk.annotations.SdkPublicApi;
19+
20+
/**
21+
* The {@code MetricLevel} associated with a {@link SdkMetric}, similar to log levels, defines the 'scenario' in which the metric
22+
* is useful. This makes it easy to reduce the cost of metric publishing (e.g. by setting it to {@link #INFO}), and then increase
23+
* it when additional data level is needed for debugging purposes (e.g. by setting it to {@link #TRACE}.
24+
*/
25+
@SdkPublicApi
26+
public enum MetricLevel {
27+
/**
28+
* The metric level that includes every other metric level, as well as some highly-technical metrics that may only be useful
29+
* in very specific performance or failure scenarios.
30+
*/
31+
TRACE,
32+
33+
/**
34+
* The "default" metric level that includes metrics that are useful for identifying <i>why</i> errors or performance issues
35+
* are occurring within the SDK. This excludes technical metrics that are only useful in very specific performance or failure
36+
* scenarios.
37+
*/
38+
INFO,
39+
40+
/**
41+
* Includes metrics that report <i>when</i> API call errors are occurring within the SDK. This <b>does not</b> include all
42+
* of the information that may be generally useful when debugging <i>why</i> errors are occurring (e.g. latency).
43+
*/
44+
ERROR;
45+
46+
public boolean includesLevel(MetricLevel level) {
47+
return this.compareTo(level) <= 0;
48+
}
49+
}

core/metrics-spi/src/main/java/software/amazon/awssdk/metrics/NoOpMetricCollector.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,12 @@
1616
package software.amazon.awssdk.metrics;
1717

1818
import software.amazon.awssdk.annotations.SdkPublicApi;
19-
import software.amazon.awssdk.utils.Logger;
2019

2120
/**
2221
* A metric collector that doesn't do anything.
2322
*/
2423
@SdkPublicApi
2524
public final class NoOpMetricCollector implements MetricCollector {
26-
private static final Logger log = Logger.loggerFor(NoOpMetricCollector.class);
2725
private static final NoOpMetricCollector INSTANCE = new NoOpMetricCollector();
2826

2927
private NoOpMetricCollector() {
@@ -36,7 +34,6 @@ public String name() {
3634

3735
@Override
3836
public <T> void reportMetric(SdkMetric<T> metric, T data) {
39-
log.trace(() -> "Metrics reported: " + data);
4037
}
4138

4239
@Override

core/metrics-spi/src/main/java/software/amazon/awssdk/metrics/SdkMetric.java

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ public interface SdkMetric<T> {
3737
*/
3838
Set<MetricCategory> categories();
3939

40+
/**
41+
* @return The level of this metric.
42+
*/
43+
MetricLevel level();
44+
4045
/**
4146
* @return The class of the value associated with this metric.
4247
*/
@@ -52,20 +57,6 @@ public interface SdkMetric<T> {
5257
*/
5358
T convertValue(Object o);
5459

55-
/**
56-
* Create a new metric under the {@link MetricCategory#DEFAULT} category.
57-
*
58-
* @param name The name of this metric.
59-
* @param clzz The class of the object containing the associated value for this metric.
60-
* @param <T> The type of the object containing the associated value for this metric.
61-
* @return The created metric.
62-
*
63-
* @throws IllegalArgumentException If a metric of the same name has already been created.
64-
*/
65-
static <T> SdkMetric<T> create(String name, Class<T> clzz) {
66-
return DefaultSdkMetric.create(name, clzz, MetricCategory.DEFAULT);
67-
}
68-
6960
/**
7061
* Create a new metric.
7162
*
@@ -78,8 +69,8 @@ static <T> SdkMetric<T> create(String name, Class<T> clzz) {
7869
*
7970
* @throws IllegalArgumentException If a metric of the same name has already been created.
8071
*/
81-
static <T> SdkMetric<T> create(String name, Class<T> clzz, MetricCategory c1, MetricCategory... cn) {
82-
return DefaultSdkMetric.create(name, clzz, c1, cn);
72+
static <T> SdkMetric<T> create(String name, Class<T> clzz, MetricLevel level, MetricCategory c1, MetricCategory... cn) {
73+
return DefaultSdkMetric.create(name, clzz, level, c1, cn);
8374
}
8475

8576
/**
@@ -93,7 +84,7 @@ static <T> SdkMetric<T> create(String name, Class<T> clzz, MetricCategory c1, Me
9384
*
9485
* @throws IllegalArgumentException If a metric of the same name has already been created.
9586
*/
96-
static <T> SdkMetric<T> create(String name, Class<T> clzz, Set<MetricCategory> categories) {
97-
return DefaultSdkMetric.create(name, clzz, categories);
87+
static <T> SdkMetric<T> create(String name, Class<T> clzz, MetricLevel level, Set<MetricCategory> categories) {
88+
return DefaultSdkMetric.create(name, clzz, level, categories);
9889
}
9990
}

core/metrics-spi/src/main/java/software/amazon/awssdk/metrics/internal/DefaultSdkMetric.java

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import software.amazon.awssdk.annotations.SdkInternalApi;
2525
import software.amazon.awssdk.annotations.SdkTestInternalApi;
2626
import software.amazon.awssdk.metrics.MetricCategory;
27+
import software.amazon.awssdk.metrics.MetricLevel;
2728
import software.amazon.awssdk.metrics.SdkMetric;
2829
import software.amazon.awssdk.utils.AttributeMap;
2930
import software.amazon.awssdk.utils.ToString;
@@ -36,32 +37,42 @@ public final class DefaultSdkMetric<T> extends AttributeMap.Key<T> implements Sd
3637
private final String name;
3738
private final Class<T> clzz;
3839
private final Set<MetricCategory> categories;
40+
private final MetricLevel level;
3941

40-
private DefaultSdkMetric(String name, Class<T> clzz, Set<MetricCategory> categories) {
42+
private DefaultSdkMetric(String name, Class<T> clzz, MetricLevel level, Set<MetricCategory> categories) {
4143
super(clzz);
4244
this.name = Validate.notBlank(name, "name must not be blank");
4345
this.clzz = Validate.notNull(clzz, "clzz must not be null");
46+
this.level = Validate.notNull(level, "level must not be null");
4447
Validate.notEmpty(categories, "categories must not be empty");
4548
this.categories = EnumSet.copyOf(categories);
4649
}
4750

4851
/**
4952
* @return The name of this event.
5053
*/
54+
@Override
5155
public String name() {
5256
return name;
5357
}
5458

5559
/**
5660
* @return The categories of this event.
5761
*/
62+
@Override
5863
public Set<MetricCategory> categories() {
5964
return Collections.unmodifiableSet(categories);
6065
}
6166

67+
@Override
68+
public MetricLevel level() {
69+
return level;
70+
}
71+
6272
/**
6373
* @return The class of the value associated with this event.
6474
*/
75+
@Override
6576
public Class<T> valueClass() {
6677
return clzz;
6778
}
@@ -106,13 +117,14 @@ public String toString() {
106117
*
107118
* @throws IllegalArgumentException If a metric of the same name has already been created.
108119
*/
109-
public static <T> SdkMetric<T> create(String name, Class<T> clzz, MetricCategory c1, MetricCategory... cn) {
120+
public static <T> SdkMetric<T> create(String name, Class<T> clzz, MetricLevel level,
121+
MetricCategory c1, MetricCategory... cn) {
110122
Stream<MetricCategory> categoryStream = Stream.of(c1);
111123
if (cn != null) {
112124
categoryStream = Stream.concat(categoryStream, Stream.of(cn));
113125
}
114126
Set<MetricCategory> categories = categoryStream.collect(Collectors.toSet());
115-
return create(name, clzz, categories);
127+
return create(name, clzz, level, categories);
116128
}
117129

118130
/**
@@ -126,9 +138,9 @@ public static <T> SdkMetric<T> create(String name, Class<T> clzz, MetricCategory
126138
*
127139
* @throws IllegalArgumentException If a metric of the same name has already been created.
128140
*/
129-
public static <T> SdkMetric<T> create(String name, Class<T> clzz, Set<MetricCategory> categories) {
141+
public static <T> SdkMetric<T> create(String name, Class<T> clzz, MetricLevel level, Set<MetricCategory> categories) {
130142
Validate.noNullElements(categories, "categories must not contain null elements");
131-
SdkMetric<T> event = new DefaultSdkMetric<>(name, clzz, categories);
143+
SdkMetric<T> event = new DefaultSdkMetric<>(name, clzz, level, categories);
132144
if (SDK_METRICS.putIfAbsent(event, Boolean.TRUE) != null) {
133145
throw new IllegalArgumentException("Metric with name " + name + " has already been created");
134146
}

0 commit comments

Comments
 (0)