Skip to content

Commit 954ffad

Browse files
authored
Allow advice to define custom mappings (#13751)
1 parent 12cbfe9 commit 954ffad

File tree

7 files changed

+69
-22
lines changed

7 files changed

+69
-22
lines changed

instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodInstrumentation.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import io.opentelemetry.instrumentation.api.incubator.semconv.util.ClassAndMethod;
2020
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
2121
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
22-
import java.lang.reflect.Method;
2322
import java.util.Set;
2423
import net.bytebuddy.asm.Advice;
2524
import net.bytebuddy.description.type.TypeDescription;
@@ -57,9 +56,18 @@ public ElementMatcher<TypeDescription> typeMatcher() {
5756
public void transform(TypeTransformer transformer) {
5857
transformer.applyAdviceToMethod(
5958
namedOneOf(methodNames.toArray(new String[0])),
59+
mapping ->
60+
mapping.bind(
61+
MethodReturnType.class,
62+
(instrumentedType, instrumentedMethod, assigner, argumentHandler, sort) ->
63+
Advice.OffsetMapping.Target.ForStackManipulation.of(
64+
instrumentedMethod.getReturnType().asErasure())),
6065
MethodInstrumentation.class.getName() + "$MethodAdvice");
6166
}
6267

68+
// custom annotation that represents the return type of the method
69+
@interface MethodReturnType {}
70+
6371
@SuppressWarnings("unused")
6472
public static class MethodAdvice {
6573

@@ -82,7 +90,7 @@ public static void onEnter(
8290

8391
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
8492
public static void stopSpan(
85-
@Advice.Origin Method method,
93+
@MethodReturnType Class<?> methodReturnType,
8694
@Advice.Local("otelMethod") ClassAndMethod classAndMethod,
8795
@Advice.Local("otelContext") Context context,
8896
@Advice.Local("otelScope") Scope scope,
@@ -94,7 +102,7 @@ public static void stopSpan(
94102
scope.close();
95103

96104
returnValue =
97-
AsyncOperationEndSupport.create(instrumenter(), Void.class, method.getReturnType())
105+
AsyncOperationEndSupport.create(instrumenter(), Void.class, methodReturnType)
98106
.asyncEnd(context, classAndMethod, returnValue, throwable);
99107
}
100108
}

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

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55

66
package io.opentelemetry.javaagent.extension.instrumentation;
77

8+
import java.util.function.Function;
89
import net.bytebuddy.agent.builder.AgentBuilder;
10+
import net.bytebuddy.asm.Advice;
911
import net.bytebuddy.description.method.MethodDescription;
1012
import net.bytebuddy.matcher.ElementMatcher;
1113

@@ -17,12 +19,23 @@
1719
* will provide the implementation of all transformations described here.
1820
*/
1921
public interface TypeTransformer {
22+
/**
23+
* Apply the advice class named {@code adviceClassName} to the instrumented type methods that
24+
* match {@code methodMatcher}.
25+
*/
26+
default void applyAdviceToMethod(
27+
ElementMatcher<? super MethodDescription> methodMatcher, String adviceClassName) {
28+
applyAdviceToMethod(methodMatcher, Function.identity(), adviceClassName);
29+
}
30+
2031
/**
2132
* Apply the advice class named {@code adviceClassName} to the instrumented type methods that
2233
* match {@code methodMatcher}.
2334
*/
2435
void applyAdviceToMethod(
25-
ElementMatcher<? super MethodDescription> methodMatcher, String adviceClassName);
36+
ElementMatcher<? super MethodDescription> methodMatcher,
37+
Function<Advice.WithCustomMapping, Advice.WithCustomMapping> mappingCustomizer,
38+
String adviceClassName);
2639

2740
/**
2841
* Apply a custom ByteBuddy {@link AgentBuilder.Transformer} to the instrumented type. Note that

javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/instrumentation/TypeTransformerImpl.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
99
import io.opentelemetry.javaagent.tooling.Utils;
1010
import io.opentelemetry.javaagent.tooling.bytebuddy.ExceptionHandlers;
11+
import java.util.function.Function;
1112
import net.bytebuddy.agent.builder.AgentBuilder;
1213
import net.bytebuddy.asm.Advice;
1314
import net.bytebuddy.description.method.MethodDescription;
@@ -26,10 +27,12 @@ final class TypeTransformerImpl implements TypeTransformer {
2627

2728
@Override
2829
public void applyAdviceToMethod(
29-
ElementMatcher<? super MethodDescription> methodMatcher, String adviceClassName) {
30+
ElementMatcher<? super MethodDescription> methodMatcher,
31+
Function<Advice.WithCustomMapping, Advice.WithCustomMapping> mappingCustomizer,
32+
String adviceClassName) {
3033
agentBuilder =
3134
agentBuilder.transform(
32-
new AgentBuilder.Transformer.ForAdvice(adviceMapping)
35+
new AgentBuilder.Transformer.ForAdvice(mappingCustomizer.apply(adviceMapping))
3336
.include(
3437
Utils.getBootstrapProxy(),
3538
Utils.getAgentClassLoader(),

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

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,12 @@ private static class AdviceLocal {
155155
private static List<OutputArgument> getWritableArguments(MethodNode source) {
156156
List<OutputArgument> result = new ArrayList<>();
157157
if (source.visibleParameterAnnotations != null) {
158-
int i = 0;
159-
for (List<AnnotationNode> list : source.visibleParameterAnnotations) {
158+
for (int i = 0; i < source.visibleParameterAnnotations.length; i++) {
159+
List<AnnotationNode> list = source.visibleParameterAnnotations[i];
160+
if (list == null) {
161+
continue;
162+
}
163+
160164
for (AnnotationNode annotationNode : list) {
161165
Type annotationType = Type.getType(annotationNode.desc);
162166
if (ADVICE_ARGUMENT.equals(annotationType) && isWriteable(annotationNode)) {
@@ -166,7 +170,6 @@ private static List<OutputArgument> getWritableArguments(MethodNode source) {
166170
}
167171
}
168172
}
169-
i++;
170173
}
171174
}
172175

@@ -178,15 +181,18 @@ private static List<OutputArgument> getWritableArguments(MethodNode source) {
178181
/** Argument annotated with {@code @Advice.Return(readOnly = false)} or {@code null}. */
179182
private static OutputArgument getWritableReturnValue(MethodNode source) {
180183
if (source.visibleParameterAnnotations != null) {
181-
int i = 0;
182-
for (List<AnnotationNode> list : source.visibleParameterAnnotations) {
184+
for (int i = 0; i < source.visibleParameterAnnotations.length; i++) {
185+
List<AnnotationNode> list = source.visibleParameterAnnotations[i];
186+
if (list == null) {
187+
continue;
188+
}
189+
183190
for (AnnotationNode annotationNode : list) {
184191
Type annotationType = Type.getType(annotationNode.desc);
185192
if (ADVICE_RETURN.equals(annotationType) && isWriteable(annotationNode)) {
186193
return new OutputArgument(i, -1);
187194
}
188195
}
189-
i++;
190196
}
191197
}
192198

@@ -199,16 +205,19 @@ private static OutputArgument getWritableReturnValue(MethodNode source) {
199205
private static OutputArgument getEnterArgument(MethodNode source) {
200206
Type[] argumentTypes = Type.getArgumentTypes(source.desc);
201207
if (source.visibleParameterAnnotations != null) {
202-
int i = 0;
203-
for (List<AnnotationNode> list : source.visibleParameterAnnotations) {
208+
for (int i = 0; i < source.visibleParameterAnnotations.length; i++) {
209+
List<AnnotationNode> list = source.visibleParameterAnnotations[i];
210+
if (list == null) {
211+
continue;
212+
}
213+
204214
for (AnnotationNode annotationNode : list) {
205215
Type annotationType = Type.getType(annotationNode.desc);
206216
if (ADVICE_ENTER.equals(annotationType)
207217
&& argumentTypes[i].getDescriptor().length() > 1) {
208218
return new OutputArgument(i, -1);
209219
}
210220
}
211-
i++;
212221
}
213222
}
214223

@@ -221,8 +230,12 @@ private static OutputArgument getEnterArgument(MethodNode source) {
221230
private static List<AdviceLocal> getLocals(MethodNode source) {
222231
List<AdviceLocal> result = new ArrayList<>();
223232
if (source.visibleParameterAnnotations != null) {
224-
int i = 0;
225-
for (List<AnnotationNode> list : source.visibleParameterAnnotations) {
233+
for (int i = 0; i < source.visibleParameterAnnotations.length; i++) {
234+
List<AnnotationNode> list = source.visibleParameterAnnotations[i];
235+
if (list == null) {
236+
continue;
237+
}
238+
226239
for (AnnotationNode annotationNode : list) {
227240
Type annotationType = Type.getType(annotationNode.desc);
228241
if (ADVICE_LOCAL.equals(annotationType)) {
@@ -232,7 +245,6 @@ private static List<AdviceLocal> getLocals(MethodNode source) {
232245
}
233246
}
234247
}
235-
i++;
236248
}
237249
}
238250

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import java.io.FileOutputStream;
1313
import java.io.IOException;
1414
import java.util.function.BiFunction;
15+
import java.util.function.Function;
1516
import net.bytebuddy.agent.builder.AgentBuilder;
1617
import net.bytebuddy.asm.Advice;
1718
import net.bytebuddy.description.method.MethodDescription;
@@ -49,13 +50,15 @@ public IndyTypeTransformerImpl(
4950

5051
@Override
5152
public void applyAdviceToMethod(
52-
ElementMatcher<? super MethodDescription> methodMatcher, String adviceClassName) {
53+
ElementMatcher<? super MethodDescription> methodMatcher,
54+
Function<Advice.WithCustomMapping, Advice.WithCustomMapping> mappingCustomizer,
55+
String adviceClassName) {
5356
// default strategy used by AgentBuilder.Transformer.ForAdvice
5457
AgentBuilder.PoolStrategy poolStrategy = AgentBuilder.PoolStrategy.Default.FAST;
5558

5659
agentBuilder =
5760
agentBuilder.transform(
58-
new AgentBuilder.Transformer.ForAdvice(adviceMapping)
61+
new AgentBuilder.Transformer.ForAdvice(mappingCustomizer.apply(adviceMapping))
5962
.advice(methodMatcher, adviceClassName)
6063
// advice transformation already performs uninlining
6164
.with(

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,11 @@
2525
import java.util.Map;
2626
import java.util.Set;
2727
import java.util.concurrent.ConcurrentHashMap;
28+
import java.util.function.Function;
2829
import java.util.stream.Collectors;
2930
import javax.annotation.Nullable;
3031
import net.bytebuddy.agent.builder.AgentBuilder;
32+
import net.bytebuddy.asm.Advice;
3133
import net.bytebuddy.description.method.MethodDescription;
3234
import net.bytebuddy.matcher.ElementMatcher;
3335
import net.bytebuddy.matcher.StringMatcher;
@@ -181,7 +183,9 @@ private static Set<String> getModuleAdviceNames(InstrumentationModule module) {
181183
new TypeTransformer() {
182184
@Override
183185
public void applyAdviceToMethod(
184-
ElementMatcher<? super MethodDescription> methodMatcher, String adviceClassName) {
186+
ElementMatcher<? super MethodDescription> methodMatcher,
187+
Function<Advice.WithCustomMapping, Advice.WithCustomMapping> mappingCustomizer,
188+
String adviceClassName) {
185189
adviceNames.add(adviceClassName);
186190
}
187191

muzzle/src/main/java/io/opentelemetry/javaagent/tooling/muzzle/generation/AdviceClassNameCollector.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
99
import java.util.HashSet;
1010
import java.util.Set;
11+
import java.util.function.Function;
1112
import net.bytebuddy.agent.builder.AgentBuilder;
13+
import net.bytebuddy.asm.Advice;
1214
import net.bytebuddy.description.method.MethodDescription;
1315
import net.bytebuddy.matcher.ElementMatcher;
1416

@@ -17,7 +19,9 @@ final class AdviceClassNameCollector implements TypeTransformer {
1719

1820
@Override
1921
public void applyAdviceToMethod(
20-
ElementMatcher<? super MethodDescription> methodMatcher, String adviceClassName) {
22+
ElementMatcher<? super MethodDescription> methodMatcher,
23+
Function<Advice.WithCustomMapping, Advice.WithCustomMapping> mappingCustomizer,
24+
String adviceClassName) {
2125
adviceClassNames.add(adviceClassName);
2226
}
2327

0 commit comments

Comments
 (0)