Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

do not merge: sample diff #5833

Closed
wants to merge 8 commits into from
Closed
6 changes: 6 additions & 0 deletions .changes/next-release/feature-AWSSDKforJavav2-e255a31.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"type": "feature",
"category": "AWS SDK for Java v2",
"contributor": "RanVaknin",
"description": "Add retry attempt count to exception messages to improve debugging visibility."
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import software.amazon.awssdk.annotations.SdkPublicApi;
import software.amazon.awssdk.awscore.internal.AwsErrorCode;
import software.amazon.awssdk.awscore.internal.AwsStatusCode;
import software.amazon.awssdk.core.exception.SdkDiagnostics;
import software.amazon.awssdk.core.exception.SdkServiceException;
import software.amazon.awssdk.core.retry.ClockSkew;
import software.amazon.awssdk.http.SdkHttpResponse;
Expand Down Expand Up @@ -60,25 +61,36 @@ public AwsErrorDetails awsErrorDetails() {

@Override
public String getMessage() {
StringJoiner joiner = new StringJoiner(" ");
String primaryMessage = rawMessage();
if (primaryMessage == null && awsErrorDetails != null) {
primaryMessage = awsErrorDetails.errorMessage();
}
if (primaryMessage != null) {
joiner.add(primaryMessage);
}

if (awsErrorDetails != null) {
StringJoiner details = new StringJoiner(", ", "(", ")");
details.add("Service: " + awsErrorDetails().serviceName());
details.add("Status Code: " + statusCode());
details.add("Request ID: " + requestId());
if (extendedRequestId() != null) {
details.add("Extended Request ID: " + extendedRequestId());
}
String message = super.getMessage();
if (message == null) {
message = awsErrorDetails().errorMessage();
}
if (message == null) {
return details.toString();
}
return message + " " + details;
joiner.add(serviceDiagnostics());
}

return super.getMessage();
if (numAttempts() != null) {
SdkDiagnostics diagnostics = SdkDiagnostics.builder().numAttempts(numAttempts()).build();
joiner.add(diagnostics.toString());
}

return joiner.toString();
}

private String serviceDiagnostics() {
StringJoiner details = new StringJoiner(", ", "(", ")");
details.add("Service: " + awsErrorDetails().serviceName());
details.add("Status Code: " + statusCode());
details.add("Request ID: " + requestId());
if (extendedRequestId() != null) {
details.add("Extended Request ID: " + extendedRequestId());
}
return details.toString();
}

@Override
Expand Down Expand Up @@ -116,9 +128,9 @@ public boolean isClockSkewException() {
@Override
public boolean isThrottlingException() {
return super.isThrottlingException() ||
Optional.ofNullable(awsErrorDetails)
.map(a -> AwsErrorCode.isThrottlingErrorCode(a.errorCode()))
.orElse(false);
Optional.ofNullable(awsErrorDetails)
.map(a -> AwsErrorCode.isThrottlingErrorCode(a.errorCode()))
.orElse(false);
}

/**
Expand Down Expand Up @@ -173,6 +185,9 @@ public interface Builder extends SdkServiceException.Builder {
@Override
Builder message(String message);

@Override
Builder numAttempts(Integer numAttempts);

@Override
Builder cause(Throwable t);

Expand Down Expand Up @@ -238,6 +253,12 @@ public Builder message(String message) {
return this;
}

@Override
public Builder numAttempts(Integer numAttempts) {
this.numAttempts = numAttempts;
return this;
}

@Override
public Builder cause(Throwable cause) {
this.cause = cause;
Expand Down Expand Up @@ -273,4 +294,4 @@ public AwsServiceException build() {
return new AwsServiceException(this);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,48 +31,32 @@
public class AwsServiceExceptionSerializationTest {

@Test
public void serializeServiceException() throws Exception {
public void serializeBasicServiceException() throws Exception {
AwsServiceException expectedException = createException();

ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
objectOutputStream.writeObject(expectedException);
objectOutputStream.flush();
objectOutputStream.close();

ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(outputStream.toByteArray()));
AwsServiceException resultException = (AwsServiceException) ois.readObject();

AwsServiceException resultException = serializeServiceException(expectedException);
assertSameValues(resultException, expectedException);
}

private void assertSameValues(AwsServiceException resultException, AwsServiceException expectedException) {
assertThat(resultException.getMessage()).isEqualTo(expectedException.getMessage());
assertThat(resultException.requestId()).isEqualTo(expectedException.requestId());
assertThat(resultException.extendedRequestId()).isEqualTo(expectedException.extendedRequestId());
assertThat(resultException.toBuilder().clockSkew()).isEqualTo(expectedException.toBuilder().clockSkew());
assertThat(resultException.toBuilder().cause().getMessage()).isEqualTo(expectedException.toBuilder().cause().getMessage());
assertThat(resultException.awsErrorDetails()).isEqualTo(expectedException.awsErrorDetails());
@Test
public void serializeRetryableServiceException() throws Exception {
AwsServiceException expectedException = createRetryableServiceException();
AwsServiceException resultException = serializeServiceException(expectedException);
assertSameValues(resultException, expectedException);
}

private void assertSameValues(AwsServiceException result, AwsServiceException expected) {
assertThat(result.getMessage()).isEqualTo(expected.getMessage());
assertThat(result.requestId()).isEqualTo(expected.requestId());
assertThat(result.extendedRequestId()).isEqualTo(expected.extendedRequestId());
assertThat(result.toBuilder().clockSkew()).isEqualTo(expected.toBuilder().clockSkew());
assertThat(result.toBuilder().cause().getMessage()).isEqualTo(expected.toBuilder().cause().getMessage());
assertThat(result.awsErrorDetails()).isEqualTo(expected.awsErrorDetails());
assertThat(result.numAttempts()).isEqualTo(expected.numAttempts());
}

private AwsServiceException createException() {
AbortableInputStream contentStream = AbortableInputStream.create(new StringInputStream("some content"));
SdkHttpResponse httpResponse = SdkHttpFullResponse.builder()
.statusCode(403)
.statusText("SomeText")
.content(contentStream)
.build();

AwsErrorDetails errorDetails = AwsErrorDetails.builder()
.errorCode("someCode")
.errorMessage("message")
.serviceName("someService")
.sdkHttpResponse(httpResponse)
.build();

return AwsServiceException.builder()
.awsErrorDetails(errorDetails)
.awsErrorDetails(createErrorDetails(403, "SomeText"))
.statusCode(403)
.cause(new RuntimeException("someThrowable"))
.clockSkew(Duration.ofSeconds(2))
Expand All @@ -81,4 +65,44 @@ private AwsServiceException createException() {
.message("message")
.build();
}

private AwsServiceException createRetryableServiceException() {
return AwsServiceException.builder()
.awsErrorDetails(createErrorDetails(429, "Throttling"))
.statusCode(429)
.cause(new RuntimeException("someThrowable"))
.clockSkew(Duration.ofSeconds(2))
.requestId("requestId")
.extendedRequestId("extendedRequestId")
.message("message")
.numAttempts(3)
.build();
}

private AwsErrorDetails createErrorDetails(int statusCode, String statusText) {
AbortableInputStream contentStream = AbortableInputStream.create(new StringInputStream("some content"));
SdkHttpResponse httpResponse = SdkHttpFullResponse.builder()
.statusCode(statusCode)
.statusText(statusText)
.content(contentStream)
.build();

return AwsErrorDetails.builder()
.errorCode("someCode")
.errorMessage("message")
.serviceName("someService")
.sdkHttpResponse(httpResponse)
.build();
}

private AwsServiceException serializeServiceException(AwsServiceException exception) throws Exception {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
objectOutputStream.writeObject(exception);
objectOutputStream.flush();
objectOutputStream.close();

ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(outputStream.toByteArray()));
return (AwsServiceException) ois.readObject();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public void exceptionMessage_withExtendedRequestId() {
.requestId("requestId")
.extendedRequestId("extendedRequestId")
.build();
assertThat(e.getMessage()).isEqualTo("errorMessage (Service: serviceName, Status Code: 500, Request ID: requestId, "
assertThat(e.getMessage()).isEqualTo("errorMessage (Service: serviceName, Status Code: 500, Request ID: requestId, "
+ "Extended Request ID: extendedRequestId)");
}

Expand All @@ -82,6 +82,60 @@ public void exceptionMessage_withoutExtendedRequestId() {
assertThat(e.getMessage()).isEqualTo("errorMessage (Service: serviceName, Status Code: 500, Request ID: requestId)");
}

@Test
public void exceptionMessage_withAttempts() {
AwsServiceException e = AwsServiceException.builder()
.message("errorMessage")
.numAttempts(6)
.awsErrorDetails(AwsErrorDetails.builder()
.errorMessage("errorMessage")
.serviceName("serviceName")
.errorCode("errorCode")
.build())
.statusCode(500)
.requestId("requestId")
.build();

assertThat(e.getMessage()).contains("(SDK Diagnostics: numAttempts = 6)");
assertThat(e.numAttempts()).isEqualTo(6);
}

@Test
public void exceptionMessage_zeroAttempts() {
AwsServiceException e = (AwsServiceException) AwsServiceException.builder()
.awsErrorDetails(AwsErrorDetails.builder()
.errorMessage("errorMessage")
.serviceName("serviceName")
.errorCode("errorCode")
.build())
.statusCode(500)
.requestId("requestId")
.numAttempts(0)
.build();

assertThat(e.getMessage()).contains("errorMessage (Service: serviceName, Status Code: 500, " +
"Request ID: requestId)");
assertThat(e.numAttempts()).isEqualTo(0);
}

@Test
public void setAttempts_modifiesMessage() {
AwsServiceException e = AwsServiceException.builder()
.numAttempts(3)
.awsErrorDetails(AwsErrorDetails.builder()
.errorMessage("errorMessage")
.serviceName("serviceName")
.errorCode("errorCode")
.build())
.statusCode(500)
.requestId("requestId")
.build();

assertThat(e.getMessage()).isEqualTo("errorMessage (Service: serviceName, Status Code: 500, " +
"Request ID: requestId) (SDK Diagnostics: numAttempts = 3)");
assertThat(e.numAttempts()).isEqualTo(3);
}

@Test
public void exceptionMessage_withoutErrorMessage() {
AwsServiceException e = AwsServiceException.builder()
Expand Down Expand Up @@ -115,19 +169,19 @@ public void assertNotSkewed(int clientSideTimeOffset,

private AwsServiceException exception(int clientSideTimeOffset, String errorCode, int statusCode, String serverDate) {
SdkHttpResponse httpResponse =
SdkHttpFullResponse.builder()
.statusCode(statusCode)
.applyMutation(r -> {
if (serverDate != null) {
r.putHeader("Date", serverDate);
}
})
.build();
AwsErrorDetails errorDetails =
AwsErrorDetails.builder()
.errorCode(errorCode)
.sdkHttpResponse(httpResponse)
SdkHttpFullResponse.builder()
.statusCode(statusCode)
.applyMutation(r -> {
if (serverDate != null) {
r.putHeader("Date", serverDate);
}
})
.build();
AwsErrorDetails errorDetails =
AwsErrorDetails.builder()
.errorCode(errorCode)
.sdkHttpResponse(httpResponse)
.build();

return AwsServiceException.builder()
.clockSkew(Duration.ofSeconds(clientSideTimeOffset))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,16 @@ public static SdkClientException create(String message, Throwable cause) {
return SdkClientException.builder().message(message).cause(cause).build();
}

@Override
public String getMessage() {
String message = rawMessage();
if (numAttempts() != null) {
SdkDiagnostics sdkDiagnostics = SdkDiagnostics.builder().numAttempts(numAttempts()).build();
message = message + " (" + sdkDiagnostics + ")";
}
return message;
}

/**
* Create a {@link Builder} initialized with the properties of this {@code SdkClientException}.
*
Expand Down Expand Up @@ -111,4 +121,4 @@ public SdkClientException build() {
return new SdkClientException(this);
}
}
}
}
Loading
Loading