Add an option to mark indy converted instrumentations (#13665)
This commit is contained in:
parent
4855626d53
commit
818f73f5fb
|
@ -10,10 +10,12 @@ import static java.util.Arrays.asList;
|
|||
import com.google.auto.service.AutoService;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule;
|
||||
import java.util.List;
|
||||
|
||||
@AutoService(InstrumentationModule.class)
|
||||
public class PekkoHttpClientInstrumentationModule extends InstrumentationModule {
|
||||
public class PekkoHttpClientInstrumentationModule extends InstrumentationModule
|
||||
implements ExperimentalInstrumentationModule {
|
||||
public PekkoHttpClientInstrumentationModule() {
|
||||
super("pekko-http", "pekko-http-1.0", "pekko-http-client");
|
||||
}
|
||||
|
@ -22,4 +24,9 @@ public class PekkoHttpClientInstrumentationModule extends InstrumentationModule
|
|||
public List<TypeInstrumentation> typeInstrumentations() {
|
||||
return asList(new HttpExtClientInstrumentation(), new PoolMasterActorInstrumentation());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIndyReady() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,4 +75,14 @@ public interface ExperimentalInstrumentationModule {
|
|||
default Map<JavaModule, List<String>> jpmsModulesToOpen() {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals that the advice in this module is ready to be used with indy instrumentation and the
|
||||
* automatic advice conversion doesn't need to be applied.
|
||||
*
|
||||
* @return true if module is ready to be used with indy instrumentation.
|
||||
*/
|
||||
default boolean isIndyReady() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,219 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.tooling.instrumentation.indy;
|
||||
|
||||
import static io.opentelemetry.javaagent.tooling.instrumentation.indy.ForceDynamicallyTypedAssignReturnedFactory.replaceAnnotationValue;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import net.bytebuddy.agent.builder.AgentBuilder;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
import net.bytebuddy.description.annotation.AnnotationDescription;
|
||||
import net.bytebuddy.description.annotation.AnnotationList;
|
||||
import net.bytebuddy.description.annotation.AnnotationValue;
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.description.method.MethodList;
|
||||
import net.bytebuddy.description.method.ParameterDescription;
|
||||
import net.bytebuddy.description.method.ParameterList;
|
||||
import net.bytebuddy.description.type.TypeDescription;
|
||||
import net.bytebuddy.description.type.TypeList;
|
||||
import net.bytebuddy.dynamic.ClassFileLocator;
|
||||
import net.bytebuddy.pool.TypePool;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Pool strategy that sets "inline" attribute to false on {@link Advice.OnMethodEnter} and {@link
|
||||
* Advice.OnMethodExit} annotations.
|
||||
*/
|
||||
class AdviceUninliningPoolStrategy implements AgentBuilder.PoolStrategy {
|
||||
private final AgentBuilder.PoolStrategy poolStrategy;
|
||||
|
||||
public AdviceUninliningPoolStrategy(AgentBuilder.PoolStrategy poolStrategy) {
|
||||
this.poolStrategy = poolStrategy;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public TypePool typePool(@NotNull ClassFileLocator classFileLocator, ClassLoader classLoader) {
|
||||
TypePool typePool = poolStrategy.typePool(classFileLocator, classLoader);
|
||||
return new TypePoolWrapper(typePool);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public TypePool typePool(
|
||||
@NotNull ClassFileLocator classFileLocator, ClassLoader classLoader, @NotNull String name) {
|
||||
TypePool typePool = poolStrategy.typePool(classFileLocator, classLoader, name);
|
||||
return new TypePoolWrapper(typePool);
|
||||
}
|
||||
|
||||
private static class TypePoolWrapper implements TypePool {
|
||||
private final TypePool typePool;
|
||||
|
||||
public TypePoolWrapper(TypePool typePool) {
|
||||
this.typePool = typePool;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Resolution describe(@NotNull String name) {
|
||||
Resolution resolution = typePool.describe(name);
|
||||
|
||||
return new Resolution() {
|
||||
@Override
|
||||
public boolean isResolved() {
|
||||
return resolution.isResolved();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public TypeDescription resolve() {
|
||||
TypeDescription typeDescription = resolution.resolve();
|
||||
|
||||
return new TypeDescription.AbstractBase.OfSimpleType.WithDelegation() {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return typeDescription.getName();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected TypeDescription delegate() {
|
||||
return typeDescription;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public MethodList<MethodDescription.InDefinedShape> getDeclaredMethods() {
|
||||
MethodList<MethodDescription.InDefinedShape> methods = super.getDeclaredMethods();
|
||||
|
||||
class MethodListWrapper
|
||||
extends MethodList.AbstractBase<MethodDescription.InDefinedShape> {
|
||||
|
||||
@Override
|
||||
public MethodDescription.InDefinedShape get(int index) {
|
||||
return new MethodDescriptionWrapper(methods.get(index));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return methods.size();
|
||||
}
|
||||
}
|
||||
|
||||
return new MethodListWrapper();
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
typePool.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private static class MethodDescriptionWrapper extends DelegatingMethodDescription {
|
||||
|
||||
MethodDescriptionWrapper(MethodDescription.InDefinedShape method) {
|
||||
super(method);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public AnnotationList getDeclaredAnnotations() {
|
||||
AnnotationList annotations = method.getDeclaredAnnotations();
|
||||
|
||||
class AnnotationListWrapper extends AnnotationList.AbstractBase {
|
||||
|
||||
@Override
|
||||
public AnnotationDescription get(int index) {
|
||||
AnnotationDescription annotation = annotations.get(index);
|
||||
String annotationTypeName = annotation.getAnnotationType().getActualName();
|
||||
// we are only interested in OnMethodEnter and OnMethodExit annotations
|
||||
if (!Advice.OnMethodEnter.class.getName().equals(annotationTypeName)
|
||||
&& !Advice.OnMethodExit.class.getName().equals(annotationTypeName)) {
|
||||
return annotation;
|
||||
}
|
||||
|
||||
// replace value for "inline" attribute with false
|
||||
return replaceAnnotationValue(
|
||||
annotation, "inline", oldVal -> AnnotationValue.ForConstant.of(false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return annotations.size();
|
||||
}
|
||||
}
|
||||
|
||||
return new AnnotationListWrapper();
|
||||
}
|
||||
}
|
||||
|
||||
private static class DelegatingMethodDescription
|
||||
extends MethodDescription.InDefinedShape.AbstractBase {
|
||||
protected final MethodDescription.InDefinedShape method;
|
||||
|
||||
DelegatingMethodDescription(MethodDescription.InDefinedShape method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public TypeDescription getDeclaringType() {
|
||||
return method.getDeclaringType();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public TypeDescription.Generic getReturnType() {
|
||||
return method.getReturnType();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ParameterList<ParameterDescription.InDefinedShape> getParameters() {
|
||||
return method.getParameters();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public TypeList.Generic getExceptionTypes() {
|
||||
return method.getExceptionTypes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationValue<?, ?> getDefaultValue() {
|
||||
return method.getDefaultValue();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getInternalName() {
|
||||
return method.getInternalName();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public TypeList.Generic getTypeVariables() {
|
||||
return method.getTypeVariables();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getModifiers() {
|
||||
return method.getModifiers();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public AnnotationList getDeclaredAnnotations() {
|
||||
return method.getDeclaredAnnotations();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -68,7 +68,6 @@ public class ForceDynamicallyTypedAssignReturnedFactory implements Advice.PostPr
|
|||
}
|
||||
|
||||
private static AnnotationDescription forceDynamicTyping(AnnotationDescription anno) {
|
||||
|
||||
String name = anno.getAnnotationType().getName();
|
||||
if (name.equals(TO_FIELD_TYPENAME)
|
||||
|| name.equals(TO_ARGUMENT_TYPENAME)
|
||||
|
@ -101,7 +100,7 @@ public class ForceDynamicallyTypedAssignReturnedFactory implements Advice.PostPr
|
|||
return anno;
|
||||
}
|
||||
|
||||
private static AnnotationDescription replaceAnnotationValue(
|
||||
static AnnotationDescription replaceAnnotationValue(
|
||||
AnnotationDescription anno,
|
||||
String propertyName,
|
||||
Function<AnnotationValue<?, ?>, AnnotationValue<?, ?>> valueMapper) {
|
||||
|
|
|
@ -7,6 +7,7 @@ package io.opentelemetry.javaagent.tooling.instrumentation.indy;
|
|||
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule;
|
||||
import io.opentelemetry.javaagent.tooling.bytebuddy.ExceptionHandlers;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
@ -25,11 +26,15 @@ public final class IndyTypeTransformerImpl implements TypeTransformer {
|
|||
private final Advice.WithCustomMapping adviceMapping;
|
||||
private AgentBuilder.Identified.Extendable agentBuilder;
|
||||
private final InstrumentationModule instrumentationModule;
|
||||
private final boolean transformAdvice;
|
||||
|
||||
public IndyTypeTransformerImpl(
|
||||
AgentBuilder.Identified.Extendable agentBuilder, InstrumentationModule module) {
|
||||
this.agentBuilder = agentBuilder;
|
||||
this.instrumentationModule = module;
|
||||
this.transformAdvice =
|
||||
!(instrumentationModule instanceof ExperimentalInstrumentationModule)
|
||||
|| !((ExperimentalInstrumentationModule) instrumentationModule).isIndyReady();
|
||||
this.adviceMapping =
|
||||
Advice.withCustomMapping()
|
||||
.with(
|
||||
|
@ -44,17 +49,23 @@ public final class IndyTypeTransformerImpl implements TypeTransformer {
|
|||
@Override
|
||||
public void applyAdviceToMethod(
|
||||
ElementMatcher<? super MethodDescription> methodMatcher, String adviceClassName) {
|
||||
// default strategy used by AgentBuilder.Transformer.ForAdvice
|
||||
AgentBuilder.PoolStrategy poolStrategy = AgentBuilder.PoolStrategy.Default.FAST;
|
||||
|
||||
agentBuilder =
|
||||
agentBuilder.transform(
|
||||
new AgentBuilder.Transformer.ForAdvice(adviceMapping)
|
||||
.advice(methodMatcher, adviceClassName)
|
||||
// advice transformation already performs uninlining
|
||||
.with(
|
||||
transformAdvice ? poolStrategy : new AdviceUninliningPoolStrategy(poolStrategy))
|
||||
.include(getAdviceLocator(instrumentationModule.getClass().getClassLoader()))
|
||||
.withExceptionHandler(ExceptionHandlers.defaultExceptionHandler()));
|
||||
}
|
||||
|
||||
private static ClassFileLocator getAdviceLocator(ClassLoader classLoader) {
|
||||
private ClassFileLocator getAdviceLocator(ClassLoader classLoader) {
|
||||
ClassFileLocator classFileLocator = ClassFileLocator.ForClassLoader.of(classLoader);
|
||||
return new AdviceLocator(classFileLocator);
|
||||
return transformAdvice ? new AdviceLocator(classFileLocator) : classFileLocator;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in New Issue