Skip to content

Commit 818f73f

Browse files
authored
Add an option to mark indy converted instrumentations (#13665)
1 parent 4855626 commit 818f73f

File tree

5 files changed

+251
-5
lines changed

5 files changed

+251
-5
lines changed

instrumentation/pekko/pekko-http-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/pekkohttp/v1_0/client/PekkoHttpClientInstrumentationModule.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@
1010
import com.google.auto.service.AutoService;
1111
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
1212
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
13+
import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule;
1314
import java.util.List;
1415

1516
@AutoService(InstrumentationModule.class)
16-
public class PekkoHttpClientInstrumentationModule extends InstrumentationModule {
17+
public class PekkoHttpClientInstrumentationModule extends InstrumentationModule
18+
implements ExperimentalInstrumentationModule {
1719
public PekkoHttpClientInstrumentationModule() {
1820
super("pekko-http", "pekko-http-1.0", "pekko-http-client");
1921
}
@@ -22,4 +24,9 @@ public PekkoHttpClientInstrumentationModule() {
2224
public List<TypeInstrumentation> typeInstrumentations() {
2325
return asList(new HttpExtClientInstrumentation(), new PoolMasterActorInstrumentation());
2426
}
27+
28+
@Override
29+
public boolean isIndyReady() {
30+
return true;
31+
}
2532
}

javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/instrumentation/internal/ExperimentalInstrumentationModule.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,14 @@ default List<String> agentPackagesToHide() {
7575
default Map<JavaModule, List<String>> jpmsModulesToOpen() {
7676
return Collections.emptyMap();
7777
}
78+
79+
/**
80+
* Signals that the advice in this module is ready to be used with indy instrumentation and the
81+
* automatic advice conversion doesn't need to be applied.
82+
*
83+
* @return true if module is ready to be used with indy instrumentation.
84+
*/
85+
default boolean isIndyReady() {
86+
return false;
87+
}
7888
}
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.javaagent.tooling.instrumentation.indy;
7+
8+
import static io.opentelemetry.javaagent.tooling.instrumentation.indy.ForceDynamicallyTypedAssignReturnedFactory.replaceAnnotationValue;
9+
10+
import javax.annotation.Nonnull;
11+
import net.bytebuddy.agent.builder.AgentBuilder;
12+
import net.bytebuddy.asm.Advice;
13+
import net.bytebuddy.description.annotation.AnnotationDescription;
14+
import net.bytebuddy.description.annotation.AnnotationList;
15+
import net.bytebuddy.description.annotation.AnnotationValue;
16+
import net.bytebuddy.description.method.MethodDescription;
17+
import net.bytebuddy.description.method.MethodList;
18+
import net.bytebuddy.description.method.ParameterDescription;
19+
import net.bytebuddy.description.method.ParameterList;
20+
import net.bytebuddy.description.type.TypeDescription;
21+
import net.bytebuddy.description.type.TypeList;
22+
import net.bytebuddy.dynamic.ClassFileLocator;
23+
import net.bytebuddy.pool.TypePool;
24+
import org.jetbrains.annotations.NotNull;
25+
26+
/**
27+
* Pool strategy that sets "inline" attribute to false on {@link Advice.OnMethodEnter} and {@link
28+
* Advice.OnMethodExit} annotations.
29+
*/
30+
class AdviceUninliningPoolStrategy implements AgentBuilder.PoolStrategy {
31+
private final AgentBuilder.PoolStrategy poolStrategy;
32+
33+
public AdviceUninliningPoolStrategy(AgentBuilder.PoolStrategy poolStrategy) {
34+
this.poolStrategy = poolStrategy;
35+
}
36+
37+
@NotNull
38+
@Override
39+
public TypePool typePool(@NotNull ClassFileLocator classFileLocator, ClassLoader classLoader) {
40+
TypePool typePool = poolStrategy.typePool(classFileLocator, classLoader);
41+
return new TypePoolWrapper(typePool);
42+
}
43+
44+
@NotNull
45+
@Override
46+
public TypePool typePool(
47+
@NotNull ClassFileLocator classFileLocator, ClassLoader classLoader, @NotNull String name) {
48+
TypePool typePool = poolStrategy.typePool(classFileLocator, classLoader, name);
49+
return new TypePoolWrapper(typePool);
50+
}
51+
52+
private static class TypePoolWrapper implements TypePool {
53+
private final TypePool typePool;
54+
55+
public TypePoolWrapper(TypePool typePool) {
56+
this.typePool = typePool;
57+
}
58+
59+
@NotNull
60+
@Override
61+
public Resolution describe(@NotNull String name) {
62+
Resolution resolution = typePool.describe(name);
63+
64+
return new Resolution() {
65+
@Override
66+
public boolean isResolved() {
67+
return resolution.isResolved();
68+
}
69+
70+
@NotNull
71+
@Override
72+
public TypeDescription resolve() {
73+
TypeDescription typeDescription = resolution.resolve();
74+
75+
return new TypeDescription.AbstractBase.OfSimpleType.WithDelegation() {
76+
77+
@NotNull
78+
@Override
79+
public String getName() {
80+
return typeDescription.getName();
81+
}
82+
83+
@NotNull
84+
@Override
85+
protected TypeDescription delegate() {
86+
return typeDescription;
87+
}
88+
89+
@NotNull
90+
@Override
91+
public MethodList<MethodDescription.InDefinedShape> getDeclaredMethods() {
92+
MethodList<MethodDescription.InDefinedShape> methods = super.getDeclaredMethods();
93+
94+
class MethodListWrapper
95+
extends MethodList.AbstractBase<MethodDescription.InDefinedShape> {
96+
97+
@Override
98+
public MethodDescription.InDefinedShape get(int index) {
99+
return new MethodDescriptionWrapper(methods.get(index));
100+
}
101+
102+
@Override
103+
public int size() {
104+
return methods.size();
105+
}
106+
}
107+
108+
return new MethodListWrapper();
109+
}
110+
};
111+
}
112+
};
113+
}
114+
115+
@Override
116+
public void clear() {
117+
typePool.clear();
118+
}
119+
}
120+
121+
private static class MethodDescriptionWrapper extends DelegatingMethodDescription {
122+
123+
MethodDescriptionWrapper(MethodDescription.InDefinedShape method) {
124+
super(method);
125+
}
126+
127+
@NotNull
128+
@Override
129+
public AnnotationList getDeclaredAnnotations() {
130+
AnnotationList annotations = method.getDeclaredAnnotations();
131+
132+
class AnnotationListWrapper extends AnnotationList.AbstractBase {
133+
134+
@Override
135+
public AnnotationDescription get(int index) {
136+
AnnotationDescription annotation = annotations.get(index);
137+
String annotationTypeName = annotation.getAnnotationType().getActualName();
138+
// we are only interested in OnMethodEnter and OnMethodExit annotations
139+
if (!Advice.OnMethodEnter.class.getName().equals(annotationTypeName)
140+
&& !Advice.OnMethodExit.class.getName().equals(annotationTypeName)) {
141+
return annotation;
142+
}
143+
144+
// replace value for "inline" attribute with false
145+
return replaceAnnotationValue(
146+
annotation, "inline", oldVal -> AnnotationValue.ForConstant.of(false));
147+
}
148+
149+
@Override
150+
public int size() {
151+
return annotations.size();
152+
}
153+
}
154+
155+
return new AnnotationListWrapper();
156+
}
157+
}
158+
159+
private static class DelegatingMethodDescription
160+
extends MethodDescription.InDefinedShape.AbstractBase {
161+
protected final MethodDescription.InDefinedShape method;
162+
163+
DelegatingMethodDescription(MethodDescription.InDefinedShape method) {
164+
this.method = method;
165+
}
166+
167+
@Nonnull
168+
@Override
169+
public TypeDescription getDeclaringType() {
170+
return method.getDeclaringType();
171+
}
172+
173+
@NotNull
174+
@Override
175+
public TypeDescription.Generic getReturnType() {
176+
return method.getReturnType();
177+
}
178+
179+
@NotNull
180+
@Override
181+
public ParameterList<ParameterDescription.InDefinedShape> getParameters() {
182+
return method.getParameters();
183+
}
184+
185+
@NotNull
186+
@Override
187+
public TypeList.Generic getExceptionTypes() {
188+
return method.getExceptionTypes();
189+
}
190+
191+
@Override
192+
public AnnotationValue<?, ?> getDefaultValue() {
193+
return method.getDefaultValue();
194+
}
195+
196+
@NotNull
197+
@Override
198+
public String getInternalName() {
199+
return method.getInternalName();
200+
}
201+
202+
@NotNull
203+
@Override
204+
public TypeList.Generic getTypeVariables() {
205+
return method.getTypeVariables();
206+
}
207+
208+
@Override
209+
public int getModifiers() {
210+
return method.getModifiers();
211+
}
212+
213+
@NotNull
214+
@Override
215+
public AnnotationList getDeclaredAnnotations() {
216+
return method.getDeclaredAnnotations();
217+
}
218+
}
219+
}

javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/instrumentation/indy/ForceDynamicallyTypedAssignReturnedFactory.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ static List<? extends AnnotationDescription> forceDynamicTyping(
6868
}
6969

7070
private static AnnotationDescription forceDynamicTyping(AnnotationDescription anno) {
71-
7271
String name = anno.getAnnotationType().getName();
7372
if (name.equals(TO_FIELD_TYPENAME)
7473
|| name.equals(TO_ARGUMENT_TYPENAME)
@@ -101,7 +100,7 @@ private static AnnotationDescription forceDynamicTyping(AnnotationDescription an
101100
return anno;
102101
}
103102

104-
private static AnnotationDescription replaceAnnotationValue(
103+
static AnnotationDescription replaceAnnotationValue(
105104
AnnotationDescription anno,
106105
String propertyName,
107106
Function<AnnotationValue<?, ?>, AnnotationValue<?, ?>> valueMapper) {

javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/instrumentation/indy/IndyTypeTransformerImpl.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
99
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
10+
import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule;
1011
import io.opentelemetry.javaagent.tooling.bytebuddy.ExceptionHandlers;
1112
import java.io.FileOutputStream;
1213
import java.io.IOException;
@@ -25,11 +26,15 @@ public final class IndyTypeTransformerImpl implements TypeTransformer {
2526
private final Advice.WithCustomMapping adviceMapping;
2627
private AgentBuilder.Identified.Extendable agentBuilder;
2728
private final InstrumentationModule instrumentationModule;
29+
private final boolean transformAdvice;
2830

2931
public IndyTypeTransformerImpl(
3032
AgentBuilder.Identified.Extendable agentBuilder, InstrumentationModule module) {
3133
this.agentBuilder = agentBuilder;
3234
this.instrumentationModule = module;
35+
this.transformAdvice =
36+
!(instrumentationModule instanceof ExperimentalInstrumentationModule)
37+
|| !((ExperimentalInstrumentationModule) instrumentationModule).isIndyReady();
3338
this.adviceMapping =
3439
Advice.withCustomMapping()
3540
.with(
@@ -44,17 +49,23 @@ public IndyTypeTransformerImpl(
4449
@Override
4550
public void applyAdviceToMethod(
4651
ElementMatcher<? super MethodDescription> methodMatcher, String adviceClassName) {
52+
// default strategy used by AgentBuilder.Transformer.ForAdvice
53+
AgentBuilder.PoolStrategy poolStrategy = AgentBuilder.PoolStrategy.Default.FAST;
54+
4755
agentBuilder =
4856
agentBuilder.transform(
4957
new AgentBuilder.Transformer.ForAdvice(adviceMapping)
5058
.advice(methodMatcher, adviceClassName)
59+
// advice transformation already performs uninlining
60+
.with(
61+
transformAdvice ? poolStrategy : new AdviceUninliningPoolStrategy(poolStrategy))
5162
.include(getAdviceLocator(instrumentationModule.getClass().getClassLoader()))
5263
.withExceptionHandler(ExceptionHandlers.defaultExceptionHandler()));
5364
}
5465

55-
private static ClassFileLocator getAdviceLocator(ClassLoader classLoader) {
66+
private ClassFileLocator getAdviceLocator(ClassLoader classLoader) {
5667
ClassFileLocator classFileLocator = ClassFileLocator.ForClassLoader.of(classLoader);
57-
return new AdviceLocator(classFileLocator);
68+
return transformAdvice ? new AdviceLocator(classFileLocator) : classFileLocator;
5869
}
5970

6071
@Override

0 commit comments

Comments
 (0)