Skip to content

Commit 1e499bc

Browse files
authored
CloudTrail log request id and request name. (#268)
* Log request id and name for V1 and V2 SDK * Added test for injectCredentialsAndInvokeIterableV2
1 parent 1fbea70 commit 1e499bc

File tree

2 files changed

+89
-6
lines changed

2 files changed

+89
-6
lines changed

src/main/java/software/amazon/cloudformation/proxy/AmazonWebServicesClientProxy.java

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,9 @@ public final long getRemainingTimeInMillis() {
466466
request.setRequestCredentialsProvider(v1CredentialsProvider);
467467

468468
try {
469-
return requestFunction.apply(request);
469+
ResultT respose = requestFunction.apply(request);
470+
logRequestMetadata(request, respose);
471+
return respose;
470472
} catch (final Throwable e) {
471473
loggerProxy.log(String.format("Failed to execute remote function: {%s}", e.getMessage()));
472474
throw e;
@@ -486,7 +488,9 @@ public final long getRemainingTimeInMillis() {
486488
RequestT wrappedRequest = (RequestT) request.toBuilder().overrideConfiguration(overrideConfiguration).build();
487489

488490
try {
489-
return requestFunction.apply(wrappedRequest);
491+
ResultT response = requestFunction.apply(wrappedRequest);
492+
logRequestMetadataV2(request, response);
493+
return response;
490494
} catch (final Throwable e) {
491495
loggerProxy.log(String.format("Failed to execute remote function: {%s}", e.getMessage()));
492496
throw e;
@@ -505,7 +509,11 @@ public final long getRemainingTimeInMillis() {
505509
RequestT wrappedRequest = (RequestT) request.toBuilder().overrideConfiguration(overrideConfiguration).build();
506510

507511
try {
508-
return requestFunction.apply(wrappedRequest);
512+
CompletableFuture<ResultT> response = requestFunction.apply(wrappedRequest).thenApplyAsync(resultT -> {
513+
logRequestMetadataV2(request, resultT);
514+
return resultT;
515+
});
516+
return response;
509517
} catch (final Throwable e) {
510518
loggerProxy.log(String.format("Failed to execute remote function: {%s}", e.getMessage()));
511519
throw e;
@@ -523,7 +531,9 @@ public final long getRemainingTimeInMillis() {
523531
RequestT wrappedRequest = (RequestT) request.toBuilder().overrideConfiguration(overrideConfiguration).build();
524532

525533
try {
526-
return requestFunction.apply(wrappedRequest);
534+
IterableT response = requestFunction.apply(wrappedRequest);
535+
response.forEach(r -> logRequestMetadataV2(request, r));
536+
return response;
527537
} catch (final Throwable e) {
528538
loggerProxy.log(String.format("Failed to execute remote function: {%s}", e.getMessage()));
529539
throw e;
@@ -542,7 +552,9 @@ public final long getRemainingTimeInMillis() {
542552
RequestT wrappedRequest = (RequestT) request.toBuilder().overrideConfiguration(overrideConfiguration).build();
543553

544554
try {
545-
return requestFunction.apply(wrappedRequest);
555+
ResponseInputStream<ResultT> response = requestFunction.apply(wrappedRequest);
556+
logRequestMetadataV2(request, response.response());
557+
return response;
546558
} catch (final Throwable e) {
547559
loggerProxy.log(String.format("Failed to execute remote function: {%s}", e.getMessage()));
548560
throw e;
@@ -561,7 +573,9 @@ public final long getRemainingTimeInMillis() {
561573
RequestT wrappedRequest = (RequestT) request.toBuilder().overrideConfiguration(overrideConfiguration).build();
562574

563575
try {
564-
return requestFunction.apply(wrappedRequest);
576+
ResponseBytes<ResultT> response = requestFunction.apply(wrappedRequest);
577+
logRequestMetadataV2(request, response.response());
578+
return response;
565579
} catch (final Throwable e) {
566580
loggerProxy.log(String.format("Failed to execute remote function: {%s}", e.getMessage()));
567581
throw e;
@@ -623,4 +637,33 @@ public final long getRemainingTimeInMillis() {
623637
return ProgressEvent.failed(model, context, HandlerErrorCode.InternalFailure, e.getMessage());
624638

625639
}
640+
641+
private <RequestT extends AmazonWebServiceRequest, ResultT extends AmazonWebServiceResult<ResponseMetadata>>
642+
void
643+
logRequestMetadata(final RequestT request, final ResultT response) {
644+
try {
645+
String requestName = request.getClass().getSimpleName();
646+
String requestId = (response == null || response.getSdkResponseMetadata() == null)
647+
? ""
648+
: response.getSdkResponseMetadata().getRequestId();
649+
loggerProxy
650+
.log(String.format("{\"apiRequest\": {\"requestId\": \"%s\", \"requestName\": \"%s\"}}", requestId, requestName));
651+
} catch (final Exception e) {
652+
loggerProxy.log(e.getMessage());
653+
}
654+
}
655+
656+
private <RequestT extends AwsRequest, ResultT extends AwsResponse> void logRequestMetadataV2(final RequestT request,
657+
final ResultT response) {
658+
try {
659+
String requestName = request.getClass().getSimpleName();
660+
String requestId = (response == null || response.responseMetadata() == null)
661+
? ""
662+
: response.responseMetadata().requestId();
663+
loggerProxy
664+
.log(String.format("{\"apiRequest\": {\"requestId\": \"%s\", \"requestName\": \"%s\"}}", requestId, requestName));
665+
} catch (final Exception e) {
666+
loggerProxy.log(e.getMessage());
667+
}
668+
}
626669
}

src/test/java/software/amazon/cloudformation/proxy/AmazonWebServicesClientProxyTest.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,20 @@
4242
import software.amazon.awssdk.auth.credentials.AwsSessionCredentials;
4343
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
4444
import software.amazon.awssdk.awscore.AwsRequestOverrideConfiguration;
45+
import software.amazon.awssdk.awscore.AwsResponse;
4546
import software.amazon.awssdk.awscore.exception.AwsErrorDetails;
4647
import software.amazon.awssdk.awscore.exception.AwsServiceException;
4748
import software.amazon.awssdk.core.ResponseBytes;
4849
import software.amazon.awssdk.core.ResponseInputStream;
4950
import software.amazon.awssdk.core.exception.NonRetryableException;
51+
import software.amazon.awssdk.core.pagination.sync.SdkIterable;
5052
import software.amazon.awssdk.http.SdkHttpResponse;
5153
import software.amazon.awssdk.services.cloudformation.CloudFormationAsyncClient;
5254
import software.amazon.awssdk.services.cloudformation.CloudFormationClient;
5355
import software.amazon.awssdk.services.cloudformation.model.DescribeStackEventsResponse;
5456
import software.amazon.awssdk.services.s3.S3Client;
5557
import software.amazon.awssdk.services.s3.model.GetObjectResponse;
58+
import software.amazon.awssdk.services.s3.paginators.ListObjectsV2Iterable;
5659
import software.amazon.cloudformation.exceptions.ResourceAlreadyExistsException;
5760
import software.amazon.cloudformation.exceptions.TerminalException;
5861
import software.amazon.cloudformation.proxy.delay.Constant;
@@ -160,6 +163,43 @@ public void testInjectCredentialsAndInvokeV2() {
160163
assertThat(result).isEqualTo(expectedResult);
161164
}
162165

166+
@Test
167+
public <ResultT extends AwsResponse, IterableT extends SdkIterable<ResultT>> void testInjectCredentialsAndInvokeV2Iterable() {
168+
169+
final LoggerProxy loggerProxy = mock(LoggerProxy.class);
170+
final Credentials credentials = new Credentials("accessKeyId", "secretAccessKey", "sessionToken");
171+
final ListObjectsV2Iterable response = mock(ListObjectsV2Iterable.class);
172+
173+
final AmazonWebServicesClientProxy proxy = new AmazonWebServicesClientProxy(loggerProxy, credentials, () -> 1000L);
174+
175+
final software.amazon.awssdk.services.s3.model.ListObjectsV2Request wrappedRequest = mock(
176+
software.amazon.awssdk.services.s3.model.ListObjectsV2Request.class);
177+
178+
final software.amazon.awssdk.services.s3.model.ListObjectsV2Request.Builder builder = mock(
179+
software.amazon.awssdk.services.s3.model.ListObjectsV2Request.Builder.class);
180+
when(builder.overrideConfiguration(any(AwsRequestOverrideConfiguration.class))).thenReturn(builder);
181+
when(builder.build()).thenReturn(wrappedRequest);
182+
final software.amazon.awssdk.services.s3.model.ListObjectsV2Request request = mock(
183+
software.amazon.awssdk.services.s3.model.ListObjectsV2Request.class);
184+
when(request.toBuilder()).thenReturn(builder);
185+
186+
final S3Client client = mock(S3Client.class);
187+
188+
when(client.listObjectsV2Paginator(any(software.amazon.awssdk.services.s3.model.ListObjectsV2Request.class)))
189+
.thenReturn(response);
190+
191+
final ListObjectsV2Iterable result = proxy.injectCredentialsAndInvokeIterableV2(request, client::listObjectsV2Paginator);
192+
193+
// verify request is rebuilt for injection
194+
verify(request).toBuilder();
195+
196+
// verify the wrapped request is sent over the initiate
197+
verify(client).listObjectsV2Paginator(wrappedRequest);
198+
199+
// ensure the return type matches
200+
assertThat(result).isEqualTo(response);
201+
}
202+
163203
@Test
164204
public void testInjectCredentialsAndInvokeV2Async() throws ExecutionException, InterruptedException {
165205

0 commit comments

Comments
 (0)