From f7e834c5166eb63aa4d960fd916b93efd9980291 Mon Sep 17 00:00:00 2001 From: Dongie Agnir Date: Tue, 2 Jun 2020 14:26:20 -0700 Subject: [PATCH] Add setup code for API call metrics for sync --- codegen/pom.xml | 5 + .../poet/client/AsyncClientInterface.java | 7 + .../codegen/poet/client/SyncClientClass.java | 26 +- .../poet/client/specs/JsonProtocolSpec.java | 2 + .../poet/client/specs/QueryProtocolSpec.java | 3 + .../poet/client/specs/XmlProtocolSpec.java | 3 + .../poet/client/test-async-client-class.java | 108 +++--- .../client/test-endpoint-discovery-async.java | 5 + .../client/test-endpoint-discovery-sync.java | 84 +++- .../test-json-async-client-interface.java | 112 +++--- .../poet/client/test-json-client-class.java | 367 +++++++++++------- .../client/test-query-async-client-class.java | 81 ++-- .../poet/client/test-query-client-class.java | 131 +++++-- core/aws-core/pom.xml | 5 + .../awssdk/awscore/metrics/AwsCoreMetric.java | 45 +++ core/sdk-core/pom.xml | 5 + .../builder/SdkDefaultClientBuilder.java | 7 + .../core/client/config/SdkClientOption.java | 3 + .../client/handler/ClientExecutionParams.java | 11 + services/pom.xml | 5 + test/codegen-generated-classes-test/pom.xml | 5 + test/protocol-tests/pom.xml | 5 + 22 files changed, 687 insertions(+), 338 deletions(-) create mode 100644 core/aws-core/src/main/java/software/amazon/awssdk/awscore/metrics/AwsCoreMetric.java diff --git a/codegen/pom.xml b/codegen/pom.xml index e6fe0beb0c07..40713ee7c698 100644 --- a/codegen/pom.xml +++ b/codegen/pom.xml @@ -57,6 +57,11 @@ http-client-spi ${awsjavasdk.version} + + software.amazon.awssdk + metrics-spi + ${awsjavasdk.version} + software.amazon.awssdk regions diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/AsyncClientInterface.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/AsyncClientInterface.java index d9eeabfad3f9..3b36a1e330f2 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/AsyncClientInterface.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/AsyncClientInterface.java @@ -47,6 +47,7 @@ import software.amazon.awssdk.core.SdkClient; import software.amazon.awssdk.core.async.AsyncRequestBody; import software.amazon.awssdk.core.async.AsyncResponseTransformer; +import software.amazon.awssdk.metrics.MetricCollector; import software.amazon.awssdk.regions.providers.DefaultAwsRegionProviderChain; public class AsyncClientInterface implements ClassSpec { @@ -284,6 +285,12 @@ private MethodSpec traditionalMethod(OperationModel opModel) { .addParameter(requestType, opModel.getInput().getVariableName()) .addJavadoc(opModel.getDocs(model, ClientType.ASYNC)); + + String metricCollectorName = "apiCallMetricCollector"; + + builder.addStatement("$1T $2N = $1T.create($3S)", + MetricCollector.class, metricCollectorName, "ApiCall"); + if (opModel.hasStreamingInput()) { builder.addParameter(ClassName.get(AsyncRequestBody.class), "requestBody"); } else if (opModel.hasEventStreamInput()) { diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/SyncClientClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/SyncClientClass.java index cd26f0fc0a5b..3be04d2362dc 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/SyncClientClass.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/SyncClientClass.java @@ -32,6 +32,7 @@ import javax.lang.model.element.Modifier; import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.awscore.client.config.AwsClientOption; +import software.amazon.awssdk.awscore.metrics.AwsCoreMetric; import software.amazon.awssdk.codegen.docs.SimpleMethodOverload; import software.amazon.awssdk.codegen.emitters.GeneratorTaskParams; import software.amazon.awssdk.codegen.model.config.customization.UtilitiesMethod; @@ -52,6 +53,8 @@ import software.amazon.awssdk.core.client.handler.SyncClientHandler; import software.amazon.awssdk.core.endpointdiscovery.EndpointDiscoveryRefreshCache; import software.amazon.awssdk.core.endpointdiscovery.EndpointDiscoveryRequest; +import software.amazon.awssdk.metrics.MetricCollector; +import software.amazon.awssdk.metrics.MetricPublisher; //TODO Make SyncClientClass extend SyncClientInterface (similar to what we do in AsyncClientClass) public class SyncClientClass implements ClassSpec { @@ -186,7 +189,28 @@ private List operationMethodSpecs(OperationModel opModel) { method.endControlFlow(); } - method.addCode(protocolSpec.executionHandler(opModel)); + String metricCollectorName = "apiCallMetricCollector"; + + method.addStatement("$1T $2N = $1T.create($3S)", + MetricCollector.class, metricCollectorName, "ApiCall"); + + method.addStatement("$N.reportMetric($T.$L, $S)", metricCollectorName, AwsCoreMetric.class, "SERVICE_ID", + model.getMetadata().getServiceId()); + method.addStatement("$N.reportMetric($T.$L, $S)", metricCollectorName, AwsCoreMetric.class, "OPERATION_NAME", + opModel.getOperationName()); + + String publisherName = "metricPublisher"; + + method.beginControlFlow("try") + .addCode(protocolSpec.executionHandler(opModel)) + .endControlFlow() + .beginControlFlow("finally") + .addStatement("$T $N = clientConfiguration.option($T.$L)", + MetricPublisher.class, publisherName, SdkClientOption.class, "METRIC_PUBLISHER") + .beginControlFlow("if ($N != null)", publisherName) + .addStatement("$N.publish($N.collect())", publisherName, metricCollectorName) + .endControlFlow() + .endControlFlow(); methods.add(method.build()); diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/specs/JsonProtocolSpec.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/specs/JsonProtocolSpec.java index 9f99ab13377b..1dd17e93ea4c 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/specs/JsonProtocolSpec.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/specs/JsonProtocolSpec.java @@ -178,6 +178,8 @@ public CodeBlock executionHandler(OperationModel opModel) { "errorResponseHandler", opModel.getInput().getVariableName()); + codeBlock.add(".withMetricCollector($N)", "apiCallMetricCollector"); + if (opModel.hasStreamingInput()) { codeBlock.add(".withRequestBody(requestBody)") .add(".withMarshaller($L)", syncStreamingMarshaller(model, opModel, marshaller)); diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/specs/QueryProtocolSpec.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/specs/QueryProtocolSpec.java index cd6b0b2dc94d..f5a1763a4d1f 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/specs/QueryProtocolSpec.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/specs/QueryProtocolSpec.java @@ -113,6 +113,9 @@ public CodeBlock executionHandler(OperationModel opModel) { "responseHandler", "errorResponseHandler", opModel.getInput().getVariableName()); + + codeBlock.add(".withMetricCollector($N)", "apiCallMetricCollector"); + if (opModel.hasStreamingInput()) { return codeBlock.add(".withRequestBody(requestBody)") .add(".withMarshaller($L));", syncStreamingMarshaller(intermediateModel, opModel, marshaller)) diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/specs/XmlProtocolSpec.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/specs/XmlProtocolSpec.java index 55beb7078878..9eacd267a14c 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/specs/XmlProtocolSpec.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/specs/XmlProtocolSpec.java @@ -120,6 +120,9 @@ public CodeBlock executionHandler(OperationModel opModel) { opModel.getOperationName(), "responseHandler", opModel.getInput().getVariableName()); + + codeBlock.add(".withMetricCollector($N)", "apiCallMetricCollector"); + if (opModel.hasStreamingInput()) { return codeBlock.add(".withRequestBody(requestBody)") .add(".withMarshaller($L));", syncStreamingMarshaller(intermediateModel, opModel, marshaller)) diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-async-client-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-async-client-class.java index 853adc50a05d..2b0c659a467f 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-async-client-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-async-client-class.java @@ -37,6 +37,7 @@ import software.amazon.awssdk.core.runtime.transform.AsyncStreamingRequestMarshaller; import software.amazon.awssdk.core.signer.Signer; import software.amazon.awssdk.core.util.VersionInfo; +import software.amazon.awssdk.metrics.MetricCollector; import software.amazon.awssdk.protocols.core.ExceptionMetadata; import software.amazon.awssdk.protocols.json.AwsJsonProtocol; import software.amazon.awssdk.protocols.json.AwsJsonProtocolFactory; @@ -151,6 +152,7 @@ public final String serviceName() { */ @Override public CompletableFuture aPostOperation(APostOperationRequest aPostOperationRequest) { + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); try { String hostPrefix = "{StringMember}-foo."; Validate.paramNotBlank(aPostOperationRequest.stringMember(), "StringMember"); @@ -202,6 +204,7 @@ public CompletableFuture aPostOperation(APostOperationRe @Override public CompletableFuture aPostOperationWithOutput( APostOperationWithOutputRequest aPostOperationWithOutputRequest) { + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); try { JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) .isPayloadJson(true).build(); @@ -246,6 +249,7 @@ public CompletableFuture aPostOperationWithOut @Override public CompletableFuture eventStreamOperation(EventStreamOperationRequest eventStreamOperationRequest, Publisher requestStream, EventStreamOperationResponseHandler asyncResponseHandler) { + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); try { eventStreamOperationRequest = applySignerOverride(eventStreamOperationRequest, EventStreamAws4Signer.create()); JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) @@ -261,8 +265,7 @@ public CompletableFuture eventStreamOperation(EventStreamOperationRequest JsonOperationMetadata.builder().isPayloadJson(true).hasStreamingSuccessResponse(false).build(), EventStreamTaggedUnionPojoSupplier.builder().putSdkPojoSupplier("EventOne", EventOne::builder) .putSdkPojoSupplier("event-two", EventTwo::builder) - .defaultSdkPojoSupplier(() -> new SdkPojoBuilder(EventStream.UNKNOWN)) - .build()); + .defaultSdkPojoSupplier(() -> new SdkPojoBuilder(EventStream.UNKNOWN)).build()); HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, operationMetadata); @@ -331,6 +334,7 @@ public CompletableFuture eventStreamOperation(EventStreamOperationRequest public CompletableFuture eventStreamOperationWithOnlyInput( EventStreamOperationWithOnlyInputRequest eventStreamOperationWithOnlyInputRequest, Publisher requestStream) { + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); try { eventStreamOperationWithOnlyInputRequest = applySignerOverride(eventStreamOperationWithOnlyInputRequest, EventStreamAws4Signer.create()); @@ -384,45 +388,45 @@ public CompletableFuture eventStreamO */ @Override public CompletableFuture eventStreamOperationWithOnlyOutput( - EventStreamOperationWithOnlyOutputRequest eventStreamOperationWithOnlyOutputRequest, - EventStreamOperationWithOnlyOutputResponseHandler asyncResponseHandler) { + EventStreamOperationWithOnlyOutputRequest eventStreamOperationWithOnlyOutputRequest, + EventStreamOperationWithOnlyOutputResponseHandler asyncResponseHandler) { + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); try { JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) - .isPayloadJson(true).build(); + .isPayloadJson(true).build(); HttpResponseHandler responseHandler = new AttachHttpMetadataResponseHandler( - protocolFactory.createResponseHandler(operationMetadata, EventStreamOperationWithOnlyOutputResponse::builder)); + protocolFactory.createResponseHandler(operationMetadata, EventStreamOperationWithOnlyOutputResponse::builder)); HttpResponseHandler voidResponseHandler = protocolFactory.createResponseHandler(JsonOperationMetadata - .builder().isPayloadJson(false).hasStreamingSuccessResponse(true).build(), VoidSdkResponse::builder); + .builder().isPayloadJson(false).hasStreamingSuccessResponse(true).build(), VoidSdkResponse::builder); HttpResponseHandler eventResponseHandler = protocolFactory.createResponseHandler( - JsonOperationMetadata.builder().isPayloadJson(true).hasStreamingSuccessResponse(false).build(), - EventStreamTaggedUnionPojoSupplier.builder().putSdkPojoSupplier("EventOne", EventOne::builder) - .putSdkPojoSupplier("event-two", EventTwo::builder) - .defaultSdkPojoSupplier(() -> new SdkPojoBuilder(EventStream.UNKNOWN)) - .build()); + JsonOperationMetadata.builder().isPayloadJson(true).hasStreamingSuccessResponse(false).build(), + EventStreamTaggedUnionPojoSupplier.builder().putSdkPojoSupplier("EventOne", EventOne::builder) + .putSdkPojoSupplier("event-two", EventTwo::builder) + .defaultSdkPojoSupplier(() -> new SdkPojoBuilder(EventStream.UNKNOWN)).build()); HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, - operationMetadata); + operationMetadata); CompletableFuture future = new CompletableFuture<>(); EventStreamAsyncResponseTransformer asyncResponseTransformer = EventStreamAsyncResponseTransformer - . builder() - .eventStreamResponseHandler(asyncResponseHandler).eventResponseHandler(eventResponseHandler) - .initialResponseHandler(responseHandler).exceptionResponseHandler(errorResponseHandler).future(future) - .executor(executor).serviceName(serviceName()).build(); + . builder() + .eventStreamResponseHandler(asyncResponseHandler).eventResponseHandler(eventResponseHandler) + .initialResponseHandler(responseHandler).exceptionResponseHandler(errorResponseHandler).future(future) + .executor(executor).serviceName(serviceName()).build(); RestEventStreamAsyncResponseTransformer restAsyncResponseTransformer = RestEventStreamAsyncResponseTransformer - . builder() - .eventStreamAsyncResponseTransformer(asyncResponseTransformer) - .eventStreamResponseHandler(asyncResponseHandler).build(); + . builder() + .eventStreamAsyncResponseTransformer(asyncResponseTransformer) + .eventStreamResponseHandler(asyncResponseHandler).build(); CompletableFuture executeFuture = clientHandler - .execute( - new ClientExecutionParams() - .withOperationName("EventStreamOperationWithOnlyOutput") - .withMarshaller(new EventStreamOperationWithOnlyOutputRequestMarshaller(protocolFactory)) - .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) - .withInput(eventStreamOperationWithOnlyOutputRequest), restAsyncResponseTransformer); + .execute( + new ClientExecutionParams() + .withOperationName("EventStreamOperationWithOnlyOutput") + .withMarshaller(new EventStreamOperationWithOnlyOutputRequestMarshaller(protocolFactory)) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .withInput(eventStreamOperationWithOnlyOutputRequest), restAsyncResponseTransformer); executeFuture.whenComplete((r, e) -> { if (e != null) { try { @@ -435,7 +439,7 @@ public CompletableFuture eventStreamOperationWithOnlyOutput( return CompletableFutureUtils.forwardExceptionTo(future, executeFuture); } catch (Throwable t) { runAndLogError(log, "Exception thrown in exceptionOccurred callback, ignoring", - () -> asyncResponseHandler.exceptionOccurred(t)); + () -> asyncResponseHandler.exceptionOccurred(t)); return CompletableFutureUtils.failedFuture(t); } } @@ -466,6 +470,7 @@ public CompletableFuture eventStreamOperationWithOnlyOutput( @Override public CompletableFuture getWithoutRequiredMembers( GetWithoutRequiredMembersRequest getWithoutRequiredMembersRequest) { + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); try { JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) .isPayloadJson(true).build(); @@ -511,6 +516,7 @@ public CompletableFuture getWithoutRequiredMe @Override public CompletableFuture paginatedOperationWithResultKey( PaginatedOperationWithResultKeyRequest paginatedOperationWithResultKeyRequest) { + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); try { JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) .isPayloadJson(true).build(); @@ -555,7 +561,7 @@ public CompletableFuture paginatedOpera * The following are few ways to use the response class: *

* 1) Using the subscribe helper method - * + * *
      * {@code
      * software.amazon.awssdk.services.json.paginators.PaginatedOperationWithResultKeyPublisher publisher = client.paginatedOperationWithResultKeyPaginator(request);
@@ -565,19 +571,19 @@ public CompletableFuture paginatedOpera
      * 
* * 2) Using a custom subscriber - * + * *
      * {@code
      * software.amazon.awssdk.services.json.paginators.PaginatedOperationWithResultKeyPublisher publisher = client.paginatedOperationWithResultKeyPaginator(request);
      * publisher.subscribe(new Subscriber() {
-     *
+     * 
      * public void onSubscribe(org.reactivestreams.Subscriber subscription) { //... };
-     *
-     *
+     * 
+     * 
      * public void onNext(software.amazon.awssdk.services.json.model.PaginatedOperationWithResultKeyResponse response) { //... };
      * });}
      * 
- * + * * As the response is a publisher, it can work well with third party reactive streams implementations like RxJava2. *

* Please notice that the configuration of MaxResults won't limit the number of results you get with the @@ -633,6 +639,7 @@ public PaginatedOperationWithResultKeyPublisher paginatedOperationWithResultKeyP @Override public CompletableFuture paginatedOperationWithoutResultKey( PaginatedOperationWithoutResultKeyRequest paginatedOperationWithoutResultKeyRequest) { + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); try { JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) .isPayloadJson(true).build(); @@ -677,7 +684,7 @@ public CompletableFuture paginatedOp * The following are few ways to use the response class: *

* 1) Using the subscribe helper method - * + * *
      * {@code
      * software.amazon.awssdk.services.json.paginators.PaginatedOperationWithoutResultKeyPublisher publisher = client.paginatedOperationWithoutResultKeyPaginator(request);
@@ -687,19 +694,19 @@ public CompletableFuture paginatedOp
      * 
* * 2) Using a custom subscriber - * + * *
      * {@code
      * software.amazon.awssdk.services.json.paginators.PaginatedOperationWithoutResultKeyPublisher publisher = client.paginatedOperationWithoutResultKeyPaginator(request);
      * publisher.subscribe(new Subscriber() {
-     *
+     * 
      * public void onSubscribe(org.reactivestreams.Subscriber subscription) { //... };
-     *
-     *
+     * 
+     * 
      * public void onNext(software.amazon.awssdk.services.json.model.PaginatedOperationWithoutResultKeyResponse response) { //... };
      * });}
      * 
- * + * * As the response is a publisher, it can work well with third party reactive streams implementations like RxJava2. *

* Please notice that the configuration of MaxResults won't limit the number of results you get with the @@ -760,6 +767,7 @@ public PaginatedOperationWithoutResultKeyPublisher paginatedOperationWithoutResu @Override public CompletableFuture streamingInputOperation( StreamingInputOperationRequest streamingInputOperationRequest, AsyncRequestBody requestBody) { + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); try { JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) .isPayloadJson(true).build(); @@ -774,9 +782,9 @@ public CompletableFuture streamingInputOperatio .execute(new ClientExecutionParams() .withOperationName("StreamingInputOperation") .withMarshaller( - AsyncStreamingRequestMarshaller.builder() - .delegateMarshaller(new StreamingInputOperationRequestMarshaller(protocolFactory)) - .asyncRequestBody(requestBody).build()).withResponseHandler(responseHandler) + AsyncStreamingRequestMarshaller.builder() + .delegateMarshaller(new StreamingInputOperationRequestMarshaller(protocolFactory)) + .asyncRequestBody(requestBody).build()).withResponseHandler(responseHandler) .withErrorResponseHandler(errorResponseHandler).withAsyncRequestBody(requestBody) .withInput(streamingInputOperationRequest)); return executeFuture; @@ -818,6 +826,7 @@ public CompletableFuture streamingInputOperatio public CompletableFuture streamingInputOutputOperation( StreamingInputOutputOperationRequest streamingInputOutputOperationRequest, AsyncRequestBody requestBody, AsyncResponseTransformer asyncResponseTransformer) { + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); try { streamingInputOutputOperationRequest = applySignerOverride(streamingInputOutputOperationRequest, Aws4UnsignedPayloadSigner.create()); @@ -834,18 +843,18 @@ public CompletableFuture streamingInputOutputOperation( new ClientExecutionParams() .withOperationName("StreamingInputOutputOperation") .withMarshaller( - AsyncStreamingRequestMarshaller - .builder() - .delegateMarshaller( - new StreamingInputOutputOperationRequestMarshaller(protocolFactory)) - .asyncRequestBody(requestBody).transferEncoding(true).build()) + AsyncStreamingRequestMarshaller + .builder() + .delegateMarshaller( + new StreamingInputOutputOperationRequestMarshaller(protocolFactory)) + .asyncRequestBody(requestBody).transferEncoding(true).build()) .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) .withAsyncRequestBody(requestBody).withInput(streamingInputOutputOperationRequest), asyncResponseTransformer); executeFuture.whenComplete((r, e) -> { if (e != null) { runAndLogError(log, "Exception thrown in exceptionOccurred callback, ignoring", - () -> asyncResponseTransformer.exceptionOccurred(e)); + () -> asyncResponseTransformer.exceptionOccurred(e)); } }); return executeFuture; @@ -884,6 +893,7 @@ public CompletableFuture streamingInputOutputOperation( public CompletableFuture streamingOutputOperation( StreamingOutputOperationRequest streamingOutputOperationRequest, AsyncResponseTransformer asyncResponseTransformer) { + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); try { JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(true) .isPayloadJson(false).build(); @@ -903,7 +913,7 @@ public CompletableFuture streamingOutputOperation( executeFuture.whenComplete((r, e) -> { if (e != null) { runAndLogError(log, "Exception thrown in exceptionOccurred callback, ignoring", - () -> asyncResponseTransformer.exceptionOccurred(e)); + () -> asyncResponseTransformer.exceptionOccurred(e)); } }); return executeFuture; diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-endpoint-discovery-async.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-endpoint-discovery-async.java index c9cba7797d3d..da4ca5d9f07b 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-endpoint-discovery-async.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-endpoint-discovery-async.java @@ -18,6 +18,7 @@ import software.amazon.awssdk.core.endpointdiscovery.EndpointDiscoveryRefreshCache; import software.amazon.awssdk.core.endpointdiscovery.EndpointDiscoveryRequest; import software.amazon.awssdk.core.http.HttpResponseHandler; +import software.amazon.awssdk.metrics.MetricCollector; import software.amazon.awssdk.protocols.json.AwsJsonProtocol; import software.amazon.awssdk.protocols.json.AwsJsonProtocolFactory; import software.amazon.awssdk.protocols.json.BaseAwsJsonProtocolFactory; @@ -89,6 +90,7 @@ public final String serviceName() { */ @Override public CompletableFuture describeEndpoints(DescribeEndpointsRequest describeEndpointsRequest) { + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); try { JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) .isPayloadJson(true).build(); @@ -132,6 +134,7 @@ public CompletableFuture describeEndpoints(DescribeEn @Override public CompletableFuture testDiscoveryIdentifiersRequired( TestDiscoveryIdentifiersRequiredRequest testDiscoveryIdentifiersRequiredRequest) { + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); try { JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) .isPayloadJson(true).build(); @@ -182,6 +185,7 @@ public CompletableFuture testDiscovery @Override public CompletableFuture testDiscoveryOptional( TestDiscoveryOptionalRequest testDiscoveryOptionalRequest) { + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); try { JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) .isPayloadJson(true).build(); @@ -232,6 +236,7 @@ public CompletableFuture testDiscoveryOptional( @Override public CompletableFuture testDiscoveryRequired( TestDiscoveryRequiredRequest testDiscoveryRequiredRequest) { + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); try { JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) .isPayloadJson(true).build(); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-endpoint-discovery-sync.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-endpoint-discovery-sync.java index 75d9d095cc41..cc9fe0dfe5ce 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-endpoint-discovery-sync.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-endpoint-discovery-sync.java @@ -6,6 +6,7 @@ import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.client.handler.AwsSyncClientHandler; import software.amazon.awssdk.awscore.exception.AwsServiceException; +import software.amazon.awssdk.awscore.metrics.AwsCoreMetric; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; import software.amazon.awssdk.core.client.config.SdkClientOption; import software.amazon.awssdk.core.client.handler.ClientExecutionParams; @@ -14,6 +15,8 @@ import software.amazon.awssdk.core.endpointdiscovery.EndpointDiscoveryRequest; import software.amazon.awssdk.core.exception.SdkClientException; import software.amazon.awssdk.core.http.HttpResponseHandler; +import software.amazon.awssdk.metrics.MetricCollector; +import software.amazon.awssdk.metrics.MetricPublisher; import software.amazon.awssdk.protocols.json.AwsJsonProtocol; import software.amazon.awssdk.protocols.json.AwsJsonProtocolFactory; import software.amazon.awssdk.protocols.json.BaseAwsJsonProtocolFactory; @@ -88,11 +91,22 @@ public DescribeEndpointsResponse describeEndpoints(DescribeEndpointsRequest desc HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, operationMetadata); + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); + apiCallMetricCollector.reportMetric(AwsCoreMetric.SERVICE_ID, "AwsEndpointDiscoveryTest"); + apiCallMetricCollector.reportMetric(AwsCoreMetric.OPERATION_NAME, "DescribeEndpoints"); + try { - return clientHandler.execute(new ClientExecutionParams() - .withOperationName("DescribeEndpoints").withResponseHandler(responseHandler) - .withErrorResponseHandler(errorResponseHandler).withInput(describeEndpointsRequest) - .withMarshaller(new DescribeEndpointsRequestMarshaller(protocolFactory))); + return clientHandler.execute(new ClientExecutionParams() + .withOperationName("DescribeEndpoints").withResponseHandler(responseHandler) + .withErrorResponseHandler(errorResponseHandler).withInput(describeEndpointsRequest) + .withMetricCollector(apiCallMetricCollector) + .withMarshaller(new DescribeEndpointsRequestMarshaller(protocolFactory))); + } finally { + MetricPublisher metricPublisher = clientConfiguration.option(SdkClientOption.METRIC_PUBLISHER); + if (metricPublisher != null) { + metricPublisher.publish(apiCallMetricCollector.collect()); + } + } } /** @@ -129,13 +143,23 @@ public TestDiscoveryIdentifiersRequiredResponse testDiscoveryIdentifiersRequired .defaultEndpoint(clientConfiguration.option(SdkClientOption.ENDPOINT)).build(); cachedEndpoint = endpointDiscoveryCache.get(key, endpointDiscoveryRequest); } + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); + apiCallMetricCollector.reportMetric(AwsCoreMetric.SERVICE_ID, "AwsEndpointDiscoveryTest"); + apiCallMetricCollector.reportMetric(AwsCoreMetric.OPERATION_NAME, "TestDiscoveryIdentifiersRequired"); + try { - return clientHandler - .execute(new ClientExecutionParams() - .withOperationName("TestDiscoveryIdentifiersRequired").withResponseHandler(responseHandler) - .withErrorResponseHandler(errorResponseHandler).discoveredEndpoint(cachedEndpoint) - .withInput(testDiscoveryIdentifiersRequiredRequest) - .withMarshaller(new TestDiscoveryIdentifiersRequiredRequestMarshaller(protocolFactory))); + return clientHandler + .execute(new ClientExecutionParams() + .withOperationName("TestDiscoveryIdentifiersRequired").withResponseHandler(responseHandler) + .withErrorResponseHandler(errorResponseHandler).discoveredEndpoint(cachedEndpoint) + .withInput(testDiscoveryIdentifiersRequiredRequest).withMetricCollector(apiCallMetricCollector) + .withMarshaller(new TestDiscoveryIdentifiersRequiredRequestMarshaller(protocolFactory))); + } finally { + MetricPublisher metricPublisher = clientConfiguration.option(SdkClientOption.METRIC_PUBLISHER); + if (metricPublisher != null) { + metricPublisher.publish(apiCallMetricCollector.collect()); + } + } } /** @@ -171,12 +195,22 @@ public TestDiscoveryOptionalResponse testDiscoveryOptional(TestDiscoveryOptional .defaultEndpoint(clientConfiguration.option(SdkClientOption.ENDPOINT)).build(); cachedEndpoint = endpointDiscoveryCache.get(key, endpointDiscoveryRequest); } + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); + apiCallMetricCollector.reportMetric(AwsCoreMetric.SERVICE_ID, "AwsEndpointDiscoveryTest"); + apiCallMetricCollector.reportMetric(AwsCoreMetric.OPERATION_NAME, "TestDiscoveryOptional"); + try { - return clientHandler.execute(new ClientExecutionParams() - .withOperationName("TestDiscoveryOptional").withResponseHandler(responseHandler) - .withErrorResponseHandler(errorResponseHandler).discoveredEndpoint(cachedEndpoint) - .withInput(testDiscoveryOptionalRequest) - .withMarshaller(new TestDiscoveryOptionalRequestMarshaller(protocolFactory))); + return clientHandler.execute(new ClientExecutionParams() + .withOperationName("TestDiscoveryOptional").withResponseHandler(responseHandler) + .withErrorResponseHandler(errorResponseHandler).discoveredEndpoint(cachedEndpoint) + .withInput(testDiscoveryOptionalRequest).withMetricCollector(apiCallMetricCollector) + .withMarshaller(new TestDiscoveryOptionalRequestMarshaller(protocolFactory))); + } finally { + MetricPublisher metricPublisher = clientConfiguration.option(SdkClientOption.METRIC_PUBLISHER); + if (metricPublisher != null) { + metricPublisher.publish(apiCallMetricCollector.collect()); + } + } } /** @@ -212,12 +246,22 @@ public TestDiscoveryRequiredResponse testDiscoveryRequired(TestDiscoveryRequired .defaultEndpoint(clientConfiguration.option(SdkClientOption.ENDPOINT)).build(); cachedEndpoint = endpointDiscoveryCache.get(key, endpointDiscoveryRequest); } + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); + apiCallMetricCollector.reportMetric(AwsCoreMetric.SERVICE_ID, "AwsEndpointDiscoveryTest"); + apiCallMetricCollector.reportMetric(AwsCoreMetric.OPERATION_NAME, "TestDiscoveryRequired"); + try { - return clientHandler.execute(new ClientExecutionParams() - .withOperationName("TestDiscoveryRequired").withResponseHandler(responseHandler) - .withErrorResponseHandler(errorResponseHandler).discoveredEndpoint(cachedEndpoint) - .withInput(testDiscoveryRequiredRequest) - .withMarshaller(new TestDiscoveryRequiredRequestMarshaller(protocolFactory))); + return clientHandler.execute(new ClientExecutionParams() + .withOperationName("TestDiscoveryRequired").withResponseHandler(responseHandler) + .withErrorResponseHandler(errorResponseHandler).discoveredEndpoint(cachedEndpoint) + .withInput(testDiscoveryRequiredRequest).withMetricCollector(apiCallMetricCollector) + .withMarshaller(new TestDiscoveryRequiredRequestMarshaller(protocolFactory))); + } finally { + MetricPublisher metricPublisher = clientConfiguration.option(SdkClientOption.METRIC_PUBLISHER); + if (metricPublisher != null) { + metricPublisher.publish(apiCallMetricCollector.collect()); + } + } } private HttpResponseHandler createErrorResponseHandler(BaseAwsJsonProtocolFactory protocolFactory, diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-json-async-client-interface.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-json-async-client-interface.java index 1f7f80cadc1c..0024827d14a9 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-json-async-client-interface.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-json-async-client-interface.java @@ -8,6 +8,7 @@ import software.amazon.awssdk.core.SdkClient; import software.amazon.awssdk.core.async.AsyncRequestBody; import software.amazon.awssdk.core.async.AsyncResponseTransformer; +import software.amazon.awssdk.metrics.MetricCollector; import software.amazon.awssdk.services.json.model.APostOperationRequest; import software.amazon.awssdk.services.json.model.APostOperationResponse; import software.amazon.awssdk.services.json.model.APostOperationWithOutputRequest; @@ -85,6 +86,7 @@ static JsonAsyncClientBuilder builder() { * API Documentation */ default CompletableFuture aPostOperation(APostOperationRequest aPostOperationRequest) { + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); throw new UnsupportedOperationException(); } @@ -146,6 +148,7 @@ default CompletableFuture aPostOperation(Consumer aPostOperationWithOutput( APostOperationWithOutputRequest aPostOperationWithOutputRequest) { + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); throw new UnsupportedOperationException(); } @@ -182,7 +185,7 @@ default CompletableFuture aPostOperationWithOu default CompletableFuture aPostOperationWithOutput( Consumer aPostOperationWithOutputRequest) { return aPostOperationWithOutput(APostOperationWithOutputRequest.builder().applyMutation(aPostOperationWithOutputRequest) - .build()); + .build()); } /** @@ -205,7 +208,8 @@ default CompletableFuture aPostOperationWithOu * target="_top">AWS API Documentation */ default CompletableFuture eventStreamOperation(EventStreamOperationRequest eventStreamOperationRequest, - Publisher requestStream, EventStreamOperationResponseHandler asyncResponseHandler) { + Publisher requestStream, EventStreamOperationResponseHandler asyncResponseHandler) { + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); throw new UnsupportedOperationException(); } @@ -238,7 +242,7 @@ default CompletableFuture eventStreamOperation( Consumer eventStreamOperationRequest, Publisher requestStream, EventStreamOperationResponseHandler asyncResponseHandler) { return eventStreamOperation(EventStreamOperationRequest.builder().applyMutation(eventStreamOperationRequest).build(), - requestStream, asyncResponseHandler); + requestStream, asyncResponseHandler); } /** @@ -264,6 +268,7 @@ default CompletableFuture eventStreamOperation( default CompletableFuture eventStreamOperationWithOnlyInput( EventStreamOperationWithOnlyInputRequest eventStreamOperationWithOnlyInputRequest, Publisher requestStream) { + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); throw new UnsupportedOperationException(); } @@ -298,7 +303,7 @@ default CompletableFuture eventStream Publisher requestStream) { return eventStreamOperationWithOnlyInput( EventStreamOperationWithOnlyInputRequest.builder().applyMutation(eventStreamOperationWithOnlyInputRequest) - .build(), requestStream); + .build(), requestStream); } /** @@ -322,8 +327,9 @@ default CompletableFuture eventStream * target="_top">AWS API Documentation */ default CompletableFuture eventStreamOperationWithOnlyOutput( - EventStreamOperationWithOnlyOutputRequest eventStreamOperationWithOnlyOutputRequest, - EventStreamOperationWithOnlyOutputResponseHandler asyncResponseHandler) { + EventStreamOperationWithOnlyOutputRequest eventStreamOperationWithOnlyOutputRequest, + EventStreamOperationWithOnlyOutputResponseHandler asyncResponseHandler) { + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); throw new UnsupportedOperationException(); } @@ -354,11 +360,11 @@ default CompletableFuture eventStreamOperationWithOnlyOutput( * target="_top">AWS API Documentation */ default CompletableFuture eventStreamOperationWithOnlyOutput( - Consumer eventStreamOperationWithOnlyOutputRequest, - EventStreamOperationWithOnlyOutputResponseHandler asyncResponseHandler) { + Consumer eventStreamOperationWithOnlyOutputRequest, + EventStreamOperationWithOnlyOutputResponseHandler asyncResponseHandler) { return eventStreamOperationWithOnlyOutput( - EventStreamOperationWithOnlyOutputRequest.builder().applyMutation(eventStreamOperationWithOnlyOutputRequest) - .build(), asyncResponseHandler); + EventStreamOperationWithOnlyOutputRequest.builder().applyMutation(eventStreamOperationWithOnlyOutputRequest) + .build(), asyncResponseHandler); } /** @@ -386,6 +392,7 @@ default CompletableFuture eventStreamOperationWithOnlyOutput( */ default CompletableFuture getWithoutRequiredMembers( GetWithoutRequiredMembersRequest getWithoutRequiredMembersRequest) { + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); throw new UnsupportedOperationException(); } @@ -422,7 +429,7 @@ default CompletableFuture getWithoutRequiredM default CompletableFuture getWithoutRequiredMembers( Consumer getWithoutRequiredMembersRequest) { return getWithoutRequiredMembers(GetWithoutRequiredMembersRequest.builder() - .applyMutation(getWithoutRequiredMembersRequest).build()); + .applyMutation(getWithoutRequiredMembersRequest).build()); } /** @@ -447,6 +454,7 @@ default CompletableFuture getWithoutRequiredM */ default CompletableFuture paginatedOperationWithResultKey( PaginatedOperationWithResultKeyRequest paginatedOperationWithResultKeyRequest) { + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); throw new UnsupportedOperationException(); } @@ -479,7 +487,7 @@ default CompletableFuture paginatedOper default CompletableFuture paginatedOperationWithResultKey( Consumer paginatedOperationWithResultKeyRequest) { return paginatedOperationWithResultKey(PaginatedOperationWithResultKeyRequest.builder() - .applyMutation(paginatedOperationWithResultKeyRequest).build()); + .applyMutation(paginatedOperationWithResultKeyRequest).build()); } /** @@ -527,7 +535,7 @@ default CompletableFuture paginatedOper * The following are few ways to use the response class: *

* 1) Using the subscribe helper method - * + * *
      * {@code
      * software.amazon.awssdk.services.json.paginators.PaginatedOperationWithResultKeyPublisher publisher = client.paginatedOperationWithResultKeyPaginator(request);
@@ -537,19 +545,19 @@ default CompletableFuture paginatedOper
      * 
* * 2) Using a custom subscriber - * + * *
      * {@code
      * software.amazon.awssdk.services.json.paginators.PaginatedOperationWithResultKeyPublisher publisher = client.paginatedOperationWithResultKeyPaginator(request);
      * publisher.subscribe(new Subscriber() {
-     *
+     * 
      * public void onSubscribe(org.reactivestreams.Subscriber subscription) { //... };
-     *
-     *
+     * 
+     * 
      * public void onNext(software.amazon.awssdk.services.json.model.PaginatedOperationWithResultKeyResponse response) { //... };
      * });}
      * 
- * + * * As the response is a publisher, it can work well with third party reactive streams implementations like RxJava2. *

* Please notice that the configuration of MaxResults won't limit the number of results you get with the @@ -602,7 +610,7 @@ default PaginatedOperationWithResultKeyPublisher paginatedOperationWithResultKey * The following are few ways to use the response class: *

* 1) Using the subscribe helper method - * + * *
      * {@code
      * software.amazon.awssdk.services.json.paginators.PaginatedOperationWithResultKeyPublisher publisher = client.paginatedOperationWithResultKeyPaginator(request);
@@ -612,19 +620,19 @@ default PaginatedOperationWithResultKeyPublisher paginatedOperationWithResultKey
      * 
* * 2) Using a custom subscriber - * + * *
      * {@code
      * software.amazon.awssdk.services.json.paginators.PaginatedOperationWithResultKeyPublisher publisher = client.paginatedOperationWithResultKeyPaginator(request);
      * publisher.subscribe(new Subscriber() {
-     *
+     * 
      * public void onSubscribe(org.reactivestreams.Subscriber subscription) { //... };
-     *
-     *
+     * 
+     * 
      * public void onNext(software.amazon.awssdk.services.json.model.PaginatedOperationWithResultKeyResponse response) { //... };
      * });}
      * 
- * + * * As the response is a publisher, it can work well with third party reactive streams implementations like RxJava2. *

* Please notice that the configuration of MaxResults won't limit the number of results you get with the @@ -679,7 +687,7 @@ default PaginatedOperationWithResultKeyPublisher paginatedOperationWithResultKey * The following are few ways to use the response class: *

* 1) Using the subscribe helper method - * + * *
      * {@code
      * software.amazon.awssdk.services.json.paginators.PaginatedOperationWithResultKeyPublisher publisher = client.paginatedOperationWithResultKeyPaginator(request);
@@ -689,19 +697,19 @@ default PaginatedOperationWithResultKeyPublisher paginatedOperationWithResultKey
      * 
* * 2) Using a custom subscriber - * + * *
      * {@code
      * software.amazon.awssdk.services.json.paginators.PaginatedOperationWithResultKeyPublisher publisher = client.paginatedOperationWithResultKeyPaginator(request);
      * publisher.subscribe(new Subscriber() {
-     *
+     * 
      * public void onSubscribe(org.reactivestreams.Subscriber subscription) { //... };
-     *
-     *
+     * 
+     * 
      * public void onNext(software.amazon.awssdk.services.json.model.PaginatedOperationWithResultKeyResponse response) { //... };
      * });}
      * 
- * + * * As the response is a publisher, it can work well with third party reactive streams implementations like RxJava2. *

* Please notice that the configuration of MaxResults won't limit the number of results you get with the @@ -738,7 +746,7 @@ default PaginatedOperationWithResultKeyPublisher paginatedOperationWithResultKey default PaginatedOperationWithResultKeyPublisher paginatedOperationWithResultKeyPaginator( Consumer paginatedOperationWithResultKeyRequest) { return paginatedOperationWithResultKeyPaginator(PaginatedOperationWithResultKeyRequest.builder() - .applyMutation(paginatedOperationWithResultKeyRequest).build()); + .applyMutation(paginatedOperationWithResultKeyRequest).build()); } /** @@ -763,6 +771,7 @@ default PaginatedOperationWithResultKeyPublisher paginatedOperationWithResultKey */ default CompletableFuture paginatedOperationWithoutResultKey( PaginatedOperationWithoutResultKeyRequest paginatedOperationWithoutResultKeyRequest) { + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); throw new UnsupportedOperationException(); } @@ -795,7 +804,7 @@ default CompletableFuture paginatedO default CompletableFuture paginatedOperationWithoutResultKey( Consumer paginatedOperationWithoutResultKeyRequest) { return paginatedOperationWithoutResultKey(PaginatedOperationWithoutResultKeyRequest.builder() - .applyMutation(paginatedOperationWithoutResultKeyRequest).build()); + .applyMutation(paginatedOperationWithoutResultKeyRequest).build()); } /** @@ -820,7 +829,7 @@ default CompletableFuture paginatedO * The following are few ways to use the response class: *

* 1) Using the subscribe helper method - * + * *
      * {@code
      * software.amazon.awssdk.services.json.paginators.PaginatedOperationWithoutResultKeyPublisher publisher = client.paginatedOperationWithoutResultKeyPaginator(request);
@@ -830,19 +839,19 @@ default CompletableFuture paginatedO
      * 
* * 2) Using a custom subscriber - * + * *
      * {@code
      * software.amazon.awssdk.services.json.paginators.PaginatedOperationWithoutResultKeyPublisher publisher = client.paginatedOperationWithoutResultKeyPaginator(request);
      * publisher.subscribe(new Subscriber() {
-     *
+     * 
      * public void onSubscribe(org.reactivestreams.Subscriber subscription) { //... };
-     *
-     *
+     * 
+     * 
      * public void onNext(software.amazon.awssdk.services.json.model.PaginatedOperationWithoutResultKeyResponse response) { //... };
      * });}
      * 
- * + * * As the response is a publisher, it can work well with third party reactive streams implementations like RxJava2. *

* Please notice that the configuration of MaxResults won't limit the number of results you get with the @@ -897,7 +906,7 @@ default PaginatedOperationWithoutResultKeyPublisher paginatedOperationWithoutRes * The following are few ways to use the response class: *

* 1) Using the subscribe helper method - * + * *
      * {@code
      * software.amazon.awssdk.services.json.paginators.PaginatedOperationWithoutResultKeyPublisher publisher = client.paginatedOperationWithoutResultKeyPaginator(request);
@@ -907,19 +916,19 @@ default PaginatedOperationWithoutResultKeyPublisher paginatedOperationWithoutRes
      * 
* * 2) Using a custom subscriber - * + * *
      * {@code
      * software.amazon.awssdk.services.json.paginators.PaginatedOperationWithoutResultKeyPublisher publisher = client.paginatedOperationWithoutResultKeyPaginator(request);
      * publisher.subscribe(new Subscriber() {
-     *
+     * 
      * public void onSubscribe(org.reactivestreams.Subscriber subscription) { //... };
-     *
-     *
+     * 
+     * 
      * public void onNext(software.amazon.awssdk.services.json.model.PaginatedOperationWithoutResultKeyResponse response) { //... };
      * });}
      * 
- * + * * As the response is a publisher, it can work well with third party reactive streams implementations like RxJava2. *

* Please notice that the configuration of MaxResults won't limit the number of results you get with the @@ -956,7 +965,7 @@ default PaginatedOperationWithoutResultKeyPublisher paginatedOperationWithoutRes default PaginatedOperationWithoutResultKeyPublisher paginatedOperationWithoutResultKeyPaginator( Consumer paginatedOperationWithoutResultKeyRequest) { return paginatedOperationWithoutResultKeyPaginator(PaginatedOperationWithoutResultKeyRequest.builder() - .applyMutation(paginatedOperationWithoutResultKeyRequest).build()); + .applyMutation(paginatedOperationWithoutResultKeyRequest).build()); } /** @@ -985,6 +994,7 @@ default PaginatedOperationWithoutResultKeyPublisher paginatedOperationWithoutRes */ default CompletableFuture streamingInputOperation( StreamingInputOperationRequest streamingInputOperationRequest, AsyncRequestBody requestBody) { + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); throw new UnsupportedOperationException(); } @@ -1021,7 +1031,7 @@ default CompletableFuture streamingInputOperati default CompletableFuture streamingInputOperation( Consumer streamingInputOperationRequest, AsyncRequestBody requestBody) { return streamingInputOperation(StreamingInputOperationRequest.builder().applyMutation(streamingInputOperationRequest) - .build(), requestBody); + .build(), requestBody); } /** @@ -1086,7 +1096,7 @@ default CompletableFuture streamingInputOperati default CompletableFuture streamingInputOperation( Consumer streamingInputOperationRequest, Path sourcePath) { return streamingInputOperation(StreamingInputOperationRequest.builder().applyMutation(streamingInputOperationRequest) - .build(), sourcePath); + .build(), sourcePath); } /** @@ -1121,6 +1131,7 @@ default CompletableFuture streamingInputOperati default CompletableFuture streamingInputOutputOperation( StreamingInputOutputOperationRequest streamingInputOutputOperationRequest, AsyncRequestBody requestBody, AsyncResponseTransformer asyncResponseTransformer) { + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); throw new UnsupportedOperationException(); } @@ -1199,7 +1210,7 @@ default CompletableFuture streamingInputOutputOperation( default CompletableFuture streamingInputOutputOperation( StreamingInputOutputOperationRequest streamingInputOutputOperationRequest, Path sourcePath, Path destinationPath) { return streamingInputOutputOperation(streamingInputOutputOperationRequest, AsyncRequestBody.fromFile(sourcePath), - AsyncResponseTransformer.toFile(destinationPath)); + AsyncResponseTransformer.toFile(destinationPath)); } /** @@ -1271,6 +1282,7 @@ default CompletableFuture streamingInputO default CompletableFuture streamingOutputOperation( StreamingOutputOperationRequest streamingOutputOperationRequest, AsyncResponseTransformer asyncResponseTransformer) { + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); throw new UnsupportedOperationException(); } @@ -1308,7 +1320,7 @@ default CompletableFuture streamingOutputOperation( Consumer streamingOutputOperationRequest, AsyncResponseTransformer asyncResponseTransformer) { return streamingOutputOperation(StreamingOutputOperationRequest.builder().applyMutation(streamingOutputOperationRequest) - .build(), asyncResponseTransformer); + .build(), asyncResponseTransformer); } /** @@ -1371,7 +1383,7 @@ default CompletableFuture streamingOutputOpera default CompletableFuture streamingOutputOperation( Consumer streamingOutputOperationRequest, Path destinationPath) { return streamingOutputOperation(StreamingOutputOperationRequest.builder().applyMutation(streamingOutputOperationRequest) - .build(), destinationPath); + .build(), destinationPath); } /** diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-json-client-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-json-client-class.java index a3b391edbbb2..67ac43ee3963 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-json-client-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-json-client-class.java @@ -7,8 +7,10 @@ import software.amazon.awssdk.awscore.AwsRequestOverrideConfiguration; import software.amazon.awssdk.awscore.client.handler.AwsSyncClientHandler; import software.amazon.awssdk.awscore.exception.AwsServiceException; +import software.amazon.awssdk.awscore.metrics.AwsCoreMetric; import software.amazon.awssdk.core.ApiName; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; +import software.amazon.awssdk.core.client.config.SdkClientOption; import software.amazon.awssdk.core.client.handler.ClientExecutionParams; import software.amazon.awssdk.core.client.handler.SyncClientHandler; import software.amazon.awssdk.core.exception.SdkClientException; @@ -18,6 +20,8 @@ import software.amazon.awssdk.core.sync.RequestBody; import software.amazon.awssdk.core.sync.ResponseTransformer; import software.amazon.awssdk.core.util.VersionInfo; +import software.amazon.awssdk.metrics.MetricCollector; +import software.amazon.awssdk.metrics.MetricPublisher; import software.amazon.awssdk.protocols.core.ExceptionMetadata; import software.amazon.awssdk.protocols.json.AwsJsonProtocol; import software.amazon.awssdk.protocols.json.AwsJsonProtocolFactory; @@ -101,24 +105,34 @@ public final String serviceName() { */ @Override public APostOperationResponse aPostOperation(APostOperationRequest aPostOperationRequest) throws InvalidInputException, - AwsServiceException, SdkClientException, JsonException { + AwsServiceException, SdkClientException, JsonException { String hostPrefix = "{StringMember}-foo."; Validate.paramNotBlank(aPostOperationRequest.stringMember(), "StringMember"); String resolvedHostExpression = String.format("%s-foo.", aPostOperationRequest.stringMember()); JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) - .isPayloadJson(true).build(); + .isPayloadJson(true).build(); HttpResponseHandler responseHandler = protocolFactory.createResponseHandler(operationMetadata, - APostOperationResponse::builder); + APostOperationResponse::builder); HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, - operationMetadata); - - return clientHandler.execute(new ClientExecutionParams() - .withOperationName("APostOperation") - .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) - .hostPrefixExpression(resolvedHostExpression).withInput(aPostOperationRequest) - .withMarshaller(new APostOperationRequestMarshaller(protocolFactory))); + operationMetadata); + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); + apiCallMetricCollector.reportMetric(AwsCoreMetric.SERVICE_ID, "Json Service"); + apiCallMetricCollector.reportMetric(AwsCoreMetric.OPERATION_NAME, "APostOperation"); + try { + + return clientHandler.execute(new ClientExecutionParams() + .withOperationName("APostOperation").withResponseHandler(responseHandler) + .withErrorResponseHandler(errorResponseHandler).hostPrefixExpression(resolvedHostExpression) + .withInput(aPostOperationRequest).withMetricCollector(apiCallMetricCollector) + .withMarshaller(new APostOperationRequestMarshaller(protocolFactory))); + } finally { + MetricPublisher metricPublisher = clientConfiguration.option(SdkClientOption.METRIC_PUBLISHER); + if (metricPublisher != null) { + metricPublisher.publish(apiCallMetricCollector.collect()); + } + } } /** @@ -143,23 +157,33 @@ public APostOperationResponse aPostOperation(APostOperationRequest aPostOperatio */ @Override public APostOperationWithOutputResponse aPostOperationWithOutput( - APostOperationWithOutputRequest aPostOperationWithOutputRequest) throws InvalidInputException, AwsServiceException, - SdkClientException, JsonException { + APostOperationWithOutputRequest aPostOperationWithOutputRequest) throws InvalidInputException, AwsServiceException, + SdkClientException, JsonException { JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) - .isPayloadJson(true).build(); + .isPayloadJson(true).build(); HttpResponseHandler responseHandler = protocolFactory.createResponseHandler( - operationMetadata, APostOperationWithOutputResponse::builder); + operationMetadata, APostOperationWithOutputResponse::builder); HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, - operationMetadata); - - return clientHandler - .execute(new ClientExecutionParams() - .withOperationName("APostOperationWithOutput") - .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) - .withInput(aPostOperationWithOutputRequest) - .withMarshaller(new APostOperationWithOutputRequestMarshaller(protocolFactory))); + operationMetadata); + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); + apiCallMetricCollector.reportMetric(AwsCoreMetric.SERVICE_ID, "Json Service"); + apiCallMetricCollector.reportMetric(AwsCoreMetric.OPERATION_NAME, "APostOperationWithOutput"); + try { + + return clientHandler + .execute(new ClientExecutionParams() + .withOperationName("APostOperationWithOutput").withResponseHandler(responseHandler) + .withErrorResponseHandler(errorResponseHandler).withInput(aPostOperationWithOutputRequest) + .withMetricCollector(apiCallMetricCollector) + .withMarshaller(new APostOperationWithOutputRequestMarshaller(protocolFactory))); + } finally { + MetricPublisher metricPublisher = clientConfiguration.option(SdkClientOption.METRIC_PUBLISHER); + if (metricPublisher != null) { + metricPublisher.publish(apiCallMetricCollector.collect()); + } + } } /** @@ -184,23 +208,33 @@ public APostOperationWithOutputResponse aPostOperationWithOutput( */ @Override public GetWithoutRequiredMembersResponse getWithoutRequiredMembers( - GetWithoutRequiredMembersRequest getWithoutRequiredMembersRequest) throws InvalidInputException, AwsServiceException, - SdkClientException, JsonException { + GetWithoutRequiredMembersRequest getWithoutRequiredMembersRequest) throws InvalidInputException, AwsServiceException, + SdkClientException, JsonException { JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) - .isPayloadJson(true).build(); + .isPayloadJson(true).build(); HttpResponseHandler responseHandler = protocolFactory.createResponseHandler( - operationMetadata, GetWithoutRequiredMembersResponse::builder); + operationMetadata, GetWithoutRequiredMembersResponse::builder); HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, - operationMetadata); - - return clientHandler - .execute(new ClientExecutionParams() - .withOperationName("GetWithoutRequiredMembers") - .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) - .withInput(getWithoutRequiredMembersRequest) - .withMarshaller(new GetWithoutRequiredMembersRequestMarshaller(protocolFactory))); + operationMetadata); + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); + apiCallMetricCollector.reportMetric(AwsCoreMetric.SERVICE_ID, "Json Service"); + apiCallMetricCollector.reportMetric(AwsCoreMetric.OPERATION_NAME, "GetWithoutRequiredMembers"); + try { + + return clientHandler + .execute(new ClientExecutionParams() + .withOperationName("GetWithoutRequiredMembers").withResponseHandler(responseHandler) + .withErrorResponseHandler(errorResponseHandler).withInput(getWithoutRequiredMembersRequest) + .withMetricCollector(apiCallMetricCollector) + .withMarshaller(new GetWithoutRequiredMembersRequestMarshaller(protocolFactory))); + } finally { + MetricPublisher metricPublisher = clientConfiguration.option(SdkClientOption.METRIC_PUBLISHER); + if (metricPublisher != null) { + metricPublisher.publish(apiCallMetricCollector.collect()); + } + } } /** @@ -221,23 +255,33 @@ public GetWithoutRequiredMembersResponse getWithoutRequiredMembers( */ @Override public PaginatedOperationWithResultKeyResponse paginatedOperationWithResultKey( - PaginatedOperationWithResultKeyRequest paginatedOperationWithResultKeyRequest) throws AwsServiceException, - SdkClientException, JsonException { + PaginatedOperationWithResultKeyRequest paginatedOperationWithResultKeyRequest) throws AwsServiceException, + SdkClientException, JsonException { JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) - .isPayloadJson(true).build(); + .isPayloadJson(true).build(); HttpResponseHandler responseHandler = protocolFactory.createResponseHandler( - operationMetadata, PaginatedOperationWithResultKeyResponse::builder); + operationMetadata, PaginatedOperationWithResultKeyResponse::builder); HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, - operationMetadata); - - return clientHandler - .execute(new ClientExecutionParams() - .withOperationName("PaginatedOperationWithResultKey") - .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) - .withInput(paginatedOperationWithResultKeyRequest) - .withMarshaller(new PaginatedOperationWithResultKeyRequestMarshaller(protocolFactory))); + operationMetadata); + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); + apiCallMetricCollector.reportMetric(AwsCoreMetric.SERVICE_ID, "Json Service"); + apiCallMetricCollector.reportMetric(AwsCoreMetric.OPERATION_NAME, "PaginatedOperationWithResultKey"); + try { + + return clientHandler + .execute(new ClientExecutionParams() + .withOperationName("PaginatedOperationWithResultKey").withResponseHandler(responseHandler) + .withErrorResponseHandler(errorResponseHandler).withInput(paginatedOperationWithResultKeyRequest) + .withMetricCollector(apiCallMetricCollector) + .withMarshaller(new PaginatedOperationWithResultKeyRequestMarshaller(protocolFactory))); + } finally { + MetricPublisher metricPublisher = clientConfiguration.option(SdkClientOption.METRIC_PUBLISHER); + if (metricPublisher != null) { + metricPublisher.publish(apiCallMetricCollector.collect()); + } + } } /** @@ -259,7 +303,7 @@ public PaginatedOperationWithResultKeyResponse paginatedOperationWithResultKey( * The following are few ways to iterate through the response pages: *

* 1) Using a Stream - * + * *
      * {@code
      * software.amazon.awssdk.services.json.paginators.PaginatedOperationWithResultKeyIterable responses = client.paginatedOperationWithResultKeyPaginator(request);
@@ -268,7 +312,7 @@ public PaginatedOperationWithResultKeyResponse paginatedOperationWithResultKey(
      * 
* * 2) Using For loop - * + * *
      * {
      *     @code
@@ -281,7 +325,7 @@ public PaginatedOperationWithResultKeyResponse paginatedOperationWithResultKey(
      * 
* * 3) Use iterator directly - * + * *
      * {@code
      * software.amazon.awssdk.services.json.paginators.PaginatedOperationWithResultKeyIterable responses = client.paginatedOperationWithResultKeyPaginator(request);
@@ -313,8 +357,8 @@ public PaginatedOperationWithResultKeyResponse paginatedOperationWithResultKey(
      */
     @Override
     public PaginatedOperationWithResultKeyIterable paginatedOperationWithResultKeyPaginator(
-        PaginatedOperationWithResultKeyRequest paginatedOperationWithResultKeyRequest) throws AwsServiceException,
-                                                                                              SdkClientException, JsonException {
+            PaginatedOperationWithResultKeyRequest paginatedOperationWithResultKeyRequest) throws AwsServiceException,
+            SdkClientException, JsonException {
         return new PaginatedOperationWithResultKeyIterable(this, applyPaginatorUserAgent(paginatedOperationWithResultKeyRequest));
     }
 
@@ -336,23 +380,33 @@ public PaginatedOperationWithResultKeyIterable paginatedOperationWithResultKeyPa
      */
     @Override
     public PaginatedOperationWithoutResultKeyResponse paginatedOperationWithoutResultKey(
-        PaginatedOperationWithoutResultKeyRequest paginatedOperationWithoutResultKeyRequest) throws AwsServiceException,
-                                                                                                    SdkClientException, JsonException {
+            PaginatedOperationWithoutResultKeyRequest paginatedOperationWithoutResultKeyRequest) throws AwsServiceException,
+            SdkClientException, JsonException {
         JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false)
-                                                                       .isPayloadJson(true).build();
+                .isPayloadJson(true).build();
 
         HttpResponseHandler responseHandler = protocolFactory.createResponseHandler(
-            operationMetadata, PaginatedOperationWithoutResultKeyResponse::builder);
+                operationMetadata, PaginatedOperationWithoutResultKeyResponse::builder);
 
         HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory,
-                                                                                                   operationMetadata);
-
-        return clientHandler
-            .execute(new ClientExecutionParams()
-                         .withOperationName("PaginatedOperationWithoutResultKey")
-                         .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler)
-                         .withInput(paginatedOperationWithoutResultKeyRequest)
-                         .withMarshaller(new PaginatedOperationWithoutResultKeyRequestMarshaller(protocolFactory)));
+                operationMetadata);
+        MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall");
+        apiCallMetricCollector.reportMetric(AwsCoreMetric.SERVICE_ID, "Json Service");
+        apiCallMetricCollector.reportMetric(AwsCoreMetric.OPERATION_NAME, "PaginatedOperationWithoutResultKey");
+        try {
+
+            return clientHandler
+                    .execute(new ClientExecutionParams()
+                            .withOperationName("PaginatedOperationWithoutResultKey").withResponseHandler(responseHandler)
+                            .withErrorResponseHandler(errorResponseHandler).withInput(paginatedOperationWithoutResultKeyRequest)
+                            .withMetricCollector(apiCallMetricCollector)
+                            .withMarshaller(new PaginatedOperationWithoutResultKeyRequestMarshaller(protocolFactory)));
+        } finally {
+            MetricPublisher metricPublisher = clientConfiguration.option(SdkClientOption.METRIC_PUBLISHER);
+            if (metricPublisher != null) {
+                metricPublisher.publish(apiCallMetricCollector.collect());
+            }
+        }
     }
 
     /**
@@ -374,7 +428,7 @@ public PaginatedOperationWithoutResultKeyResponse paginatedOperationWithoutResul
      * The following are few ways to iterate through the response pages:
      * 

* 1) Using a Stream - * + * *
      * {@code
      * software.amazon.awssdk.services.json.paginators.PaginatedOperationWithoutResultKeyIterable responses = client.paginatedOperationWithoutResultKeyPaginator(request);
@@ -383,7 +437,7 @@ public PaginatedOperationWithoutResultKeyResponse paginatedOperationWithoutResul
      * 
* * 2) Using For loop - * + * *
      * {
      *     @code
@@ -396,7 +450,7 @@ public PaginatedOperationWithoutResultKeyResponse paginatedOperationWithoutResul
      * 
* * 3) Use iterator directly - * + * *
      * {@code
      * software.amazon.awssdk.services.json.paginators.PaginatedOperationWithoutResultKeyIterable responses = client.paginatedOperationWithoutResultKeyPaginator(request);
@@ -428,10 +482,10 @@ public PaginatedOperationWithoutResultKeyResponse paginatedOperationWithoutResul
      */
     @Override
     public PaginatedOperationWithoutResultKeyIterable paginatedOperationWithoutResultKeyPaginator(
-        PaginatedOperationWithoutResultKeyRequest paginatedOperationWithoutResultKeyRequest) throws AwsServiceException,
-                                                                                                    SdkClientException, JsonException {
+            PaginatedOperationWithoutResultKeyRequest paginatedOperationWithoutResultKeyRequest) throws AwsServiceException,
+            SdkClientException, JsonException {
         return new PaginatedOperationWithoutResultKeyIterable(this,
-                                                              applyPaginatorUserAgent(paginatedOperationWithoutResultKeyRequest));
+                applyPaginatorUserAgent(paginatedOperationWithoutResultKeyRequest));
     }
 
     /**
@@ -442,11 +496,11 @@ public PaginatedOperationWithoutResultKeyIterable paginatedOperationWithoutResul
      *        The content to send to the service. A {@link RequestBody} can be created using one of several factory
      *        methods for various sources of data. For example, to create a request body from a file you can do the
      *        following.
-     *
+     * 
      *        
      * {@code RequestBody.fromFile(new File("myfile.txt"))}
      * 
- * + * * See documentation in {@link RequestBody} for additional details and which sources of data are supported. * The service documentation for the request content is as follows 'This be a stream' * @return Result of the StreamingInputOperation operation returned by the service. @@ -463,26 +517,38 @@ public PaginatedOperationWithoutResultKeyIterable paginatedOperationWithoutResul */ @Override public StreamingInputOperationResponse streamingInputOperation(StreamingInputOperationRequest streamingInputOperationRequest, - RequestBody requestBody) throws AwsServiceException, SdkClientException, JsonException { + RequestBody requestBody) throws AwsServiceException, SdkClientException, JsonException { JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false) - .isPayloadJson(true).build(); + .isPayloadJson(true).build(); HttpResponseHandler responseHandler = protocolFactory.createResponseHandler( - operationMetadata, StreamingInputOperationResponse::builder); + operationMetadata, StreamingInputOperationResponse::builder); HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, - operationMetadata); - - return clientHandler.execute(new ClientExecutionParams() - .withOperationName("StreamingInputOperation") - .withResponseHandler(responseHandler) - .withErrorResponseHandler(errorResponseHandler) - .withInput(streamingInputOperationRequest) - .withRequestBody(requestBody) - .withMarshaller( - StreamingRequestMarshaller.builder() - .delegateMarshaller(new StreamingInputOperationRequestMarshaller(protocolFactory)) - .requestBody(requestBody).build())); + operationMetadata); + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); + apiCallMetricCollector.reportMetric(AwsCoreMetric.SERVICE_ID, "Json Service"); + apiCallMetricCollector.reportMetric(AwsCoreMetric.OPERATION_NAME, "StreamingInputOperation"); + try { + + return clientHandler + .execute(new ClientExecutionParams() + .withOperationName("StreamingInputOperation") + .withResponseHandler(responseHandler) + .withErrorResponseHandler(errorResponseHandler) + .withInput(streamingInputOperationRequest) + .withMetricCollector(apiCallMetricCollector) + .withRequestBody(requestBody) + .withMarshaller( + StreamingRequestMarshaller.builder() + .delegateMarshaller(new StreamingInputOperationRequestMarshaller(protocolFactory)) + .requestBody(requestBody).build())); + } finally { + MetricPublisher metricPublisher = clientConfiguration.option(SdkClientOption.METRIC_PUBLISHER); + if (metricPublisher != null) { + metricPublisher.publish(apiCallMetricCollector.collect()); + } + } } /** @@ -493,20 +559,20 @@ public StreamingInputOperationResponse streamingInputOperation(StreamingInputOpe * The content to send to the service. A {@link RequestBody} can be created using one of several factory * methods for various sources of data. For example, to create a request body from a file you can do the * following. - * + * *
      * {@code RequestBody.fromFile(new File("myfile.txt"))}
      * 
- * + * * See documentation in {@link RequestBody} for additional details and which sources of data are supported. * The service documentation for the request content is as follows 'This be a stream' * @param responseTransformer * Functional interface for processing the streamed response content. The unmarshalled - * StreamingInputOutputOperationResponse and an InputStream to the response content are provided as parameters - * to the callback. The callback may return a transformed type which will be the return value of this method. - * See {@link software.amazon.awssdk.core.sync.ResponseTransformer} for details on implementing this - * interface and for links to pre-canned implementations for common scenarios like downloading to a file. The - * service documentation for the response content is as follows 'This be a stream'. + * StreamingInputOutputOperationResponse and an InputStream to the response content are provided as + * parameters to the callback. The callback may return a transformed type which will be the return value of + * this method. See {@link software.amazon.awssdk.core.sync.ResponseTransformer} for details on implementing + * this interface and for links to pre-canned implementations for common scenarios like downloading to a + * file. The service documentation for the response content is as follows 'This be a stream'. * @return The transformed result of the ResponseTransformer. * @throws SdkException * Base class for all exceptions that can be thrown by the SDK (both service and client). Can be used for @@ -521,31 +587,44 @@ public StreamingInputOperationResponse streamingInputOperation(StreamingInputOpe */ @Override public ReturnT streamingInputOutputOperation( - StreamingInputOutputOperationRequest streamingInputOutputOperationRequest, RequestBody requestBody, - ResponseTransformer responseTransformer) throws AwsServiceException, - SdkClientException, JsonException { + StreamingInputOutputOperationRequest streamingInputOutputOperationRequest, RequestBody requestBody, + ResponseTransformer responseTransformer) throws AwsServiceException, + SdkClientException, JsonException { streamingInputOutputOperationRequest = applySignerOverride(streamingInputOutputOperationRequest, - Aws4UnsignedPayloadSigner.create()); + Aws4UnsignedPayloadSigner.create()); JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(true) - .isPayloadJson(false).build(); + .isPayloadJson(false).build(); HttpResponseHandler responseHandler = protocolFactory.createResponseHandler( - operationMetadata, StreamingInputOutputOperationResponse::builder); + operationMetadata, StreamingInputOutputOperationResponse::builder); HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, - operationMetadata); - - return clientHandler.execute( - new ClientExecutionParams() - .withOperationName("StreamingInputOutputOperation") - .withResponseHandler(responseHandler) - .withErrorResponseHandler(errorResponseHandler) - .withInput(streamingInputOutputOperationRequest) - .withRequestBody(requestBody) - .withMarshaller( - StreamingRequestMarshaller.builder() - .delegateMarshaller(new StreamingInputOutputOperationRequestMarshaller(protocolFactory)) - .requestBody(requestBody).transferEncoding(true).build()), responseTransformer); + operationMetadata); + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); + apiCallMetricCollector.reportMetric(AwsCoreMetric.SERVICE_ID, "Json Service"); + apiCallMetricCollector.reportMetric(AwsCoreMetric.OPERATION_NAME, "StreamingInputOutputOperation"); + try { + + return clientHandler.execute( + new ClientExecutionParams() + .withOperationName("StreamingInputOutputOperation") + .withResponseHandler(responseHandler) + .withErrorResponseHandler(errorResponseHandler) + .withInput(streamingInputOutputOperationRequest) + .withMetricCollector(apiCallMetricCollector) + .withRequestBody(requestBody) + .withMarshaller( + StreamingRequestMarshaller + .builder() + .delegateMarshaller( + new StreamingInputOutputOperationRequestMarshaller(protocolFactory)) + .requestBody(requestBody).transferEncoding(true).build()), responseTransformer); + } finally { + MetricPublisher metricPublisher = clientConfiguration.option(SdkClientOption.METRIC_PUBLISHER); + if (metricPublisher != null) { + metricPublisher.publish(apiCallMetricCollector.collect()); + } + } } /** @@ -554,8 +633,8 @@ public ReturnT streamingInputOutputOperation( * @param streamingOutputOperationRequest * @param responseTransformer * Functional interface for processing the streamed response content. The unmarshalled - * StreamingOutputOperationResponse and an InputStream to the response content are provided as parameters - * to the callback. The callback may return a transformed type which will be the return value of this method. + * StreamingOutputOperationResponse and an InputStream to the response content are provided as parameters to + * the callback. The callback may return a transformed type which will be the return value of this method. * See {@link software.amazon.awssdk.core.sync.ResponseTransformer} for details on implementing this * interface and for links to pre-canned implementations for common scenarios like downloading to a file. The * service documentation for the response content is as follows 'This be a stream'. @@ -573,39 +652,49 @@ public ReturnT streamingInputOutputOperation( */ @Override public ReturnT streamingOutputOperation(StreamingOutputOperationRequest streamingOutputOperationRequest, - ResponseTransformer responseTransformer) throws AwsServiceException, - SdkClientException, JsonException { + ResponseTransformer responseTransformer) throws AwsServiceException, + SdkClientException, JsonException { JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(true) - .isPayloadJson(false).build(); + .isPayloadJson(false).build(); HttpResponseHandler responseHandler = protocolFactory.createResponseHandler( - operationMetadata, StreamingOutputOperationResponse::builder); + operationMetadata, StreamingOutputOperationResponse::builder); HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory, - operationMetadata); - - return clientHandler.execute( - new ClientExecutionParams() - .withOperationName("StreamingOutputOperation") - .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) - .withInput(streamingOutputOperationRequest) - .withMarshaller(new StreamingOutputOperationRequestMarshaller(protocolFactory)), responseTransformer); + operationMetadata); + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); + apiCallMetricCollector.reportMetric(AwsCoreMetric.SERVICE_ID, "Json Service"); + apiCallMetricCollector.reportMetric(AwsCoreMetric.OPERATION_NAME, "StreamingOutputOperation"); + try { + + return clientHandler.execute( + new ClientExecutionParams() + .withOperationName("StreamingOutputOperation").withResponseHandler(responseHandler) + .withErrorResponseHandler(errorResponseHandler).withInput(streamingOutputOperationRequest) + .withMetricCollector(apiCallMetricCollector) + .withMarshaller(new StreamingOutputOperationRequestMarshaller(protocolFactory)), responseTransformer); + } finally { + MetricPublisher metricPublisher = clientConfiguration.option(SdkClientOption.METRIC_PUBLISHER); + if (metricPublisher != null) { + metricPublisher.publish(apiCallMetricCollector.collect()); + } + } } private HttpResponseHandler createErrorResponseHandler(BaseAwsJsonProtocolFactory protocolFactory, - JsonOperationMetadata operationMetadata) { + JsonOperationMetadata operationMetadata) { return protocolFactory.createErrorResponseHandler(operationMetadata); } private > T init(T builder) { return builder - .clientConfiguration(clientConfiguration) - .defaultServiceExceptionSupplier(JsonException::builder) - .protocol(AwsJsonProtocol.REST_JSON) - .protocolVersion("1.1") - .registerModeledException( - ExceptionMetadata.builder().errorCode("InvalidInput") - .exceptionBuilderSupplier(InvalidInputException::builder).httpStatusCode(400).build()); + .clientConfiguration(clientConfiguration) + .defaultServiceExceptionSupplier(JsonException::builder) + .protocol(AwsJsonProtocol.REST_JSON) + .protocolVersion("1.1") + .registerModeledException( + ExceptionMetadata.builder().errorCode("InvalidInput") + .exceptionBuilderSupplier(InvalidInputException::builder).httpStatusCode(400).build()); } @Override @@ -615,10 +704,10 @@ public void close() { private T applyPaginatorUserAgent(T request) { Consumer userAgentApplier = b -> b.addApiName(ApiName.builder() - .version(VersionInfo.SDK_VERSION).name("PAGINATED").build()); + .version(VersionInfo.SDK_VERSION).name("PAGINATED").build()); AwsRequestOverrideConfiguration overrideConfiguration = request.overrideConfiguration() - .map(c -> c.toBuilder().applyMutation(userAgentApplier).build()) - .orElse((AwsRequestOverrideConfiguration.builder().applyMutation(userAgentApplier).build())); + .map(c -> c.toBuilder().applyMutation(userAgentApplier).build()) + .orElse((AwsRequestOverrideConfiguration.builder().applyMutation(userAgentApplier).build())); return (T) request.toBuilder().overrideConfiguration(overrideConfiguration).build(); } @@ -628,8 +717,8 @@ private T applySignerOverride(T request, Signer signer) } Consumer signerOverride = b -> b.signer(signer).build(); AwsRequestOverrideConfiguration overrideConfiguration = request.overrideConfiguration() - .map(c -> c.toBuilder().applyMutation(signerOverride).build()) - .orElse((AwsRequestOverrideConfiguration.builder().applyMutation(signerOverride).build())); + .map(c -> c.toBuilder().applyMutation(signerOverride).build()) + .orElse((AwsRequestOverrideConfiguration.builder().applyMutation(signerOverride).build())); return (T) request.toBuilder().overrideConfiguration(overrideConfiguration).build(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-query-async-client-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-query-async-client-class.java index e6ddff92b7f4..e96ac5147355 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-query-async-client-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-query-async-client-class.java @@ -16,6 +16,7 @@ import software.amazon.awssdk.core.client.handler.ClientExecutionParams; import software.amazon.awssdk.core.http.HttpResponseHandler; import software.amazon.awssdk.core.runtime.transform.AsyncStreamingRequestMarshaller; +import software.amazon.awssdk.metrics.MetricCollector; import software.amazon.awssdk.protocols.core.ExceptionMetadata; import software.amazon.awssdk.protocols.query.AwsQueryProtocolFactory; import software.amazon.awssdk.services.query.model.APostOperationRequest; @@ -86,21 +87,22 @@ public final String serviceName() { */ @Override public CompletableFuture aPostOperation(APostOperationRequest aPostOperationRequest) { + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); try { String hostPrefix = "foo-"; String resolvedHostExpression = "foo-"; HttpResponseHandler responseHandler = protocolFactory - .createResponseHandler(APostOperationResponse::builder); + .createResponseHandler(APostOperationResponse::builder); HttpResponseHandler errorResponseHandler = protocolFactory.createErrorResponseHandler(); CompletableFuture executeFuture = clientHandler - .execute(new ClientExecutionParams() - .withOperationName("APostOperation") - .withMarshaller(new APostOperationRequestMarshaller(protocolFactory)) - .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) - .hostPrefixExpression(resolvedHostExpression).withInput(aPostOperationRequest)); + .execute(new ClientExecutionParams() + .withOperationName("APostOperation") + .withMarshaller(new APostOperationRequestMarshaller(protocolFactory)) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .hostPrefixExpression(resolvedHostExpression).withInput(aPostOperationRequest)); return executeFuture; } catch (Throwable t) { return CompletableFutureUtils.failedFuture(t); @@ -132,20 +134,21 @@ public CompletableFuture aPostOperation(APostOperationRe */ @Override public CompletableFuture aPostOperationWithOutput( - APostOperationWithOutputRequest aPostOperationWithOutputRequest) { + APostOperationWithOutputRequest aPostOperationWithOutputRequest) { + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); try { HttpResponseHandler responseHandler = protocolFactory - .createResponseHandler(APostOperationWithOutputResponse::builder); + .createResponseHandler(APostOperationWithOutputResponse::builder); HttpResponseHandler errorResponseHandler = protocolFactory.createErrorResponseHandler(); CompletableFuture executeFuture = clientHandler - .execute(new ClientExecutionParams() - .withOperationName("APostOperationWithOutput") - .withMarshaller(new APostOperationWithOutputRequestMarshaller(protocolFactory)) - .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) - .withInput(aPostOperationWithOutputRequest)); + .execute(new ClientExecutionParams() + .withOperationName("APostOperationWithOutput") + .withMarshaller(new APostOperationWithOutputRequestMarshaller(protocolFactory)) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .withInput(aPostOperationWithOutputRequest)); return executeFuture; } catch (Throwable t) { return CompletableFutureUtils.failedFuture(t); @@ -178,23 +181,24 @@ public CompletableFuture aPostOperationWithOut */ @Override public CompletableFuture streamingInputOperation( - StreamingInputOperationRequest streamingInputOperationRequest, AsyncRequestBody requestBody) { + StreamingInputOperationRequest streamingInputOperationRequest, AsyncRequestBody requestBody) { + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); try { HttpResponseHandler responseHandler = protocolFactory - .createResponseHandler(StreamingInputOperationResponse::builder); + .createResponseHandler(StreamingInputOperationResponse::builder); HttpResponseHandler errorResponseHandler = protocolFactory.createErrorResponseHandler(); CompletableFuture executeFuture = clientHandler - .execute(new ClientExecutionParams() - .withOperationName("StreamingInputOperation") - .withMarshaller( - AsyncStreamingRequestMarshaller.builder() - .delegateMarshaller(new StreamingInputOperationRequestMarshaller(protocolFactory)) - .asyncRequestBody(requestBody).build()).withResponseHandler(responseHandler) - .withErrorResponseHandler(errorResponseHandler).withAsyncRequestBody(requestBody) - .withInput(streamingInputOperationRequest)); + .execute(new ClientExecutionParams() + .withOperationName("StreamingInputOperation") + .withMarshaller( + AsyncStreamingRequestMarshaller.builder() + .delegateMarshaller(new StreamingInputOperationRequestMarshaller(protocolFactory)) + .asyncRequestBody(requestBody).build()).withResponseHandler(responseHandler) + .withErrorResponseHandler(errorResponseHandler).withAsyncRequestBody(requestBody) + .withInput(streamingInputOperationRequest)); return executeFuture; } catch (Throwable t) { return CompletableFutureUtils.failedFuture(t); @@ -227,31 +231,32 @@ public CompletableFuture streamingInputOperatio */ @Override public CompletableFuture streamingOutputOperation( - StreamingOutputOperationRequest streamingOutputOperationRequest, - AsyncResponseTransformer asyncResponseTransformer) { + StreamingOutputOperationRequest streamingOutputOperationRequest, + AsyncResponseTransformer asyncResponseTransformer) { + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); try { HttpResponseHandler responseHandler = protocolFactory - .createResponseHandler(StreamingOutputOperationResponse::builder); + .createResponseHandler(StreamingOutputOperationResponse::builder); HttpResponseHandler errorResponseHandler = protocolFactory.createErrorResponseHandler(); CompletableFuture executeFuture = clientHandler.execute( - new ClientExecutionParams() - .withOperationName("StreamingOutputOperation") - .withMarshaller(new StreamingOutputOperationRequestMarshaller(protocolFactory)) - .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) - .withInput(streamingOutputOperationRequest), asyncResponseTransformer); + new ClientExecutionParams() + .withOperationName("StreamingOutputOperation") + .withMarshaller(new StreamingOutputOperationRequestMarshaller(protocolFactory)) + .withResponseHandler(responseHandler).withErrorResponseHandler(errorResponseHandler) + .withInput(streamingOutputOperationRequest), asyncResponseTransformer); executeFuture.whenComplete((r, e) -> { if (e != null) { runAndLogError(log, "Exception thrown in exceptionOccurred callback, ignoring", - () -> asyncResponseTransformer.exceptionOccurred(e)); + () -> asyncResponseTransformer.exceptionOccurred(e)); } }); return executeFuture; } catch (Throwable t) { runAndLogError(log, "Exception thrown in exceptionOccurred callback, ignoring", - () -> asyncResponseTransformer.exceptionOccurred(t)); + () -> asyncResponseTransformer.exceptionOccurred(t)); return CompletableFutureUtils.failedFuture(t); } } @@ -263,10 +268,10 @@ public void close() { private AwsQueryProtocolFactory init() { return AwsQueryProtocolFactory - .builder() - .registerModeledException( - ExceptionMetadata.builder().errorCode("InvalidInput") - .exceptionBuilderSupplier(InvalidInputException::builder).httpStatusCode(400).build()) - .clientConfiguration(clientConfiguration).defaultServiceExceptionSupplier(QueryException::builder).build(); + .builder() + .registerModeledException( + ExceptionMetadata.builder().errorCode("InvalidInput") + .exceptionBuilderSupplier(InvalidInputException::builder).httpStatusCode(400).build()) + .clientConfiguration(clientConfiguration).defaultServiceExceptionSupplier(QueryException::builder).build(); } } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-query-client-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-query-client-class.java index c99dfe5cf930..c4c82282dd3c 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-query-client-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-query-client-class.java @@ -4,7 +4,9 @@ import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.awscore.client.handler.AwsSyncClientHandler; import software.amazon.awssdk.awscore.exception.AwsServiceException; +import software.amazon.awssdk.awscore.metrics.AwsCoreMetric; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; +import software.amazon.awssdk.core.client.config.SdkClientOption; import software.amazon.awssdk.core.client.handler.ClientExecutionParams; import software.amazon.awssdk.core.client.handler.SyncClientHandler; import software.amazon.awssdk.core.exception.SdkClientException; @@ -12,6 +14,8 @@ import software.amazon.awssdk.core.runtime.transform.StreamingRequestMarshaller; import software.amazon.awssdk.core.sync.RequestBody; import software.amazon.awssdk.core.sync.ResponseTransformer; +import software.amazon.awssdk.metrics.MetricCollector; +import software.amazon.awssdk.metrics.MetricPublisher; import software.amazon.awssdk.protocols.core.ExceptionMetadata; import software.amazon.awssdk.protocols.query.AwsQueryProtocolFactory; import software.amazon.awssdk.services.query.model.APostOperationRequest; @@ -76,19 +80,30 @@ public final String serviceName() { */ @Override public APostOperationResponse aPostOperation(APostOperationRequest aPostOperationRequest) throws InvalidInputException, - AwsServiceException, SdkClientException, QueryException { + AwsServiceException, SdkClientException, QueryException { String hostPrefix = "foo-"; String resolvedHostExpression = "foo-"; HttpResponseHandler responseHandler = protocolFactory - .createResponseHandler(APostOperationResponse::builder); + .createResponseHandler(APostOperationResponse::builder); HttpResponseHandler errorResponseHandler = protocolFactory.createErrorResponseHandler(); + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); + apiCallMetricCollector.reportMetric(AwsCoreMetric.SERVICE_ID, "Query Service"); + apiCallMetricCollector.reportMetric(AwsCoreMetric.OPERATION_NAME, "APostOperation"); + try { - return clientHandler.execute(new ClientExecutionParams() - .withOperationName("APostOperation").withResponseHandler(responseHandler) - .withErrorResponseHandler(errorResponseHandler).hostPrefixExpression(resolvedHostExpression) - .withInput(aPostOperationRequest).withMarshaller(new APostOperationRequestMarshaller(protocolFactory))); + return clientHandler.execute(new ClientExecutionParams() + .withOperationName("APostOperation").withResponseHandler(responseHandler) + .withErrorResponseHandler(errorResponseHandler).hostPrefixExpression(resolvedHostExpression) + .withInput(aPostOperationRequest).withMetricCollector(apiCallMetricCollector) + .withMarshaller(new APostOperationRequestMarshaller(protocolFactory))); + } finally { + MetricPublisher metricPublisher = clientConfiguration.option(SdkClientOption.METRIC_PUBLISHER); + if (metricPublisher != null) { + metricPublisher.publish(apiCallMetricCollector.collect()); + } + } } /** @@ -113,19 +128,30 @@ public APostOperationResponse aPostOperation(APostOperationRequest aPostOperatio */ @Override public APostOperationWithOutputResponse aPostOperationWithOutput( - APostOperationWithOutputRequest aPostOperationWithOutputRequest) throws InvalidInputException, AwsServiceException, - SdkClientException, QueryException { + APostOperationWithOutputRequest aPostOperationWithOutputRequest) throws InvalidInputException, AwsServiceException, + SdkClientException, QueryException { HttpResponseHandler responseHandler = protocolFactory - .createResponseHandler(APostOperationWithOutputResponse::builder); + .createResponseHandler(APostOperationWithOutputResponse::builder); HttpResponseHandler errorResponseHandler = protocolFactory.createErrorResponseHandler(); + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); + apiCallMetricCollector.reportMetric(AwsCoreMetric.SERVICE_ID, "Query Service"); + apiCallMetricCollector.reportMetric(AwsCoreMetric.OPERATION_NAME, "APostOperationWithOutput"); + try { - return clientHandler - .execute(new ClientExecutionParams() - .withOperationName("APostOperationWithOutput").withResponseHandler(responseHandler) - .withErrorResponseHandler(errorResponseHandler).withInput(aPostOperationWithOutputRequest) - .withMarshaller(new APostOperationWithOutputRequestMarshaller(protocolFactory))); + return clientHandler + .execute(new ClientExecutionParams() + .withOperationName("APostOperationWithOutput").withResponseHandler(responseHandler) + .withErrorResponseHandler(errorResponseHandler).withInput(aPostOperationWithOutputRequest) + .withMetricCollector(apiCallMetricCollector) + .withMarshaller(new APostOperationWithOutputRequestMarshaller(protocolFactory))); + } finally { + MetricPublisher metricPublisher = clientConfiguration.option(SdkClientOption.METRIC_PUBLISHER); + if (metricPublisher != null) { + metricPublisher.publish(apiCallMetricCollector.collect()); + } + } } /** @@ -136,11 +162,11 @@ public APostOperationWithOutputResponse aPostOperationWithOutput( * The content to send to the service. A {@link RequestBody} can be created using one of several factory * methods for various sources of data. For example, to create a request body from a file you can do the * following. - * + * *
      * {@code RequestBody.fromFile(new File("myfile.txt"))}
      * 
- * + * * See documentation in {@link RequestBody} for additional details and which sources of data are supported. * The service documentation for the request content is as follows 'This be a stream' * @return Result of the StreamingInputOperation operation returned by the service. @@ -157,23 +183,35 @@ public APostOperationWithOutputResponse aPostOperationWithOutput( */ @Override public StreamingInputOperationResponse streamingInputOperation(StreamingInputOperationRequest streamingInputOperationRequest, - RequestBody requestBody) throws AwsServiceException, SdkClientException, QueryException { + RequestBody requestBody) throws AwsServiceException, SdkClientException, QueryException { HttpResponseHandler responseHandler = protocolFactory - .createResponseHandler(StreamingInputOperationResponse::builder); + .createResponseHandler(StreamingInputOperationResponse::builder); HttpResponseHandler errorResponseHandler = protocolFactory.createErrorResponseHandler(); + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); + apiCallMetricCollector.reportMetric(AwsCoreMetric.SERVICE_ID, "Query Service"); + apiCallMetricCollector.reportMetric(AwsCoreMetric.OPERATION_NAME, "StreamingInputOperation"); + try { - return clientHandler.execute(new ClientExecutionParams() - .withOperationName("StreamingInputOperation") - .withResponseHandler(responseHandler) - .withErrorResponseHandler(errorResponseHandler) - .withInput(streamingInputOperationRequest) - .withRequestBody(requestBody) - .withMarshaller( - StreamingRequestMarshaller.builder() - .delegateMarshaller(new StreamingInputOperationRequestMarshaller(protocolFactory)) - .requestBody(requestBody).build())); + return clientHandler + .execute(new ClientExecutionParams() + .withOperationName("StreamingInputOperation") + .withResponseHandler(responseHandler) + .withErrorResponseHandler(errorResponseHandler) + .withInput(streamingInputOperationRequest) + .withMetricCollector(apiCallMetricCollector) + .withRequestBody(requestBody) + .withMarshaller( + StreamingRequestMarshaller.builder() + .delegateMarshaller(new StreamingInputOperationRequestMarshaller(protocolFactory)) + .requestBody(requestBody).build())); + } finally { + MetricPublisher metricPublisher = clientConfiguration.option(SdkClientOption.METRIC_PUBLISHER); + if (metricPublisher != null) { + metricPublisher.publish(apiCallMetricCollector.collect()); + } + } } /** @@ -201,28 +239,39 @@ public StreamingInputOperationResponse streamingInputOperation(StreamingInputOpe */ @Override public ReturnT streamingOutputOperation(StreamingOutputOperationRequest streamingOutputOperationRequest, - ResponseTransformer responseTransformer) throws AwsServiceException, - SdkClientException, QueryException { + ResponseTransformer responseTransformer) throws AwsServiceException, + SdkClientException, QueryException { HttpResponseHandler responseHandler = protocolFactory - .createResponseHandler(StreamingOutputOperationResponse::builder); + .createResponseHandler(StreamingOutputOperationResponse::builder); HttpResponseHandler errorResponseHandler = protocolFactory.createErrorResponseHandler(); + MetricCollector apiCallMetricCollector = MetricCollector.create("ApiCall"); + apiCallMetricCollector.reportMetric(AwsCoreMetric.SERVICE_ID, "Query Service"); + apiCallMetricCollector.reportMetric(AwsCoreMetric.OPERATION_NAME, "StreamingOutputOperation"); + try { - return clientHandler.execute( - new ClientExecutionParams() - .withOperationName("StreamingOutputOperation").withResponseHandler(responseHandler) - .withErrorResponseHandler(errorResponseHandler).withInput(streamingOutputOperationRequest) - .withMarshaller(new StreamingOutputOperationRequestMarshaller(protocolFactory)), responseTransformer); + return clientHandler.execute( + new ClientExecutionParams() + .withOperationName("StreamingOutputOperation").withResponseHandler(responseHandler) + .withErrorResponseHandler(errorResponseHandler).withInput(streamingOutputOperationRequest) + .withMetricCollector(apiCallMetricCollector) + .withMarshaller(new StreamingOutputOperationRequestMarshaller(protocolFactory)), responseTransformer); + } finally { + MetricPublisher metricPublisher = clientConfiguration.option(SdkClientOption.METRIC_PUBLISHER); + if (metricPublisher != null) { + metricPublisher.publish(apiCallMetricCollector.collect()); + } + } } private AwsQueryProtocolFactory init() { return AwsQueryProtocolFactory - .builder() - .registerModeledException( - ExceptionMetadata.builder().errorCode("InvalidInput") - .exceptionBuilderSupplier(InvalidInputException::builder).httpStatusCode(400).build()) - .clientConfiguration(clientConfiguration).defaultServiceExceptionSupplier(QueryException::builder).build(); + .builder() + .registerModeledException( + ExceptionMetadata.builder().errorCode("InvalidInput") + .exceptionBuilderSupplier(InvalidInputException::builder).httpStatusCode(400).build()) + .clientConfiguration(clientConfiguration).defaultServiceExceptionSupplier(QueryException::builder).build(); } @Override diff --git a/core/aws-core/pom.xml b/core/aws-core/pom.xml index 45a68fe355c5..0f289fa045ad 100644 --- a/core/aws-core/pom.xml +++ b/core/aws-core/pom.xml @@ -63,6 +63,11 @@ http-client-spi ${awsjavasdk.version} + + software.amazon.awssdk + metrics-spi + ${awsjavasdk.version} + software.amazon.awssdk utils diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/metrics/AwsCoreMetric.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/metrics/AwsCoreMetric.java new file mode 100644 index 000000000000..5e387fdead5b --- /dev/null +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/metrics/AwsCoreMetric.java @@ -0,0 +1,45 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.awscore.metrics; + +import software.amazon.awssdk.annotations.SdkPublicApi; +import software.amazon.awssdk.metrics.MetricCategory; +import software.amazon.awssdk.metrics.SdkMetric; + +/** + * The set of metrics collected for all SDK clients. + */ +@SdkPublicApi +public final class AwsCoreMetric { + + /** + * The unique ID for the service. This is present for all API call metrics. + */ + public static final SdkMetric SERVICE_ID = metric("ServiceName", String.class); + + /** + * The name of the service operation being invoked. This is present for all + * API call metrics. + */ + public static final SdkMetric OPERATION_NAME = metric("OperationName", String.class); + + private AwsCoreMetric() { + } + + private static SdkMetric metric(String name, Class clzz) { + return SdkMetric.create(name, clzz, MetricCategory.DEFAULT); + } +} diff --git a/core/sdk-core/pom.xml b/core/sdk-core/pom.xml index ac66e61d21d3..81334cd13e05 100644 --- a/core/sdk-core/pom.xml +++ b/core/sdk-core/pom.xml @@ -41,6 +41,11 @@ http-client-spi ${awsjavasdk.version} + + software.amazon.awssdk + metrics-spi + ${awsjavasdk.version} + software.amazon.awssdk utils diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/client/builder/SdkDefaultClientBuilder.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/client/builder/SdkDefaultClientBuilder.java index 1be24c8bac0c..c4194399f976 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/client/builder/SdkDefaultClientBuilder.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/client/builder/SdkDefaultClientBuilder.java @@ -28,6 +28,7 @@ import static software.amazon.awssdk.core.client.config.SdkClientOption.ASYNC_HTTP_CLIENT; import static software.amazon.awssdk.core.client.config.SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED; import static software.amazon.awssdk.core.client.config.SdkClientOption.EXECUTION_INTERCEPTORS; +import static software.amazon.awssdk.core.client.config.SdkClientOption.METRIC_PUBLISHER; import static software.amazon.awssdk.core.client.config.SdkClientOption.PROFILE_FILE; import static software.amazon.awssdk.core.client.config.SdkClientOption.PROFILE_NAME; import static software.amazon.awssdk.core.client.config.SdkClientOption.RETRY_POLICY; @@ -66,6 +67,7 @@ import software.amazon.awssdk.http.SdkHttpClient; import software.amazon.awssdk.http.async.AsyncExecuteRequest; import software.amazon.awssdk.http.async.SdkAsyncHttpClient; +import software.amazon.awssdk.metrics.MetricPublisher; import software.amazon.awssdk.profiles.ProfileFile; import software.amazon.awssdk.profiles.ProfileFileSystemSetting; import software.amazon.awssdk.utils.AttributeMap; @@ -391,6 +393,11 @@ public final B httpClientBuilder(SdkAsyncHttpClient.Builder httpClientBuilder) { return thisBuilder(); } + public final B metricPublisher(MetricPublisher metricPublisher) { + clientConfiguration.option(METRIC_PUBLISHER, metricPublisher); + return thisBuilder(); + } + /** * Return "this" for method chaining. */ diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/client/config/SdkClientOption.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/client/config/SdkClientOption.java index 11c26163287d..98669b52dc2c 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/client/config/SdkClientOption.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/client/config/SdkClientOption.java @@ -27,6 +27,7 @@ import software.amazon.awssdk.core.retry.RetryPolicy; import software.amazon.awssdk.http.SdkHttpClient; import software.amazon.awssdk.http.async.SdkAsyncHttpClient; +import software.amazon.awssdk.metrics.MetricPublisher; import software.amazon.awssdk.profiles.ProfileFile; /** @@ -129,6 +130,8 @@ public final class SdkClientOption extends ClientOption { */ public static final SdkClientOption PROFILE_NAME = new SdkClientOption<>(String.class); + public static final SdkClientOption METRIC_PUBLISHER = new SdkClientOption<>(MetricPublisher.class); + private SdkClientOption(Class valueClass) { super(valueClass); } diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/client/handler/ClientExecutionParams.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/client/handler/ClientExecutionParams.java index 3d4b03dda61f..1b5320886fd2 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/client/handler/ClientExecutionParams.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/client/handler/ClientExecutionParams.java @@ -25,6 +25,7 @@ import software.amazon.awssdk.core.http.HttpResponseHandler; import software.amazon.awssdk.core.runtime.transform.Marshaller; import software.amazon.awssdk.core.sync.RequestBody; +import software.amazon.awssdk.metrics.MetricCollector; /** * Encapsulates parameters needed for a particular API call. Captures input and output pojo types. @@ -47,6 +48,7 @@ public final class ClientExecutionParams { private String hostPrefixExpression; private String operationName; private URI discoveredEndpoint; + private MetricCollector metricCollector; public Marshaller getMarshaller() { return marshaller; @@ -166,4 +168,13 @@ public ClientExecutionParams discoveredEndpoint(URI discoveredE this.discoveredEndpoint = discoveredEndpoint; return this; } + + public ClientExecutionParams withMetricCollector(MetricCollector metricCollector) { + this.metricCollector = metricCollector; + return this; + } + + public MetricCollector getMetricCollector() { + return metricCollector; + } } diff --git a/services/pom.xml b/services/pom.xml index d3d5d1432b8c..c8d8b5e9e2d0 100644 --- a/services/pom.xml +++ b/services/pom.xml @@ -292,6 +292,11 @@ software.amazon.awssdk ${awsjavasdk.version} + + software.amazon.awssdk + metrics-spi + ${awsjavasdk.version} + apache-client software.amazon.awssdk diff --git a/test/codegen-generated-classes-test/pom.xml b/test/codegen-generated-classes-test/pom.xml index 279a70810e29..9a8aa2e595a8 100644 --- a/test/codegen-generated-classes-test/pom.xml +++ b/test/codegen-generated-classes-test/pom.xml @@ -75,6 +75,11 @@ http-client-spi ${awsjavasdk.version} + + software.amazon.awssdk + metrics-spi + ${awsjavasdk.version} + software.amazon.awssdk sdk-core diff --git a/test/protocol-tests/pom.xml b/test/protocol-tests/pom.xml index ec28701980e1..6d58efef7945 100644 --- a/test/protocol-tests/pom.xml +++ b/test/protocol-tests/pom.xml @@ -83,6 +83,11 @@ http-client-spi ${awsjavasdk.version} + + software.amazon.awssdk + metrics-spi + ${awsjavasdk.version} + software.amazon.awssdk sdk-core