Skip to content

Commit 8224067

Browse files
traskCopilot
andcommitted
Move opentelemetry-api-1.0 instrumentation under v1_0 subpackage (open-telemetry#18886)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
1 parent 4a6446b commit 8224067

88 files changed

Lines changed: 381 additions & 119 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

instrumentation/azure-core/azure-core-1.36/javaagent/build.gradle.kts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ muzzle {
88
module.set("azure-core")
99
versions.set("[1.36.0,1.53.0)")
1010
assertInverse.set(true)
11+
// our advice helper bridges an explicitly supplied application parent context to the agent
12+
// context, so it references io.opentelemetry.context.{Context,Scope}
13+
extraDependency("io.opentelemetry:opentelemetry-api:1.27.0")
1114
}
1215
}
1316

@@ -24,6 +27,10 @@ sourceSets {
2427
dependencies {
2528
compileOnly(project(":instrumentation:azure-core:azure-core-1.36:library-instrumentation-shaded", configuration = "shadow"))
2629

30+
// needed to bridge an explicitly supplied application parent context (the unshaded
31+
// "application.io.opentelemetry.*" types) to the agent context inside our advice
32+
compileOnly(project(":opentelemetry-api-shaded-for-instrumenting", configuration = "shadow"))
33+
2734
library("com.azure:azure-core:1.36.0")
2835

2936
// Ensure no cross interference
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.javaagent.instrumentation.azurecore.v1_36;
7+
8+
import static net.bytebuddy.matcher.ElementMatchers.named;
9+
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
10+
11+
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
12+
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
13+
import java.util.Optional;
14+
import net.bytebuddy.asm.Advice;
15+
import net.bytebuddy.asm.Advice.AssignReturned;
16+
import net.bytebuddy.description.type.TypeDescription;
17+
import net.bytebuddy.matcher.ElementMatcher;
18+
19+
/**
20+
* Bridges an explicitly supplied parent context for {@code azure-core-tracing-opentelemetry}.
21+
*
22+
* <p>When a user passes a parent context to an Azure SDK call, the value is stored on the {@link
23+
* com.azure.core.util.Context} under {@link
24+
* com.azure.core.util.tracing.Tracer#PARENT_TRACE_CONTEXT_KEY} as the application's (unshaded)
25+
* {@code io.opentelemetry.context.Context}. The bundled {@code OpenTelemetryTracer} reads that
26+
* value back and expects it to be the agent's (shaded) context. Convert it here so the tracer does
27+
* not need to reach into agent internals reflectively.
28+
*/
29+
class AzureContextInstrumentation implements TypeInstrumentation {
30+
31+
@Override
32+
public ElementMatcher<TypeDescription> typeMatcher() {
33+
return named("com.azure.core.util.Context");
34+
}
35+
36+
@Override
37+
public void transform(TypeTransformer transformer) {
38+
transformer.applyAdviceToMethod(
39+
named("getData").and(takesArguments(1)), getClass().getName() + "$GetDataAdvice");
40+
}
41+
42+
@SuppressWarnings("unused")
43+
public static class GetDataAdvice {
44+
@AssignReturned.ToReturned
45+
@Advice.OnMethodExit(suppress = Throwable.class, inline = false)
46+
public static Optional<Object> onExit(
47+
@Advice.Argument(0) Object key, @Advice.Return Optional<Object> data) {
48+
return AzureExplicitParentContextHelper.bridgeApplicationContext(key, data);
49+
}
50+
}
51+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.javaagent.instrumentation.azurecore.v1_36;
7+
8+
import static com.azure.core.util.tracing.Tracer.PARENT_TRACE_CONTEXT_KEY;
9+
10+
import io.opentelemetry.context.Context;
11+
import java.util.Optional;
12+
13+
/**
14+
* Converts an explicitly supplied application parent context into the agent context.
15+
*
16+
* <p>In the agent the application's {@code io.opentelemetry.context.Context} (referenced here as
17+
* {@code application.io.opentelemetry.context.Context}) is bridged to the agent context by the
18+
* opentelemetry-api instrumentation. Making the application context current and reading back the
19+
* agent context performs that conversion using only public API, so this works in both inline and
20+
* indy mode without reaching into agent-internal helper classes.
21+
*/
22+
public final class AzureExplicitParentContextHelper {
23+
24+
public static Optional<Object> bridgeApplicationContext(Object key, Optional<Object> data) {
25+
if (!PARENT_TRACE_CONTEXT_KEY.equals(key) || data == null || !data.isPresent()) {
26+
return data;
27+
}
28+
Object value = data.get();
29+
if (!(value instanceof application.io.opentelemetry.context.Context)) {
30+
return data;
31+
}
32+
application.io.opentelemetry.context.Context applicationContext =
33+
(application.io.opentelemetry.context.Context) value;
34+
Context agentContext;
35+
try (application.io.opentelemetry.context.Scope ignored = applicationContext.makeCurrent()) {
36+
agentContext = Context.current();
37+
}
38+
return Optional.of(agentContext);
39+
}
40+
41+
private AzureExplicitParentContextHelper() {}
42+
}

instrumentation/azure-core/azure-core-1.36/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/azurecore/v1_36/AzureSdkInstrumentationModule.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,10 @@ public ElementMatcher.Junction<ClassLoader> classLoaderMatcher() {
5959

6060
@Override
6161
public List<TypeInstrumentation> typeInstrumentations() {
62-
return asList(new EmptyTypeInstrumentation(), new AzureHttpClientInstrumentation());
62+
return asList(
63+
new EmptyTypeInstrumentation(),
64+
new AzureContextInstrumentation(),
65+
new AzureHttpClientInstrumentation());
6366
}
6467

6568
private static class EmptyTypeInstrumentation implements TypeInstrumentation {

instrumentation/azure-core/azure-core-1.36/javaagent/src/testAzure/java/io/opentelemetry/javaagent/instrumentation/azurecore/v1_36/AzureSdkTest.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
import com.azure.core.util.TracingOptions;
3333
import com.azure.core.util.tracing.Tracer;
3434
import com.azure.core.util.tracing.TracerProvider;
35+
import io.opentelemetry.api.GlobalOpenTelemetry;
36+
import io.opentelemetry.api.trace.Span;
3537
import io.opentelemetry.api.trace.SpanKind;
3638
import io.opentelemetry.instrumentation.api.internal.SpanKey;
3739
import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension;
@@ -78,6 +80,32 @@ void testSpan() {
7880
equalTo(stringKey("az.namespace"), "otel.tests"))));
7981
}
8082

83+
@Test
84+
void testExplicitParentContextBridge() {
85+
// Azure's bundled OpenTelemetryTracer expects the value stored under
86+
// Tracer.PARENT_TRACE_CONTEXT_KEY to be the agent (shaded) Context.
87+
// This test verifies our Context#getData instrumentation bridges an explicitly supplied
88+
// application io.opentelemetry.context.Context into an agent io.opentelemetry.context.Context.
89+
// The parent span is never made current, so correct parenting requires this bridge.
90+
Tracer azTracer = createAzTracer();
91+
92+
Span parentSpan = GlobalOpenTelemetry.getTracer("test").spanBuilder("parent").startSpan();
93+
// application (unshaded) context carrying the parent span, NOT made current
94+
io.opentelemetry.context.Context parentContext =
95+
io.opentelemetry.context.Context.root().with(parentSpan);
96+
97+
Context azContext = new Context(Tracer.PARENT_TRACE_CONTEXT_KEY, parentContext);
98+
Context child = azTracer.start("child", azContext);
99+
azTracer.end(null, null, child);
100+
parentSpan.end();
101+
102+
testing.waitAndAssertTracesWithoutScopeVersionVerification(
103+
trace ->
104+
trace.hasSpansSatisfyingExactly(
105+
span -> span.hasName("parent").hasNoParent(),
106+
span -> span.hasName("child").hasParent(trace.getSpan(0))));
107+
}
108+
81109
@Test
82110
void testPipelineAndSuppression() {
83111
AtomicBoolean hasClientAndHttpKeys = new AtomicBoolean(false);

instrumentation/azure-core/azure-core-1.53/javaagent/build.gradle.kts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ muzzle {
88
module.set("azure-core")
99
versions.set("[1.53.0,)")
1010
assertInverse.set(true)
11+
// our advice helper bridges an explicitly supplied application parent context to the agent
12+
// context, so it references io.opentelemetry.context.{Context,Scope}
13+
extraDependency("io.opentelemetry:opentelemetry-api:1.27.0")
1114
}
1215
}
1316

@@ -24,6 +27,10 @@ sourceSets {
2427
dependencies {
2528
compileOnly(project(":instrumentation:azure-core:azure-core-1.53:library-instrumentation-shaded", configuration = "shadow"))
2629

30+
// needed to bridge an explicitly supplied application parent context (the unshaded
31+
// "application.io.opentelemetry.*" types) to the agent context inside our advice
32+
compileOnly(project(":opentelemetry-api-shaded-for-instrumenting", configuration = "shadow"))
33+
2734
library("com.azure:azure-core:1.53.0")
2835

2936
// Ensure no cross interference
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.javaagent.instrumentation.azurecore.v1_53;
7+
8+
import static net.bytebuddy.matcher.ElementMatchers.named;
9+
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
10+
11+
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
12+
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
13+
import java.util.Optional;
14+
import net.bytebuddy.asm.Advice;
15+
import net.bytebuddy.asm.Advice.AssignReturned;
16+
import net.bytebuddy.description.type.TypeDescription;
17+
import net.bytebuddy.matcher.ElementMatcher;
18+
19+
/**
20+
* Bridges an explicitly supplied parent context for {@code azure-core-tracing-opentelemetry}.
21+
*
22+
* <p>When a user passes a parent context to an Azure SDK call, the value is stored on the {@link
23+
* com.azure.core.util.Context} under {@link
24+
* com.azure.core.util.tracing.Tracer#PARENT_TRACE_CONTEXT_KEY} as the application's (unshaded)
25+
* {@code io.opentelemetry.context.Context}. The bundled {@code OpenTelemetryTracer} reads that
26+
* value back and expects it to be the agent's (shaded) context. Convert it here so the tracer does
27+
* not need to reach into agent internals reflectively.
28+
*/
29+
class AzureContextInstrumentation implements TypeInstrumentation {
30+
31+
@Override
32+
public ElementMatcher<TypeDescription> typeMatcher() {
33+
return named("com.azure.core.util.Context");
34+
}
35+
36+
@Override
37+
public void transform(TypeTransformer transformer) {
38+
transformer.applyAdviceToMethod(
39+
named("getData").and(takesArguments(1)), getClass().getName() + "$GetDataAdvice");
40+
}
41+
42+
@SuppressWarnings("unused")
43+
public static class GetDataAdvice {
44+
@AssignReturned.ToReturned
45+
@Advice.OnMethodExit(suppress = Throwable.class, inline = false)
46+
public static Optional<Object> onExit(
47+
@Advice.Argument(0) Object key, @Advice.Return Optional<Object> data) {
48+
return AzureExplicitParentContextHelper.bridgeApplicationContext(key, data);
49+
}
50+
}
51+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.javaagent.instrumentation.azurecore.v1_53;
7+
8+
import static com.azure.core.util.tracing.Tracer.PARENT_TRACE_CONTEXT_KEY;
9+
10+
import io.opentelemetry.context.Context;
11+
import java.util.Optional;
12+
13+
/**
14+
* Converts an explicitly supplied application parent context into the agent context.
15+
*
16+
* <p>In the agent the application's {@code io.opentelemetry.context.Context} (referenced here as
17+
* {@code application.io.opentelemetry.context.Context}) is bridged to the agent context by the
18+
* opentelemetry-api instrumentation. Making the application context current and reading back the
19+
* agent context performs that conversion using only public API, so this works in both inline and
20+
* indy mode without reaching into agent-internal helper classes.
21+
*/
22+
public final class AzureExplicitParentContextHelper {
23+
24+
public static Optional<Object> bridgeApplicationContext(Object key, Optional<Object> data) {
25+
if (!PARENT_TRACE_CONTEXT_KEY.equals(key) || data == null || !data.isPresent()) {
26+
return data;
27+
}
28+
Object value = data.get();
29+
if (!(value instanceof application.io.opentelemetry.context.Context)) {
30+
return data;
31+
}
32+
application.io.opentelemetry.context.Context applicationContext =
33+
(application.io.opentelemetry.context.Context) value;
34+
Context agentContext;
35+
try (application.io.opentelemetry.context.Scope ignored = applicationContext.makeCurrent()) {
36+
agentContext = Context.current();
37+
}
38+
return Optional.of(agentContext);
39+
}
40+
41+
private AzureExplicitParentContextHelper() {}
42+
}

instrumentation/azure-core/azure-core-1.53/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/azurecore/v1_53/AzureSdkInstrumentationModule.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,10 @@ public ElementMatcher.Junction<ClassLoader> classLoaderMatcher() {
5757

5858
@Override
5959
public List<TypeInstrumentation> typeInstrumentations() {
60-
return asList(new EmptyTypeInstrumentation(), new AzureHttpClientInstrumentation());
60+
return asList(
61+
new EmptyTypeInstrumentation(),
62+
new AzureContextInstrumentation(),
63+
new AzureHttpClientInstrumentation());
6164
}
6265

6366
private static class EmptyTypeInstrumentation implements TypeInstrumentation {

instrumentation/azure-core/azure-core-1.53/javaagent/src/testAzure/java/io/opentelemetry/javaagent/instrumentation/azurecore/v1_53/AzureSdkTest.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
import com.azure.core.util.TracingOptions;
3333
import com.azure.core.util.tracing.Tracer;
3434
import com.azure.core.util.tracing.TracerProvider;
35+
import io.opentelemetry.api.GlobalOpenTelemetry;
36+
import io.opentelemetry.api.trace.Span;
3537
import io.opentelemetry.api.trace.SpanKind;
3638
import io.opentelemetry.instrumentation.api.internal.SpanKey;
3739
import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension;
@@ -78,6 +80,32 @@ void testSpan() {
7880
equalTo(stringKey("az.namespace"), "otel.tests"))));
7981
}
8082

83+
@Test
84+
void testExplicitParentContextBridge() {
85+
// Azure's bundled OpenTelemetryTracer expects the value stored under
86+
// Tracer.PARENT_TRACE_CONTEXT_KEY to be the agent (shaded) Context.
87+
// This test verifies our Context#getData instrumentation bridges an explicitly supplied
88+
// application io.opentelemetry.context.Context into an agent io.opentelemetry.context.Context.
89+
// The parent span is never made current, so correct parenting requires this bridge.
90+
Tracer azTracer = createAzTracer();
91+
92+
Span parentSpan = GlobalOpenTelemetry.getTracer("test").spanBuilder("parent").startSpan();
93+
// application (unshaded) context carrying the parent span, NOT made current
94+
io.opentelemetry.context.Context parentContext =
95+
io.opentelemetry.context.Context.root().with(parentSpan);
96+
97+
Context azContext = new Context(Tracer.PARENT_TRACE_CONTEXT_KEY, parentContext);
98+
Context child = azTracer.start("child", azContext);
99+
azTracer.end(null, null, child);
100+
parentSpan.end();
101+
102+
testing.waitAndAssertTracesWithoutScopeVersionVerification(
103+
trace ->
104+
trace.hasSpansSatisfyingExactly(
105+
span -> span.hasName("parent").hasNoParent(),
106+
span -> span.hasName("child").hasParent(trace.getSpan(0))));
107+
}
108+
81109
@Test
82110
void testPipelineAndSuppression() {
83111
AtomicBoolean hasClientAndHttpKeys = new AtomicBoolean(false);

0 commit comments

Comments
 (0)