Skip to content

Commit 6f5ecec

Browse files
Merge pull request #924 from commercetools/metrics-custom-attributes
support custom attributes for metrics
2 parents d67b616 + ee8b422 commit 6f5ecec

File tree

12 files changed

+342
-60
lines changed

12 files changed

+342
-60
lines changed

.git-blame-ignore-revs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ d0129c1095216d5c830900c8a6223ef5d4274de1
66
352051999507bd78542e177d67ce1548a0752691
77
bbe9f971763ca1b27687a6a51067a385a0d23b04
88
de95c481329aa8b821e6e71ac35c1b8bc67e3e86
9+
78c44064f4ec15091bde7a2dc590aa2b3a99341d

commercetools/commercetools-monitoring-datadog/src/main/java/com/commercetools/monitoring/datadog/DatadogMiddleware.java

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,16 @@
22
package com.commercetools.monitoring.datadog;
33

44
import static com.commercetools.monitoring.datadog.DatadogUtils.*;
5+
import static java.lang.String.format;
56

67
import java.time.Duration;
78
import java.time.Instant;
9+
import java.util.Collection;
10+
import java.util.Collections;
11+
import java.util.Map;
812
import java.util.concurrent.CompletableFuture;
913
import java.util.function.Function;
14+
import java.util.stream.Collectors;
1015

1116
import com.datadog.api.client.ApiClient;
1217
import com.datadog.api.client.ApiException;
@@ -40,12 +45,26 @@ public class DatadogMiddleware implements TelemetryMiddleware {
4045

4146
private final MetricsApi apiInstance;
4247

48+
private final Collection<String> tags;
49+
4350
public DatadogMiddleware(final ApiClient ddApiClient) {
44-
this.apiInstance = new MetricsApi(ddApiClient);
51+
this(new MetricsApi(ddApiClient));
52+
}
53+
54+
public DatadogMiddleware(final ApiClient ddApiClient, final Map<String, String> tags) {
55+
this(new MetricsApi(ddApiClient), tags);
4556
}
4657

4758
public DatadogMiddleware(final MetricsApi apiInstance) {
59+
this(apiInstance, Collections.emptyMap());
60+
}
61+
62+
public DatadogMiddleware(final MetricsApi apiInstance, final Map<String, String> tags) {
4863
this.apiInstance = apiInstance;
64+
this.tags = tags.entrySet()
65+
.stream()
66+
.map(entry -> format("%s:%s", entry.getKey(), entry.getValue()))
67+
.collect(Collectors.toList());
4968
}
5069

5170
@Override
@@ -65,10 +84,10 @@ else if (throwable instanceof ApiHttpException && ((ApiHttpException) throwable)
6584
}
6685
try {
6786
submitClientDurationMetric(request, apiInstance, Duration.between(start, Instant.now()).toMillis(),
68-
statusCode);
69-
submitTotalRequestsMetric(request, apiInstance, statusCode);
87+
statusCode, tags);
88+
submitTotalRequestsMetric(request, apiInstance, statusCode, tags);
7089
if (statusCode >= 400 || throwable != null) {
71-
submitErrorRequestsMetric(request, apiInstance, statusCode);
90+
submitErrorRequestsMetric(request, apiInstance, statusCode, tags);
7291
}
7392
}
7493
catch (ApiException e) {

commercetools/commercetools-monitoring-datadog/src/main/java/com/commercetools/monitoring/datadog/DatadogResponseSerializer.java

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,14 @@
33

44
import static com.commercetools.monitoring.datadog.DatadogUtils.submitJsonDeserializationMetric;
55
import static com.commercetools.monitoring.datadog.DatadogUtils.submitJsonSerializationMetric;
6+
import static java.lang.String.format;
67

78
import java.time.Duration;
89
import java.time.Instant;
10+
import java.util.Collection;
11+
import java.util.Collections;
12+
import java.util.Map;
13+
import java.util.stream.Collectors;
914

1015
import com.datadog.api.client.ApiClient;
1116
import com.datadog.api.client.v2.api.MetricsApi;
@@ -25,22 +30,37 @@ public class DatadogResponseSerializer implements ResponseSerializer {
2530

2631
private final MetricsApi apiInstance;
2732

28-
public DatadogResponseSerializer(final ResponseSerializer serializer, final MetricsApi apiInstance) {
33+
private final Collection<String> tags;
34+
35+
public DatadogResponseSerializer(final ResponseSerializer serializer, final MetricsApi apiInstance,
36+
final Map<String, String> tags) {
2937
this.serializer = serializer;
3038
this.apiInstance = apiInstance;
39+
this.tags = tags.entrySet()
40+
.stream()
41+
.map(entry -> format("%s:%s", entry.getKey(), entry.getValue()))
42+
.collect(Collectors.toList());
43+
}
44+
45+
public DatadogResponseSerializer(final ResponseSerializer serializer, final MetricsApi apiInstance) {
46+
this(serializer, apiInstance, Collections.emptyMap());
47+
}
48+
49+
public DatadogResponseSerializer(final ResponseSerializer serializer, final ApiClient ddApiClient,
50+
final Map<String, String> tags) {
51+
this(serializer, new MetricsApi(ddApiClient), tags);
3152
}
3253

3354
public DatadogResponseSerializer(final ResponseSerializer serializer, final ApiClient ddApiClient) {
34-
this.serializer = serializer;
35-
this.apiInstance = new MetricsApi(ddApiClient);
55+
this(serializer, new MetricsApi(ddApiClient), Collections.emptyMap());
3656
}
3757

3858
@Override
3959
public <O> ApiHttpResponse<O> convertResponse(ApiHttpResponse<byte[]> response, Class<O> outputType) {
4060
Instant start = Instant.now();
4161
ApiHttpResponse<O> result = serializer.convertResponse(response, outputType);
4262
double durationInMillis = Duration.between(start, Instant.now()).toNanos() / 1_000_000.0;
43-
submitJsonDeserializationMetric(apiInstance, (double) durationInMillis, outputType.getCanonicalName());
63+
submitJsonDeserializationMetric(apiInstance, (double) durationInMillis, outputType.getCanonicalName(), tags);
4464
return result;
4565
}
4666

@@ -49,7 +69,7 @@ public <O> ApiHttpResponse<O> convertResponse(ApiHttpResponse<byte[]> response,
4969
Instant start = Instant.now();
5070
ApiHttpResponse<O> result = serializer.convertResponse(response, outputType);
5171
double durationInMillis = Duration.between(start, Instant.now()).toNanos() / 1_000_000.0;
52-
submitJsonDeserializationMetric(apiInstance, durationInMillis, outputType.toString());
72+
submitJsonDeserializationMetric(apiInstance, durationInMillis, outputType.toString(), tags);
5373
return result;
5474
}
5575

@@ -58,7 +78,7 @@ public <O> ApiHttpResponse<O> convertResponse(ApiHttpResponse<byte[]> response,
5878
Instant start = Instant.now();
5979
ApiHttpResponse<O> result = serializer.convertResponse(response, outputType);
6080
double durationInMillis = Duration.between(start, Instant.now()).toNanos() / 1_000_000.0;
61-
submitJsonDeserializationMetric(apiInstance, durationInMillis, outputType.getType().getTypeName());
81+
submitJsonDeserializationMetric(apiInstance, durationInMillis, outputType.getType().getTypeName(), tags);
6282
return result;
6383
}
6484

@@ -67,7 +87,7 @@ public byte[] toJsonByteArray(Object value) throws JsonProcessingException {
6787
Instant start = Instant.now();
6888
byte[] result = serializer.toJsonByteArray(value);
6989
double durationInMillis = Duration.between(start, Instant.now()).toNanos() / 1_000_000.0;
70-
submitJsonSerializationMetric(apiInstance, durationInMillis, value.getClass().getCanonicalName());
90+
submitJsonSerializationMetric(apiInstance, durationInMillis, value.getClass().getCanonicalName(), tags);
7191
return result;
7292
}
7393

commercetools/commercetools-monitoring-datadog/src/main/java/com/commercetools/monitoring/datadog/DatadogUtils.java

Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@
55
import static java.lang.String.format;
66

77
import java.time.OffsetDateTime;
8-
import java.util.Arrays;
9-
import java.util.Collections;
10-
import java.util.List;
8+
import java.util.*;
119

1210
import com.datadog.api.client.ApiException;
1311
import com.datadog.api.client.v2.api.MetricsApi;
@@ -27,75 +25,82 @@ public class DatadogUtils {
2725
private static final Logger logger = LoggerFactory.getLogger(DatadogMiddleware.class);
2826

2927
protected static void submitClientDurationMetric(final ApiHttpRequest request, final MetricsApi apiInstance,
30-
final double durationInMillis, final ApiHttpResponse<byte[]> response) throws ApiException {
31-
submitClientDurationMetric(request, apiInstance, durationInMillis, response.getStatusCode());
28+
final double durationInMillis, final ApiHttpResponse<byte[]> response, final Collection<String> tags)
29+
throws ApiException {
30+
submitClientDurationMetric(request, apiInstance, durationInMillis, response.getStatusCode(), tags);
3231
}
3332

3433
protected static void submitClientDurationMetric(final ApiHttpRequest request, final MetricsApi apiInstance,
35-
final double durationInMillis, final int statusCode) throws ApiException {
34+
final double durationInMillis, final int statusCode, final Collection<String> tags) throws ApiException {
3635
final String name = PREFIX + "." + CLIENT_DURATION;
3736
final MetricIntakeType type = MetricIntakeType.UNSPECIFIED;
38-
submitMetricWithHttpTags(name, durationInMillis, type, "ms", request, apiInstance, statusCode);
37+
submitMetricWithHttpTags(name, durationInMillis, type, "ms", request, apiInstance, statusCode, tags);
3938
}
4039

4140
protected static void submitErrorRequestsMetric(final ApiHttpRequest request, final MetricsApi apiInstance,
42-
final ApiHttpResponse<byte[]> response) throws ApiException {
43-
submitErrorRequestsMetric(request, apiInstance, response.getStatusCode());
41+
final ApiHttpResponse<byte[]> response, final Collection<String> tags) throws ApiException {
42+
submitErrorRequestsMetric(request, apiInstance, response.getStatusCode(), tags);
4443
}
4544

4645
protected static void submitErrorRequestsMetric(final ApiHttpRequest request, final MetricsApi apiInstance,
47-
final int statusCode) throws ApiException {
46+
final int statusCode, final Collection<String> tags) throws ApiException {
4847
final String name = PREFIX + "." + CLIENT_REQUEST_ERROR;
4948
final MetricIntakeType count = MetricIntakeType.COUNT;
50-
submitMetricWithHttpTags(name, 1.0, count, "count", request, apiInstance, statusCode);
49+
submitMetricWithHttpTags(name, 1.0, count, "count", request, apiInstance, statusCode, tags);
5150
}
5251

5352
protected static void submitTotalRequestsMetric(final ApiHttpRequest request, final MetricsApi apiInstance,
54-
final ApiHttpResponse<byte[]> response) throws ApiException {
55-
submitTotalRequestsMetric(request, apiInstance, response.getStatusCode());
53+
final ApiHttpResponse<byte[]> response, final Collection<String> tags) throws ApiException {
54+
submitTotalRequestsMetric(request, apiInstance, response.getStatusCode(), tags);
5655
}
5756

5857
protected static void submitTotalRequestsMetric(final ApiHttpRequest request, final MetricsApi apiInstance,
59-
final int statusCode) throws ApiException {
58+
final int statusCode, final Collection<String> tags) throws ApiException {
6059
final String name = PREFIX + "." + CLIENT_REQUEST_TOTAL;
6160
final MetricIntakeType count = MetricIntakeType.COUNT;
62-
submitMetricWithHttpTags(name, 1.0, count, "count", request, apiInstance, statusCode);
61+
submitMetricWithHttpTags(name, 1.0, count, "count", request, apiInstance, statusCode, tags);
6362
}
6463

6564
private static void submitMetricWithHttpTags(final String name, final double value, final MetricIntakeType type,
6665
final String unit, final ApiHttpRequest request, final MetricsApi apiInstance,
67-
final ApiHttpResponse<byte[]> response) throws ApiException {
68-
submitMetricWithHttpTags(name, value, type, unit, request, apiInstance, response.getStatusCode());
66+
final ApiHttpResponse<byte[]> response, final Collection<String> tags) throws ApiException {
67+
submitMetricWithHttpTags(name, value, type, unit, request, apiInstance, response.getStatusCode(), tags);
6968
}
7069

7170
private static void submitMetricWithHttpTags(final String name, final double value, final MetricIntakeType type,
72-
final String unit, final ApiHttpRequest request, final MetricsApi apiInstance, final int statusCode)
73-
throws ApiException {
74-
final List<String> tags = Arrays.asList(format("%s:%s", HTTP_RESPONSE_STATUS_CODE, statusCode),
75-
format("%s:%s", HTTP_REQUEST_METHOD, request.getMethod().name()),
76-
format("%s:%s", SERVER_ADDRESS, request.getUri().getHost()));
71+
final String unit, final ApiHttpRequest request, final MetricsApi apiInstance, final int statusCode,
72+
final Collection<String> tags) throws ApiException {
73+
final List<String> currentTags = new ArrayList<>(tags);
74+
currentTags.add(format("%s:%s", HTTP_RESPONSE_STATUS_CODE, statusCode));
75+
currentTags.add(format("%s:%s", HTTP_REQUEST_METHOD, request.getMethod().name()));
76+
currentTags.add(format("%s:%s", SERVER_ADDRESS, request.getUri().getHost()));
7777
if (request.getUri().getPort() > 0) {
78-
tags.add(format("%s:%s", SERVER_PORT, request.getUri().getPort()));
78+
currentTags.add(format("%s:%s", SERVER_PORT, request.getUri().getPort()));
7979
}
80-
submitMetric(apiInstance, name, value, type, unit, tags);
80+
submitMetric(apiInstance, name, value, type, unit, currentTags);
8181
}
8282

8383
protected static void submitJsonSerializationMetric(final MetricsApi apiInstance, final double durationInMillis,
84-
final String responseBodyType) {
84+
final String responseBodyType, final Collection<String> tags) {
8585
try {
86+
final List<String> currentTags = new ArrayList<>(tags);
87+
currentTags.add(format("%s:%s", RESPONSE_BODY_TYPE, responseBodyType));
8688
submitMetric(apiInstance, PREFIX + "." + JSON_SERIALIZATION, durationInMillis, MetricIntakeType.UNSPECIFIED,
87-
"ms", Arrays.asList(format("%s:%s", RESPONSE_BODY_TYPE, responseBodyType)));
89+
"ms", currentTags);
8890
}
8991
catch (ApiException exception) {
9092
logger.warn("Failed to submit commercetools json serialization metric", exception);
9193
}
9294
}
9395

9496
protected static void submitJsonDeserializationMetric(final MetricsApi apiInstance, final double durationInMillis,
95-
final String requestBodyType) {
97+
final String requestBodyType, final Collection<String> tags) {
9698
try {
99+
final List<String> currentTags = new ArrayList<>(tags);
100+
currentTags.add(format("%s:%s", REQUEST_BODY_TYPE, requestBodyType));
101+
97102
submitMetric(apiInstance, PREFIX + "." + JSON_DESERIALIZATION, durationInMillis,
98-
MetricIntakeType.UNSPECIFIED, "ms", Arrays.asList(format("%s:%s", REQUEST_BODY_TYPE, requestBodyType)));
103+
MetricIntakeType.UNSPECIFIED, "ms", currentTags);
99104
}
100105
catch (ApiException exception) {
101106
logger.warn("Failed to submit commercetools json deserialization metric", exception);

commercetools/commercetools-monitoring-datadog/src/main/java/com/commercetools/monitoring/datadog/statsd/DatadogMiddleware.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66

77
import java.time.Duration;
88
import java.time.Instant;
9-
import java.util.ArrayList;
10-
import java.util.List;
9+
import java.util.*;
1110
import java.util.concurrent.CompletableFuture;
1211
import java.util.function.Function;
12+
import java.util.stream.Collectors;
1313

1414
import com.timgroup.statsd.StatsDClient;
1515

@@ -41,8 +41,18 @@ public class DatadogMiddleware implements TelemetryMiddleware {
4141

4242
private final StatsDClient statsDClient;
4343

44+
private final Collection<String> tags;
45+
4446
public DatadogMiddleware(final StatsDClient datadogStatsDClient) {
47+
this(datadogStatsDClient, Collections.emptyMap());
48+
}
49+
50+
public DatadogMiddleware(final StatsDClient datadogStatsDClient, final Map<String, String> tags) {
4551
this.statsDClient = datadogStatsDClient;
52+
this.tags = tags.entrySet()
53+
.stream()
54+
.map(entry -> format("%s:%s", entry.getKey(), entry.getValue()))
55+
.collect(Collectors.toList());
4656
}
4757

4858
@Override
@@ -65,6 +75,7 @@ else if (throwable instanceof ApiHttpException && ((ApiHttpException) throwable)
6575
tags.add(format("%s:%s", HTTP_RESPONSE_STATUS_CODE, statusCode));
6676
tags.add(format("%s:%s", HTTP_REQUEST_METHOD, request.getMethod().name()));
6777
tags.add(format("%s:%s", SERVER_ADDRESS, request.getUri().getHost()));
78+
tags.addAll(this.tags);
6879
if (request.getUri().getPort() > 0) {
6980
tags.add(format("%s:%s", SERVER_PORT, request.getUri().getPort()));
7081
}

commercetools/commercetools-monitoring-datadog/src/main/java/com/commercetools/monitoring/datadog/statsd/DatadogResponseSerializer.java

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
import java.time.Duration;
88
import java.time.Instant;
9+
import java.util.*;
10+
import java.util.stream.Collectors;
911

1012
import com.fasterxml.jackson.core.JsonProcessingException;
1113
import com.fasterxml.jackson.core.type.TypeReference;
@@ -24,18 +26,32 @@ public class DatadogResponseSerializer implements ResponseSerializer {
2426

2527
private final StatsDClient statsDClient;
2628

29+
private final Collection<String> tags;
30+
2731
public DatadogResponseSerializer(final ResponseSerializer serializer, final StatsDClient datadogStatsDClient) {
32+
this(serializer, datadogStatsDClient, Collections.emptyMap());
33+
}
34+
35+
public DatadogResponseSerializer(final ResponseSerializer serializer, final StatsDClient datadogStatsDClient,
36+
final Map<String, String> tags) {
2837
this.serializer = serializer;
2938
this.statsDClient = datadogStatsDClient;
39+
this.tags = tags.entrySet()
40+
.stream()
41+
.map(entry -> format("%s:%s", entry.getKey(), entry.getValue()))
42+
.collect(Collectors.toList());
3043
}
3144

3245
@Override
3346
public <O> ApiHttpResponse<O> convertResponse(ApiHttpResponse<byte[]> response, Class<O> outputType) {
3447
Instant start = Instant.now();
3548
ApiHttpResponse<O> result = serializer.convertResponse(response, outputType);
3649
double durationInMillis = Duration.between(start, Instant.now()).toNanos() / 1_000_000.0;
50+
final Collection<String> tags = new ArrayList<>(this.tags);
51+
tags.add(format("%s:%s", RESPONSE_BODY_TYPE, outputType.getCanonicalName()));
52+
3753
this.statsDClient.recordHistogramValue(PREFIX + "." + JSON_DESERIALIZATION, durationInMillis,
38-
format("%s:%s", RESPONSE_BODY_TYPE, outputType.getCanonicalName()));
54+
tags.toArray(new String[0]));
3955
return result;
4056
}
4157

@@ -44,8 +60,11 @@ public <O> ApiHttpResponse<O> convertResponse(ApiHttpResponse<byte[]> response,
4460
Instant start = Instant.now();
4561
ApiHttpResponse<O> result = serializer.convertResponse(response, outputType);
4662
double durationInMillis = Duration.between(start, Instant.now()).toNanos() / 1_000_000.0;
63+
final Collection<String> tags = new ArrayList<>(this.tags);
64+
tags.add(format("%s:%s", RESPONSE_BODY_TYPE, outputType.toString()));
65+
4766
this.statsDClient.recordHistogramValue(PREFIX + "." + JSON_DESERIALIZATION, durationInMillis,
48-
format("%s:%s", RESPONSE_BODY_TYPE, outputType.toString()));
67+
tags.toArray(new String[0]));
4968
return result;
5069
}
5170

@@ -54,8 +73,11 @@ public <O> ApiHttpResponse<O> convertResponse(ApiHttpResponse<byte[]> response,
5473
Instant start = Instant.now();
5574
ApiHttpResponse<O> result = serializer.convertResponse(response, outputType);
5675
double durationInMillis = Duration.between(start, Instant.now()).toNanos() / 1_000_000.0;
76+
final Collection<String> tags = new ArrayList<>(this.tags);
77+
tags.add(format("%s:%s", RESPONSE_BODY_TYPE, outputType.getType().getTypeName()));
78+
5779
this.statsDClient.recordHistogramValue(PREFIX + "." + JSON_DESERIALIZATION, durationInMillis,
58-
format("%s:%s", RESPONSE_BODY_TYPE, outputType.getType().getTypeName()));
80+
tags.toArray(new String[0]));
5981
return result;
6082
}
6183

@@ -64,8 +86,11 @@ public byte[] toJsonByteArray(Object value) throws JsonProcessingException {
6486
Instant start = Instant.now();
6587
byte[] result = serializer.toJsonByteArray(value);
6688
double durationInMillis = Duration.between(start, Instant.now()).toNanos() / 1_000_000.0;
89+
final Collection<String> tags = new ArrayList<>(this.tags);
90+
tags.add(format("%s:%s", RESPONSE_BODY_TYPE, value.getClass().getCanonicalName()));
91+
6792
this.statsDClient.recordHistogramValue(PREFIX + "." + JSON_SERIALIZATION, durationInMillis,
68-
format("%s:%s", REQUEST_BODY_TYPE, value.getClass().getCanonicalName()));
93+
tags.toArray(new String[0]));
6994
return result;
7095
}
7196

0 commit comments

Comments
 (0)