Skip to content

Commit 63af4df

Browse files
Sarev0kmillems
authored andcommitted
Expose the extendedRequestId from SdkServiceException, so it can be provided to support to investigate issues
1 parent abab62e commit 63af4df

File tree

10 files changed

+175
-1
lines changed

10 files changed

+175
-1
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"category": "AWS SDK for Java v2",
3+
"type": "feature",
4+
"description": "Expose the `extendedRequestId` from `SdkServiceException`, so it can be provided to support to investigate issues."
5+
}

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ public String getMessage() {
6565
return awsErrorDetails().errorMessage() +
6666
" (Service: " + awsErrorDetails().serviceName() +
6767
", Status Code: " + statusCode() +
68-
", Request ID: " + requestId() + ")";
68+
", Request ID: " + requestId() +
69+
", Extended Request ID: " + extendedRequestId() + ")";
6970
}
7071

7172
return super.getMessage();
@@ -164,6 +165,9 @@ public interface Builder extends SdkServiceException.Builder {
164165
@Override
165166
Builder requestId(String requestId);
166167

168+
@Override
169+
Builder extendedRequestId(String extendedRequestId);
170+
167171
@Override
168172
Builder statusCode(int statusCode);
169173

@@ -232,6 +236,12 @@ public Builder requestId(String requestId) {
232236
return this;
233237
}
234238

239+
@Override
240+
public Builder extendedRequestId(String extendedRequestId) {
241+
this.extendedRequestId = extendedRequestId;
242+
return this;
243+
}
244+
235245
@Override
236246
public Builder statusCode(int statusCode) {
237247
this.statusCode = statusCode;

core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/AwsJsonProtocolErrorUnmarshaller.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ private AwsServiceException unmarshall(SdkHttpFullResponse response, ExecutionAt
8585
exception.message(errorMessage);
8686
exception.statusCode(statusCode(response, modeledExceptionMetadata));
8787
exception.requestId(getRequestIdFromHeaders(response.headers()));
88+
exception.extendedRequestId(getExtendedRequestIdFromHeaders(response.headers()));
8889
return exception.build();
8990
}
9091

@@ -136,6 +137,10 @@ private String getRequestIdFromHeaders(Map<String, List<String>> headers) {
136137
return SdkHttpUtils.firstMatchingHeader(headers, X_AMZN_REQUEST_ID_HEADER).orElse(null);
137138
}
138139

140+
private String getExtendedRequestIdFromHeaders(Map<String, List<String>> headers) {
141+
return SdkHttpUtils.firstMatchingHeader(headers, X_AMZ_ID_2_HEADER).orElse(null);
142+
}
143+
139144
public static Builder builder() {
140145
return new Builder();
141146
}

core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/JsonResponseHandler.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ public T handle(SdkHttpFullResponse response, ExecutionAttributes executionAttri
7474
response.firstMatchingHeader(X_AMZN_REQUEST_ID_HEADER)
7575
.orElse("not available"));
7676

77+
SdkStandardLogger.REQUEST_ID_LOGGER.debug(() -> X_AMZ_ID_2_HEADER + " : " +
78+
response.firstMatchingHeader(X_AMZ_ID_2_HEADER)
79+
.orElse("not available"));
7780

7881
try {
7982
T result = unmarshaller.unmarshall(pojoSupplier.apply(response), response);

core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/unmarshall/AwsXmlErrorUnmarshaller.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
@SdkInternalApi
4141
public final class AwsXmlErrorUnmarshaller {
4242
private static final String X_AMZN_REQUEST_ID_HEADER = "x-amzn-RequestId";
43+
private static final String X_AMZ_ID_2_HEADER = "x-amz-id-2";
4344

4445
private final List<ExceptionMetadata> exceptions;
4546
private final Supplier<SdkPojo> defaultExceptionSupplier;
@@ -90,6 +91,7 @@ public AwsServiceException unmarshall(XmlElement documentRoot,
9091
.build();
9192

9293
builder.requestId(getRequestId(response, documentRoot))
94+
.extendedRequestId(getExtendedRequestId(response))
9395
.statusCode(response.statusCode())
9496
.clockSkew(getClockSkew(executionAttributes))
9597
.awsErrorDetails(awsErrorDetails);
@@ -176,6 +178,16 @@ private String getRequestId(SdkHttpFullResponse response, XmlElement document) {
176178
response.firstMatchingHeader(X_AMZN_REQUEST_ID_HEADER).orElse(null);
177179
}
178180

181+
/**
182+
* Extracts the extended request ID from the response headers.
183+
*
184+
* @param response The HTTP response object.
185+
* @return Extended Request ID string or null if not present.
186+
*/
187+
private String getExtendedRequestId(SdkHttpFullResponse response) {
188+
return response.firstMatchingHeader(X_AMZ_ID_2_HEADER).orElse(null);
189+
}
190+
179191
/**
180192
* Builder for {@link AwsXmlErrorUnmarshaller}.
181193
*/

core/sdk-core/src/main/java/software/amazon/awssdk/core/exception/SdkServiceException.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,13 @@
4141
public class SdkServiceException extends SdkException implements SdkPojo {
4242

4343
private final String requestId;
44+
private final String extendedRequestId;
4445
private final int statusCode;
4546

4647
protected SdkServiceException(Builder b) {
4748
super(b);
4849
this.requestId = b.requestId();
50+
this.extendedRequestId = b.extendedRequestId();
4951
this.statusCode = b.statusCode();
5052
}
5153

@@ -57,6 +59,14 @@ public String requestId() {
5759
return requestId;
5860
}
5961

62+
/**
63+
* The extendedRequestId that was returned by the called service.
64+
* @return String ctontaining the extendedRequestId
65+
*/
66+
public String extendedRequestId() {
67+
return extendedRequestId;
68+
}
69+
6070
/**
6171
* The status code that was returned by the called service.
6272
* @return int containing the status code.
@@ -127,6 +137,21 @@ public interface Builder extends SdkException.Builder, SdkPojo {
127137
*/
128138
String requestId();
129139

140+
/**
141+
* Specifies the extendedRequestId returned by the called service.
142+
*
143+
* @param extendedRequestId A string that identifies the request made to a service.
144+
* @return This object for method chaining.
145+
*/
146+
Builder extendedRequestId(String extendedRequestId);
147+
148+
/**
149+
* The extendedRequestId returned by the called service.
150+
*
151+
* @return String containing the extendedRequestId
152+
*/
153+
String extendedRequestId();
154+
130155
/**
131156
* Specifies the status code returned by the service.
132157
*
@@ -153,6 +178,7 @@ public interface Builder extends SdkException.Builder, SdkPojo {
153178
protected static class BuilderImpl extends SdkException.BuilderImpl implements Builder {
154179

155180
protected String requestId;
181+
protected String extendedRequestId;
156182
protected int statusCode;
157183

158184
protected BuilderImpl() {
@@ -161,6 +187,7 @@ protected BuilderImpl() {
161187
protected BuilderImpl(SdkServiceException ex) {
162188
super(ex);
163189
this.requestId = ex.requestId();
190+
this.extendedRequestId = ex.extendedRequestId();
164191
this.statusCode = ex.statusCode();
165192
}
166193

@@ -182,6 +209,12 @@ public Builder requestId(String requestId) {
182209
return this;
183210
}
184211

212+
@Override
213+
public Builder extendedRequestId(String extendedRequestId) {
214+
this.extendedRequestId = extendedRequestId;
215+
return this;
216+
}
217+
185218
@Override
186219
public String requestId() {
187220
return requestId;
@@ -195,6 +228,19 @@ public void setRequestId(String requestId) {
195228
this.requestId = requestId;
196229
}
197230

231+
@Override
232+
public String extendedRequestId() {
233+
return extendedRequestId;
234+
}
235+
236+
public String getExtendedRequestId() {
237+
return extendedRequestId;
238+
}
239+
240+
public void setExtendedRequestId(String extendedRequestId) {
241+
this.extendedRequestId = extendedRequestId;
242+
}
243+
198244
@Override
199245
public Builder statusCode(int statusCode) {
200246
this.statusCode = statusCode;

test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/exception/AwsJsonExceptionTest.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,29 @@ public void modeledException_HasExceptionMetadataSet() {
126126
assertThat(awsErrorDetails.serviceName()).isEqualTo("ProtocolJsonRpc");
127127
assertThat(awsErrorDetails.sdkHttpResponse()).isNotNull();
128128
assertThat(e.requestId()).isEqualTo("1234");
129+
assertThat(e.extendedRequestId()).isNull();
130+
assertThat(e.statusCode()).isEqualTo(404);
131+
}
132+
}
133+
134+
@Test
135+
public void modeledException_HasExceptionMetadataIncludingExtendedRequestIdSet() {
136+
stubFor(post(urlEqualTo(PATH)).willReturn(
137+
aResponse()
138+
.withStatus(404)
139+
.withHeader("x-amzn-RequestId", "1234")
140+
.withHeader("x-amz-id-2", "5678")
141+
.withBody("{\"__type\": \"EmptyModeledException\", \"Message\": \"This is the service message\"}")));
142+
try {
143+
client.allTypes();
144+
} catch (EmptyModeledException e) {
145+
AwsErrorDetails awsErrorDetails = e.awsErrorDetails();
146+
assertThat(awsErrorDetails.errorCode()).isEqualTo("EmptyModeledException");
147+
assertThat(awsErrorDetails.errorMessage()).isEqualTo("This is the service message");
148+
assertThat(awsErrorDetails.serviceName()).isEqualTo("ProtocolJsonRpc");
149+
assertThat(awsErrorDetails.sdkHttpResponse()).isNotNull();
150+
assertThat(e.requestId()).isEqualTo("1234");
151+
assertThat(e.extendedRequestId()).isEqualTo("5678");
129152
assertThat(e.statusCode()).isEqualTo(404);
130153
}
131154
}

test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/exception/QueryExceptionTests.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ public void modeledException_HasExceptionMetadataSet() {
231231
assertThat(awsErrorDetails.serviceName()).isEqualTo("ProtocolQuery");
232232
assertThat(awsErrorDetails.sdkHttpResponse()).isNotNull();
233233
assertThat(e.requestId()).isEqualTo("1234");
234+
assertThat(e.extendedRequestId()).isNull();
234235
assertThat(e.statusCode()).isEqualTo(404);
235236
}
236237
}
@@ -252,6 +253,7 @@ public void modeledException_RequestIDInXml_SetCorrectly() {
252253
client.allTypes();
253254
} catch (EmptyModeledException e) {
254255
assertThat(e.requestId()).isEqualTo("1234");
256+
assertThat(e.extendedRequestId()).isNull();
255257
}
256258
}
257259

@@ -265,6 +267,22 @@ public void requestIdInHeader_IsSetOnException() {
265267
client.allTypes();
266268
} catch (ProtocolQueryException e) {
267269
assertThat(e.requestId()).isEqualTo("1234");
270+
assertThat(e.extendedRequestId()).isNull();
271+
}
272+
}
273+
274+
@Test
275+
public void requestIdAndExtendedRequestIdInHeader_IsSetOnException() {
276+
stubFor(post(urlEqualTo(PATH)).willReturn(
277+
aResponse()
278+
.withStatus(404)
279+
.withHeader("x-amzn-RequestId", "1234")
280+
.withHeader("x-amz-id-2", "5678")));
281+
try {
282+
client.allTypes();
283+
} catch (ProtocolQueryException e) {
284+
assertThat(e.requestId()).isEqualTo("1234");
285+
assertThat(e.extendedRequestId()).isEqualTo("5678");
268286
}
269287
}
270288

test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/exception/RestJsonExceptionTests.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,29 @@ public void modeledException_HasExceptionMetadataSet() {
158158
assertThat(awsErrorDetails.serviceName()).isEqualTo("ProtocolRestJson");
159159
assertThat(awsErrorDetails.sdkHttpResponse()).isNotNull();
160160
assertThat(e.requestId()).isEqualTo("1234");
161+
assertThat(e.extendedRequestId()).isNull();
162+
assertThat(e.statusCode()).isEqualTo(404);
163+
}
164+
}
165+
166+
@Test
167+
public void modeledException_HasExceptionMetadataIncludingExtendedRequestIdSet() {
168+
stubFor(post(urlEqualTo(ALL_TYPES_PATH)).willReturn(
169+
aResponse()
170+
.withStatus(404)
171+
.withHeader("x-amzn-RequestId", "1234")
172+
.withHeader("x-amz-id-2", "5678")
173+
.withBody("{\"__type\": \"EmptyModeledException\", \"Message\": \"This is the service message\"}")));
174+
try {
175+
client.allTypes();
176+
} catch (EmptyModeledException e) {
177+
AwsErrorDetails awsErrorDetails = e.awsErrorDetails();
178+
assertThat(awsErrorDetails.errorCode()).isEqualTo("EmptyModeledException");
179+
assertThat(awsErrorDetails.errorMessage()).isEqualTo("This is the service message");
180+
assertThat(awsErrorDetails.serviceName()).isEqualTo("ProtocolRestJson");
181+
assertThat(awsErrorDetails.sdkHttpResponse()).isNotNull();
182+
assertThat(e.requestId()).isEqualTo("1234");
183+
assertThat(e.extendedRequestId()).isEqualTo("5678");
161184
assertThat(e.statusCode()).isEqualTo(404);
162185
}
163186
}

test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/exception/RestXmlExceptionTests.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,35 @@ public void modeledException_HasExceptionMetadataSet() {
155155
assertThat(awsErrorDetails.serviceName()).isEqualTo("ProtocolRestXml");
156156
assertThat(awsErrorDetails.sdkHttpResponse()).isNotNull();
157157
assertThat(e.requestId()).isEqualTo("1234");
158+
assertThat(e.extendedRequestId()).isNull();
159+
assertThat(e.statusCode()).isEqualTo(404);
160+
}
161+
}
162+
163+
@Test
164+
public void modeledException_HasExceptionMetadataIncludingExtendedRequestIdSet() {
165+
String xml = "<ErrorResponse>"
166+
+ " <Error>"
167+
+ " <Code>EmptyModeledException</Code>"
168+
+ " <Message>This is the service message</Message>"
169+
+ " </Error>"
170+
+ " <RequestId>1234</RequestId>"
171+
+ "</ErrorResponse>";
172+
stubFor(post(urlEqualTo(ALL_TYPES_PATH)).willReturn(
173+
aResponse()
174+
.withStatus(404)
175+
.withHeader("x-amz-id-2", "5678")
176+
.withBody(xml)));
177+
try {
178+
client.allTypes();
179+
} catch (EmptyModeledException e) {
180+
AwsErrorDetails awsErrorDetails = e.awsErrorDetails();
181+
assertThat(awsErrorDetails.errorCode()).isEqualTo("EmptyModeledException");
182+
assertThat(awsErrorDetails.errorMessage()).isEqualTo("This is the service message");
183+
assertThat(awsErrorDetails.serviceName()).isEqualTo("ProtocolRestXml");
184+
assertThat(awsErrorDetails.sdkHttpResponse()).isNotNull();
185+
assertThat(e.requestId()).isEqualTo("1234");
186+
assertThat(e.extendedRequestId()).isEqualTo("5678");
158187
assertThat(e.statusCode()).isEqualTo(404);
159188
}
160189
}

0 commit comments

Comments
 (0)