Skip to content

Commit

Permalink
add a mechanism to tag metrics from the handler context to distinguis…
Browse files Browse the repository at this point in the history
…h metrics from multiple clients
  • Loading branch information
dbyron-sf committed Oct 29, 2021
1 parent 83d916b commit 6d7af1a
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 2 deletions.
37 changes: 37 additions & 0 deletions spectator-ext-aws/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,40 @@ aws.request.httpClientPoolPendingCount | AWSRequestMetrics.Field.HttpClientPoo
Any throttling exception that occurs is tracked in a timer `aws.request.throttling` with the same
set of tags as the other metrics, and one additional tag `throttleException` containing the exception
that caused the throttling to occur.

# Tag via handler context

To help distinguish metrics from multiple clients, it's possible to specify a
[HandlerContextKey](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/handlers/HandlerContextKey.html)
for a SpectatorRequestMetricCollector. When specified, the
SpectatorRequestMetricCollector looks for a value from each request's handler
context for the given key, and, if there's a value for that key, adds a tag to
each metric of the form

`handlerContextKey.getName()`:value

One way to put information into the handler context that's the same for all
requests from a particular client is:

`````java
class MyRequestHandler extends RequestHandler2 {
@Override
public void beforeRequest(Request<?> request) {
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "myValue");
}
}
`````
and then, for an s3 client for example:

`````java
MyRequestHandler myRequestHandler = new MyRequestHandler();
AmazonS3ClientBuilder builder = AmazonS3ClientBuilder.standard();
builder.setRequestHandlers(myRequestHandler);
`````

Each request metric from the resulting AmazonS3 client willl have the tag
`HandlerContextKey.OPERATION_NAME.getName()`:myValue.

Note that a custom handler context key (e.g. new
HandlerContextKey<String>("myContextKey") works in addition to the predefined
ones in HandlerContextKey.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import com.amazonaws.Request;
import com.amazonaws.Response;
import com.amazonaws.handlers.HandlerContextKey;
import com.amazonaws.metrics.RequestMetricCollector;
import com.amazonaws.util.AWSRequestMetrics;
import com.amazonaws.util.AWSRequestMetrics.Field;
Expand Down Expand Up @@ -91,6 +92,7 @@ public class SpectatorRequestMetricCollector extends RequestMetricCollector {

private final Registry registry;
private final Map<String, String> customTags;
private final HandlerContextKey<String> handlerContextKey;

/**
* Constructs a new instance.
Expand All @@ -100,10 +102,29 @@ public SpectatorRequestMetricCollector(Registry registry) {
}

/**
* Constructs a new instance. Custom tags provided by the user will be applied to every metric.
* Overriding built-in tags is not allowed.
* Constructs a new instance using the specified handler context key and no
* custom tags.
*/
public SpectatorRequestMetricCollector(Registry registry, HandlerContextKey<String> handlerContextKey) {
this(registry, Collections.emptyMap(), handlerContextKey);
}

/**
* Constructs a new instance using no handler context key and custom tags.
*/
public SpectatorRequestMetricCollector(Registry registry, Map<String, String> customTags) {
this(registry, customTags, null);
}

/**
* Constructs a new instance using the optional handler context key. If
* present, and a request context has a value for this key, the key/value pair
* is an additional tag on every metric for that request. Custom tags
* provided by the user will be applied to every metric. Overriding built-in
* tags is not allowed.
*/
public SpectatorRequestMetricCollector(Registry registry, Map<String, String> customTags,
HandlerContextKey<String> handlerContextKey) {
super();
this.registry = Preconditions.checkNotNull(registry, "registry");
Preconditions.checkNotNull(customTags, "customTags");
Expand All @@ -116,6 +137,13 @@ public SpectatorRequestMetricCollector(Registry registry, Map<String, String> cu
this.customTags.put(key, value);
}
});
this.handlerContextKey = handlerContextKey;
if ((this.handlerContextKey != null)
&& ALL_DEFAULT_TAGS.contains(this.handlerContextKey.getName())) {
registry.propagate(new IllegalArgumentException("Invalid handler context key "
+ this.handlerContextKey.getName()
+ " - cannot override built-in tag"));
}
}

@Override
Expand Down Expand Up @@ -167,6 +195,10 @@ private Map<String, String> getAllTags(Request<?> request) {
allTags.put(tag.getName(), tag.getValue(metrics).orElse(UNKNOWN));
}
allTags.put(TAG_REQUEST_TYPE, request.getOriginalRequest().getClass().getSimpleName());
String contextTagValue = request.getHandlerContext(handlerContextKey);
if (contextTagValue != null) {
allTags.put(handlerContextKey.getName(), contextTagValue);
}
final boolean error = isError(metrics);
if (error) {
for (TagField tag : ERRORS) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import com.amazonaws.DefaultRequest;
import com.amazonaws.Request;
import com.amazonaws.Response;
import com.amazonaws.handlers.HandlerContextKey;
import com.amazonaws.http.HttpResponse;
import com.amazonaws.services.cloudwatch.model.ListMetricsRequest;
import com.amazonaws.util.AWSRequestMetrics;
Expand Down Expand Up @@ -49,6 +50,12 @@ public void setUp() {
}

private void execRequest(String endpoint, int status) {
execRequest(endpoint, status, null, null);
}

private void execRequest(String endpoint, int status,
HandlerContextKey<String> handlerContextKey,
String handlerContextValue) {
AWSRequestMetrics metrics = new AWSRequestMetricsFullSupport();
metrics.addProperty(AWSRequestMetrics.Field.ServiceName, "AmazonCloudWatch");
metrics.addProperty(AWSRequestMetrics.Field.ServiceEndpoint, endpoint);
Expand All @@ -68,6 +75,9 @@ private void execRequest(String endpoint, int status) {
req.setAWSRequestMetrics(metrics);
req.setEndpoint(URI.create(endpoint));

if ((handlerContextKey != null) && (handlerContextValue != null)) {
req.addHandlerContext(handlerContextKey, handlerContextValue);
}
HttpResponse hr = new HttpResponse(req, new HttpPost(endpoint));
hr.setStatusCode(status);
Response<?> resp = new Response<>(null, new HttpResponse(req, new HttpPost(endpoint)));
Expand Down Expand Up @@ -175,4 +185,14 @@ public void testCustomTags_overrideDefault() {
assertThrows(IllegalArgumentException.class, () ->
new SpectatorRequestMetricCollector(new DefaultRegistry(Clock.SYSTEM, config), customTags));
}

@Test
public void testHandlerContextKey() {
String contextKeyName = "myContextKey";
HandlerContextKey<String> handlerContextKey = new HandlerContextKey<>(contextKeyName);
collector = new SpectatorRequestMetricCollector(registry, handlerContextKey);
String handlerContextValue = "some-value";
execRequest("http://monitoring", 503, handlerContextKey, handlerContextValue);
assertEquals(set(handlerContextValue), valueSet(contextKeyName));
}
}

0 comments on commit 6d7af1a

Please sign in to comment.