Skip to content

Commit fe68709

Browse files
authored
Adding attempt count to error message (#5834)
* Adding attempt count to error message * Added changelog * Fix tests * Fix HttpChecksumValidationTest * Adding copyableBuilder and fixing tests * Fix Checkstyle * Remove casting * Fixing tests * Adding default to builder iface * Fix checkstyle * Fixing comments, making sure attempt 0 is truncated * Fix incorrect builder impl * Fixing override method to exclude attempts = 0 * Adding numattempts to all exceptions * Added needed getter builder methods to generated exceptions * Removing builder getters from codegen and child exception classes * Removing numattempts larger than 0 valiadations --------- Co-authored-by: Ran Vaknin <[email protected]>
1 parent 9f735a1 commit fe68709

File tree

28 files changed

+667
-79
lines changed

28 files changed

+667
-79
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"type": "feature",
3+
"category": "AWS SDK for Java v2",
4+
"contributor": "",
5+
"description": "Add retry attempt count to exception messages to improve debugging visibility."
6+
}

codegen/src/main/java/software/amazon/awssdk/codegen/poet/model/ExceptionProperties.java

+5-2
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ public static List<MethodSpec> builderInterfaceMethods(ClassName className) {
3434
builderMethod(className, "requestId", String.class),
3535
builderMethod(className, "statusCode", int.class),
3636
builderMethod(className, "cause", Throwable.class),
37-
builderMethod(className, "writableStackTrace", Boolean.class));
37+
builderMethod(className, "writableStackTrace", Boolean.class),
38+
builderMethod(className, "numAttempts", Integer.class));
39+
3840
}
3941

4042
public static List<MethodSpec> builderImplMethods(ClassName className) {
@@ -44,7 +46,8 @@ public static List<MethodSpec> builderImplMethods(ClassName className) {
4446
builderImplMethods(className, "requestId", String.class),
4547
builderImplMethods(className, "statusCode", int.class),
4648
builderImplMethods(className, "cause", Throwable.class),
47-
builderImplMethods(className, "writableStackTrace", Boolean.class));
49+
builderImplMethods(className, "writableStackTrace", Boolean.class),
50+
builderImplMethods(className, "numAttempts", Integer.class));
4851
}
4952

5053
private static MethodSpec builderMethod(ClassName className, String name, Class clazz) {

codegen/src/main/resources/software/amazon/awssdk/codegen/rules/SourceException.java.resource

+9
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ public class SourceException extends SdkException {
2323

2424
@Override
2525
SourceException build();
26+
27+
@Override
28+
Builder numAttempts(Integer numAttempts);
2629
}
2730

2831
public static class BuilderImpl extends SdkException.BuilderImpl implements Builder {
@@ -48,5 +51,11 @@ public class SourceException extends SdkException {
4851
public SourceException build() {
4952
return new SourceException(this);
5053
}
54+
55+
@Override
56+
public Builder numAttempts(Integer numAttempts) {
57+
super.numAttempts(numAttempts);
58+
return this;
59+
}
5160
}
5261
}

codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/baseserviceexception.java

+9
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ public interface Builder extends AwsServiceException.Builder {
4040

4141
@Override
4242
Builder writableStackTrace(Boolean writableStackTrace);
43+
44+
@Override
45+
Builder numAttempts(Integer numAttempts);
4346
}
4447

4548
protected static class BuilderImpl extends AwsServiceException.BuilderImpl implements Builder {
@@ -86,6 +89,12 @@ public BuilderImpl writableStackTrace(Boolean writableStackTrace) {
8689
return this;
8790
}
8891

92+
@Override
93+
public BuilderImpl numAttempts(Integer numAttempts) {
94+
this.numAttempts = numAttempts;
95+
return this;
96+
}
97+
8998
@Override
9099
public JsonProtocolTestsException build() {
91100
return new JsonProtocolTestsException(this);

codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/emptymodeledexception.java

+9
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ public interface Builder extends SdkPojo, CopyableBuilder<Builder, EmptyModeledE
7070

7171
@Override
7272
Builder writableStackTrace(Boolean writableStackTrace);
73+
74+
@Override
75+
Builder numAttempts(Integer numAttempts);
7376
}
7477

7578
static final class BuilderImpl extends JsonProtocolTestsException.BuilderImpl implements Builder {
@@ -116,6 +119,12 @@ public BuilderImpl writableStackTrace(Boolean writableStackTrace) {
116119
return this;
117120
}
118121

122+
@Override
123+
public BuilderImpl numAttempts(Integer numAttempts) {
124+
this.numAttempts = numAttempts;
125+
return this;
126+
}
127+
119128
@Override
120129
public EmptyModeledException build() {
121130
return new EmptyModeledException(this);

codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/exceptions/jsonserviceinternalservererrorexception.java

+9
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ public interface Builder extends SdkPojo, CopyableBuilder<Builder, JsonServiceIn
7979

8080
@Override
8181
Builder writableStackTrace(Boolean writableStackTrace);
82+
83+
@Override
84+
Builder numAttempts(Integer numAttempts);
8285
}
8386

8487
static final class BuilderImpl extends JsonException.BuilderImpl implements Builder {
@@ -125,6 +128,12 @@ public BuilderImpl writableStackTrace(Boolean writableStackTrace) {
125128
return this;
126129
}
127130

131+
@Override
132+
public BuilderImpl numAttempts(Integer numAttempts) {
133+
this.numAttempts = numAttempts;
134+
return this;
135+
}
136+
128137
@Override
129138
public JsonServiceInternalServerErrorException build() {
130139
return new JsonServiceInternalServerErrorException(this);

codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/exceptions/jsonserviceinvalidinputexception.java

+9
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ public interface Builder extends SdkPojo, CopyableBuilder<Builder, JsonServiceIn
7373

7474
@Override
7575
Builder writableStackTrace(Boolean writableStackTrace);
76+
77+
@Override
78+
Builder numAttempts(Integer numAttempts);
7679
}
7780

7881
static final class BuilderImpl extends JsonException.BuilderImpl implements Builder {
@@ -119,6 +122,12 @@ public BuilderImpl writableStackTrace(Boolean writableStackTrace) {
119122
return this;
120123
}
121124

125+
@Override
126+
public BuilderImpl numAttempts(Integer numAttempts) {
127+
this.numAttempts = numAttempts;
128+
return this;
129+
}
130+
122131
@Override
123132
public JsonServiceInvalidInputException build() {
124133
return new JsonServiceInvalidInputException(this);

codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/exceptions/jsonservicethrottlingexception.java

+9
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ public interface Builder extends SdkPojo, CopyableBuilder<Builder, JsonServiceTh
8383

8484
@Override
8585
Builder writableStackTrace(Boolean writableStackTrace);
86+
87+
@Override
88+
Builder numAttempts(Integer numAttempts);
8689
}
8790

8891
static final class BuilderImpl extends JsonException.BuilderImpl implements Builder {
@@ -129,6 +132,12 @@ public BuilderImpl writableStackTrace(Boolean writableStackTrace) {
129132
return this;
130133
}
131134

135+
@Override
136+
public BuilderImpl numAttempts(Integer numAttempts) {
137+
this.numAttempts = numAttempts;
138+
return this;
139+
}
140+
132141
@Override
133142
public JsonServiceThrottlingException build() {
134143
return new JsonServiceThrottlingException(this);

core/aws-core/src/main/java/software/amazon/awssdk/awscore/exception/AwsServiceException.java

+41-20
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import software.amazon.awssdk.annotations.SdkPublicApi;
2323
import software.amazon.awssdk.awscore.internal.AwsErrorCode;
2424
import software.amazon.awssdk.awscore.internal.AwsStatusCode;
25+
import software.amazon.awssdk.core.exception.SdkDiagnostics;
2526
import software.amazon.awssdk.core.exception.SdkServiceException;
2627
import software.amazon.awssdk.core.retry.ClockSkew;
2728
import software.amazon.awssdk.http.SdkHttpResponse;
@@ -60,25 +61,36 @@ public AwsErrorDetails awsErrorDetails() {
6061

6162
@Override
6263
public String getMessage() {
64+
StringJoiner joiner = new StringJoiner(" ");
65+
String primaryMessage = rawMessage();
66+
if (primaryMessage == null && awsErrorDetails != null) {
67+
primaryMessage = awsErrorDetails.errorMessage();
68+
}
69+
if (primaryMessage != null) {
70+
joiner.add(primaryMessage);
71+
}
72+
6373
if (awsErrorDetails != null) {
64-
StringJoiner details = new StringJoiner(", ", "(", ")");
65-
details.add("Service: " + awsErrorDetails().serviceName());
66-
details.add("Status Code: " + statusCode());
67-
details.add("Request ID: " + requestId());
68-
if (extendedRequestId() != null) {
69-
details.add("Extended Request ID: " + extendedRequestId());
70-
}
71-
String message = super.getMessage();
72-
if (message == null) {
73-
message = awsErrorDetails().errorMessage();
74-
}
75-
if (message == null) {
76-
return details.toString();
77-
}
78-
return message + " " + details;
74+
joiner.add(serviceDiagnostics());
7975
}
8076

81-
return super.getMessage();
77+
if (numAttempts() != null) {
78+
SdkDiagnostics diagnostics = SdkDiagnostics.builder().numAttempts(numAttempts()).build();
79+
joiner.add(diagnostics.toString());
80+
}
81+
82+
return joiner.toString();
83+
}
84+
85+
private String serviceDiagnostics() {
86+
StringJoiner details = new StringJoiner(", ", "(", ")");
87+
details.add("Service: " + awsErrorDetails().serviceName());
88+
details.add("Status Code: " + statusCode());
89+
details.add("Request ID: " + requestId());
90+
if (extendedRequestId() != null) {
91+
details.add("Extended Request ID: " + extendedRequestId());
92+
}
93+
return details.toString();
8294
}
8395

8496
@Override
@@ -116,9 +128,9 @@ public boolean isClockSkewException() {
116128
@Override
117129
public boolean isThrottlingException() {
118130
return super.isThrottlingException() ||
119-
Optional.ofNullable(awsErrorDetails)
120-
.map(a -> AwsErrorCode.isThrottlingErrorCode(a.errorCode()))
121-
.orElse(false);
131+
Optional.ofNullable(awsErrorDetails)
132+
.map(a -> AwsErrorCode.isThrottlingErrorCode(a.errorCode()))
133+
.orElse(false);
122134
}
123135

124136
/**
@@ -173,6 +185,9 @@ public interface Builder extends SdkServiceException.Builder {
173185
@Override
174186
Builder message(String message);
175187

188+
@Override
189+
Builder numAttempts(Integer numAttempts);
190+
176191
@Override
177192
Builder cause(Throwable t);
178193

@@ -238,6 +253,12 @@ public Builder message(String message) {
238253
return this;
239254
}
240255

256+
@Override
257+
public Builder numAttempts(Integer numAttempts) {
258+
this.numAttempts = numAttempts;
259+
return this;
260+
}
261+
241262
@Override
242263
public Builder cause(Throwable cause) {
243264
this.cause = cause;
@@ -273,4 +294,4 @@ public AwsServiceException build() {
273294
return new AwsServiceException(this);
274295
}
275296
}
276-
}
297+
}

core/aws-core/src/test/java/software/amazon/awssdk/awscore/exception/AwsServiceExceptionSerializationTest.java

+57-33
Original file line numberDiff line numberDiff line change
@@ -31,48 +31,32 @@
3131
public class AwsServiceExceptionSerializationTest {
3232

3333
@Test
34-
public void serializeServiceException() throws Exception {
34+
public void serializeBasicServiceException() throws Exception {
3535
AwsServiceException expectedException = createException();
36-
37-
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
38-
ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
39-
objectOutputStream.writeObject(expectedException);
40-
objectOutputStream.flush();
41-
objectOutputStream.close();
42-
43-
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(outputStream.toByteArray()));
44-
AwsServiceException resultException = (AwsServiceException) ois.readObject();
45-
36+
AwsServiceException resultException = serializeServiceException(expectedException);
4637
assertSameValues(resultException, expectedException);
4738
}
4839

49-
private void assertSameValues(AwsServiceException resultException, AwsServiceException expectedException) {
50-
assertThat(resultException.getMessage()).isEqualTo(expectedException.getMessage());
51-
assertThat(resultException.requestId()).isEqualTo(expectedException.requestId());
52-
assertThat(resultException.extendedRequestId()).isEqualTo(expectedException.extendedRequestId());
53-
assertThat(resultException.toBuilder().clockSkew()).isEqualTo(expectedException.toBuilder().clockSkew());
54-
assertThat(resultException.toBuilder().cause().getMessage()).isEqualTo(expectedException.toBuilder().cause().getMessage());
55-
assertThat(resultException.awsErrorDetails()).isEqualTo(expectedException.awsErrorDetails());
40+
@Test
41+
public void serializeRetryableServiceException() throws Exception {
42+
AwsServiceException expectedException = createRetryableServiceException();
43+
AwsServiceException resultException = serializeServiceException(expectedException);
44+
assertSameValues(resultException, expectedException);
5645
}
5746

47+
private void assertSameValues(AwsServiceException result, AwsServiceException expected) {
48+
assertThat(result.getMessage()).isEqualTo(expected.getMessage());
49+
assertThat(result.requestId()).isEqualTo(expected.requestId());
50+
assertThat(result.extendedRequestId()).isEqualTo(expected.extendedRequestId());
51+
assertThat(result.toBuilder().clockSkew()).isEqualTo(expected.toBuilder().clockSkew());
52+
assertThat(result.toBuilder().cause().getMessage()).isEqualTo(expected.toBuilder().cause().getMessage());
53+
assertThat(result.awsErrorDetails()).isEqualTo(expected.awsErrorDetails());
54+
assertThat(result.numAttempts()).isEqualTo(expected.numAttempts());
55+
}
5856

5957
private AwsServiceException createException() {
60-
AbortableInputStream contentStream = AbortableInputStream.create(new StringInputStream("some content"));
61-
SdkHttpResponse httpResponse = SdkHttpFullResponse.builder()
62-
.statusCode(403)
63-
.statusText("SomeText")
64-
.content(contentStream)
65-
.build();
66-
67-
AwsErrorDetails errorDetails = AwsErrorDetails.builder()
68-
.errorCode("someCode")
69-
.errorMessage("message")
70-
.serviceName("someService")
71-
.sdkHttpResponse(httpResponse)
72-
.build();
73-
7458
return AwsServiceException.builder()
75-
.awsErrorDetails(errorDetails)
59+
.awsErrorDetails(createErrorDetails(403, "SomeText"))
7660
.statusCode(403)
7761
.cause(new RuntimeException("someThrowable"))
7862
.clockSkew(Duration.ofSeconds(2))
@@ -81,4 +65,44 @@ private AwsServiceException createException() {
8165
.message("message")
8266
.build();
8367
}
68+
69+
private AwsServiceException createRetryableServiceException() {
70+
return AwsServiceException.builder()
71+
.awsErrorDetails(createErrorDetails(429, "Throttling"))
72+
.statusCode(429)
73+
.cause(new RuntimeException("someThrowable"))
74+
.clockSkew(Duration.ofSeconds(2))
75+
.requestId("requestId")
76+
.extendedRequestId("extendedRequestId")
77+
.message("message")
78+
.numAttempts(3)
79+
.build();
80+
}
81+
82+
private AwsErrorDetails createErrorDetails(int statusCode, String statusText) {
83+
AbortableInputStream contentStream = AbortableInputStream.create(new StringInputStream("some content"));
84+
SdkHttpResponse httpResponse = SdkHttpFullResponse.builder()
85+
.statusCode(statusCode)
86+
.statusText(statusText)
87+
.content(contentStream)
88+
.build();
89+
90+
return AwsErrorDetails.builder()
91+
.errorCode("someCode")
92+
.errorMessage("message")
93+
.serviceName("someService")
94+
.sdkHttpResponse(httpResponse)
95+
.build();
96+
}
97+
98+
private AwsServiceException serializeServiceException(AwsServiceException exception) throws Exception {
99+
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
100+
ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
101+
objectOutputStream.writeObject(exception);
102+
objectOutputStream.flush();
103+
objectOutputStream.close();
104+
105+
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(outputStream.toByteArray()));
106+
return (AwsServiceException) ois.readObject();
107+
}
84108
}

0 commit comments

Comments
 (0)