Skip to content

Commit e65366b

Browse files
authored
Fix scope leak in aws sdk instrumentation (#13129)
1 parent 1b732de commit e65366b

File tree

2 files changed

+47
-7
lines changed

2 files changed

+47
-7
lines changed

instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/internal/TracingExecutionInterceptor.java

+24-7
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,11 @@ public SdkRequest modifyRequest(
142142
io.opentelemetry.context.Context parentOtelContext = io.opentelemetry.context.Context.current();
143143
SdkRequest request = context.request();
144144

145+
// the request has already been modified, duplicate interceptor?
146+
if (executionAttributes.getAttribute(SDK_REQUEST_ATTRIBUTE) != null) {
147+
return request;
148+
}
149+
145150
// Ignore presign request. These requests don't run all interceptor methods and the span created
146151
// here would never be ended and scope closed.
147152
if (executionAttributes.getAttribute(AwsSignerExecutionAttribute.PRESIGNER_EXPIRATION)
@@ -192,13 +197,6 @@ public SdkRequest modifyRequest(
192197
executionAttributes.putAttribute(PARENT_CONTEXT_ATTRIBUTE, parentOtelContext);
193198
executionAttributes.putAttribute(CONTEXT_ATTRIBUTE, otelContext);
194199
executionAttributes.putAttribute(REQUEST_FINISHER_ATTRIBUTE, requestFinisher);
195-
if (executionAttributes
196-
.getAttribute(SdkExecutionAttribute.CLIENT_TYPE)
197-
.equals(ClientType.SYNC)) {
198-
// We can only activate context for synchronous clients, which allows downstream
199-
// instrumentation like Apache to know about the SDK span.
200-
executionAttributes.putAttribute(SCOPE_ATTRIBUTE, otelContext.makeCurrent());
201-
}
202200

203201
Span span = Span.fromContext(otelContext);
204202

@@ -233,6 +231,25 @@ public SdkRequest modifyRequest(
233231
return request;
234232
}
235233

234+
@Override
235+
public void afterMarshalling(
236+
Context.AfterMarshalling context, ExecutionAttributes executionAttributes) {
237+
// the request has already been modified, duplicate interceptor?
238+
if (executionAttributes.getAttribute(SCOPE_ATTRIBUTE) != null) {
239+
return;
240+
}
241+
242+
io.opentelemetry.context.Context otelContext = getContext(executionAttributes);
243+
if (otelContext != null
244+
&& executionAttributes
245+
.getAttribute(SdkExecutionAttribute.CLIENT_TYPE)
246+
.equals(ClientType.SYNC)) {
247+
// We can only activate context for synchronous clients, which allows downstream
248+
// instrumentation like Apache to know about the SDK span.
249+
executionAttributes.putAttribute(SCOPE_ATTRIBUTE, otelContext.makeCurrent());
250+
}
251+
}
252+
236253
@Override
237254
public void beforeTransmission(
238255
Context.BeforeTransmission context, ExecutionAttributes executionAttributes) {

instrumentation/aws-sdk/aws-sdk-2.2/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AbstractAws2ClientTest.java

+23
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@
2424
import static io.opentelemetry.semconv.incubating.RpcIncubatingAttributes.RPC_SYSTEM;
2525
import static java.util.Arrays.asList;
2626
import static org.assertj.core.api.Assertions.assertThat;
27+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
2728
import static org.assertj.core.api.Assertions.catchThrowable;
2829

2930
import io.opentelemetry.api.trace.SpanKind;
31+
import io.opentelemetry.context.Context;
3032
import io.opentelemetry.sdk.testing.assertj.AttributeAssertion;
3133
import io.opentelemetry.sdk.trace.data.StatusData;
3234
import io.opentelemetry.testing.internal.armeria.common.HttpData;
@@ -56,6 +58,7 @@
5658
import software.amazon.awssdk.core.ResponseInputStream;
5759
import software.amazon.awssdk.core.async.AsyncResponseTransformer;
5860
import software.amazon.awssdk.core.exception.SdkClientException;
61+
import software.amazon.awssdk.core.exception.SdkException;
5962
import software.amazon.awssdk.core.retry.RetryPolicy;
6063
import software.amazon.awssdk.http.apache.ApacheHttpClient;
6164
import software.amazon.awssdk.regions.Region;
@@ -696,4 +699,24 @@ void testTimeoutAndRetryErrorsAreNotCaptured() {
696699
equalTo(stringKey("aws.agent"), "java-aws-sdk"),
697700
equalTo(stringKey("aws.bucket.name"), "somebucket"))));
698701
}
702+
703+
// regression test for
704+
// https://github.com/open-telemetry/opentelemetry-java-instrumentation/issues/13124
705+
// verify that scope is not leaked on exception
706+
@Test
707+
void testS3ListNullBucket() {
708+
S3ClientBuilder builder = S3Client.builder();
709+
configureSdkClient(builder);
710+
S3Client client =
711+
builder
712+
.endpointOverride(clientUri)
713+
.region(Region.AP_NORTHEAST_1)
714+
.credentialsProvider(CREDENTIALS_PROVIDER)
715+
.build();
716+
717+
assertThatThrownBy(() -> client.listObjectsV2(b -> b.bucket(null)))
718+
.isInstanceOf(SdkException.class);
719+
720+
assertThat(Context.current()).isEqualTo(Context.root());
721+
}
699722
}

0 commit comments

Comments
 (0)