Skip to content

Commit e1a8691

Browse files
authored
TracingInterceptor should take effect only one time (#399)
* only one xray TracingInterceptor should be effective * fix checkstyle
1 parent 0cc3e14 commit e1a8691

File tree

2 files changed

+93
-2
lines changed

2 files changed

+93
-2
lines changed

aws-xray-recorder-sdk-aws-sdk-v2/src/main/java/com/amazonaws/xray/interceptors/TracingInterceptor.java

+38-1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ public class TracingInterceptor implements ExecutionInterceptor {
6464
// TODO(anuraaga): Make private in next major version and rename.
6565
public static final ExecutionAttribute<Subsegment> entityKey = new ExecutionAttribute("AWS X-Ray Entity");
6666

67+
// Make sure only one xray interceptor takes effect.
68+
private static final ExecutionAttribute<TracingInterceptor> XRAY_INTERCEPTOR_KEY =
69+
new ExecutionAttribute("AWS X-Ray Interceptor");
70+
6771
private static final Log logger = LogFactory.getLog(TracingInterceptor.class);
6872

6973
private static final ObjectMapper MAPPER = new ObjectMapper()
@@ -239,8 +243,26 @@ private HashMap<String, Object> extractResponseParameters(
239243
return parameters;
240244
}
241245

246+
private boolean isDuplicateInterceptor(ExecutionAttributes executionAttributes) {
247+
if (executionAttributes.getAttribute(XRAY_INTERCEPTOR_KEY) == null) {
248+
executionAttributes.putAttribute(XRAY_INTERCEPTOR_KEY, this);
249+
return false;
250+
}
251+
252+
if (executionAttributes.getAttribute(XRAY_INTERCEPTOR_KEY) != this) {
253+
return true;
254+
}
255+
256+
return false;
257+
}
258+
242259
@Override
243260
public void beforeExecution(Context.BeforeExecution context, ExecutionAttributes executionAttributes) {
261+
if (isDuplicateInterceptor(executionAttributes)) {
262+
logger.debug("X-Ray TracingInterceptor already exists.");
263+
return;
264+
}
265+
244266
AWSXRayRecorder recorder = getRecorder();
245267
Entity origin = recorder.getTraceEntity();
246268

@@ -265,19 +287,26 @@ public void beforeExecution(Context.BeforeExecution context, ExecutionAttributes
265287
@Override
266288
public SdkHttpRequest modifyHttpRequest(Context.ModifyHttpRequest context, ExecutionAttributes executionAttributes) {
267289
SdkHttpRequest httpRequest = context.httpRequest();
290+
if (isDuplicateInterceptor(executionAttributes)) {
291+
return httpRequest;
292+
}
268293

269294
Subsegment subsegment = executionAttributes.getAttribute(entityKey);
270295
if (!subsegment.shouldPropagate()) {
271296
return httpRequest;
272297
}
273298

274-
return httpRequest.toBuilder().appendHeader(
299+
return httpRequest.toBuilder().putHeader(
275300
TraceHeader.HEADER_KEY,
276301
TraceHeader.fromEntity(subsegment).toString()).build();
277302
}
278303

279304
@Override
280305
public void beforeTransmission(Context.BeforeTransmission context, ExecutionAttributes executionAttributes) {
306+
if (isDuplicateInterceptor(executionAttributes)) {
307+
return;
308+
}
309+
281310
Subsegment subsegment = executionAttributes.getAttribute(entityKey);
282311
if (subsegment == null) {
283312
return;
@@ -293,6 +322,10 @@ public void beforeTransmission(Context.BeforeTransmission context, ExecutionAttr
293322

294323
@Override
295324
public void afterExecution(Context.AfterExecution context, ExecutionAttributes executionAttributes) {
325+
if (isDuplicateInterceptor(executionAttributes)) {
326+
return;
327+
}
328+
296329
Subsegment subsegment = executionAttributes.getAttribute(entityKey);
297330
if (subsegment == null) {
298331
return;
@@ -307,6 +340,10 @@ public void afterExecution(Context.AfterExecution context, ExecutionAttributes e
307340

308341
@Override
309342
public void onExecutionFailure(Context.FailedExecution context, ExecutionAttributes executionAttributes) {
343+
if (isDuplicateInterceptor(executionAttributes)) {
344+
return;
345+
}
346+
310347
Subsegment subsegment = executionAttributes.getAttribute(entityKey);
311348
if (subsegment == null) {
312349
return;

aws-xray-recorder-sdk-aws-sdk-v2/src/test/java/com/amazonaws/xray/interceptors/TracingInterceptorTest.java

+55-1
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,44 @@ public void teardown() {
9898
AWSXRay.endSegment();
9999
}
100100

101+
@Test
102+
public void testDuplicateInterceptor() throws Exception {
103+
SdkHttpClient mockClient = mockSdkHttpClient(generateLambdaInvokeResponse(400));
104+
LambdaClient client = lambdaClientDupInterceptor(mockClient);
105+
106+
Segment segment = AWSXRay.getCurrentSegment();
107+
try {
108+
client.invoke(InvokeRequest.builder()
109+
.functionName("testFunctionName")
110+
.build()
111+
);
112+
} catch (Exception e) {
113+
// ignore SDK errors
114+
} finally {
115+
Assert.assertEquals(1, segment.getSubsegments().size());
116+
Subsegment subsegment = segment.getSubsegments().get(0);
117+
Map<String, Object> awsStats = subsegment.getAws();
118+
@SuppressWarnings("unchecked")
119+
Map<String, Object> httpResponseStats = (Map<String, Object>) subsegment.getHttp().get("response");
120+
Cause cause = subsegment.getCause();
121+
122+
Assert.assertEquals("Invoke", awsStats.get("operation"));
123+
Assert.assertEquals("testFunctionName", awsStats.get("function_name"));
124+
Assert.assertEquals("1111-2222-3333-4444", awsStats.get("request_id"));
125+
Assert.assertEquals("extended", awsStats.get("id_2"));
126+
Assert.assertEquals("us-west-42", awsStats.get("region"));
127+
Assert.assertEquals(0, awsStats.get("retries"));
128+
Assert.assertEquals(2L, httpResponseStats.get("content_length"));
129+
Assert.assertEquals(400, httpResponseStats.get("status"));
130+
Assert.assertEquals(false, subsegment.isInProgress());
131+
Assert.assertEquals(true, subsegment.isError());
132+
Assert.assertEquals(false, subsegment.isThrottle());
133+
Assert.assertEquals(false, subsegment.isFault());
134+
Assert.assertEquals(1, cause.getExceptions().size());
135+
Assert.assertEquals(true, cause.getExceptions().get(0).isRemote());
136+
}
137+
}
138+
101139
@Test
102140
public void testResponseDescriptors() throws Exception {
103141
String responseBody = "{\"LastEvaluatedTableName\":\"baz\",\"TableNames\":[\"foo\",\"bar\",\"baz\"]}";
@@ -490,7 +528,7 @@ public void testNoHeaderAddedWhenPropagationOff() {
490528

491529
interceptor.modifyHttpRequest(context, attributes);
492530

493-
verify(mockRequest.toBuilder(), never()).appendHeader(anyString(), anyString());
531+
verify(mockRequest.toBuilder(), never()).putHeader(anyString(), anyString());
494532
}
495533

496534
@Test
@@ -661,6 +699,22 @@ private static LambdaClient lambdaClient(SdkHttpClient mockClient) {
661699
.build();
662700
}
663701

702+
private static LambdaClient lambdaClientDupInterceptor(SdkHttpClient mockClient) {
703+
return LambdaClient.builder()
704+
.httpClient(mockClient)
705+
.endpointOverride(URI.create("http://example.com"))
706+
.region(Region.of("us-west-42"))
707+
.credentialsProvider(StaticCredentialsProvider.create(
708+
AwsSessionCredentials.create("key", "secret", "session")
709+
))
710+
.overrideConfiguration(ClientOverrideConfiguration.builder()
711+
.addExecutionInterceptor(new TracingInterceptor())
712+
.addExecutionInterceptor(new TracingInterceptor())
713+
.build()
714+
)
715+
.build();
716+
}
717+
664718
private static LambdaAsyncClient lambdaAsyncClient(SdkAsyncHttpClient mockClient) {
665719
return LambdaAsyncClient.builder()
666720
.httpClient(mockClient)

0 commit comments

Comments
 (0)