Skip to content

Commit

Permalink
Fix instrumentation for graphql-java-22.0 (#11142)
Browse files Browse the repository at this point in the history
  • Loading branch information
laurit authored Apr 18, 2024
1 parent 4325eb2 commit 1da8f5e
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,9 @@ dependencies {

testImplementation(project(":instrumentation:graphql-java:graphql-java-common:testing"))
}

if (findProperty("testLatestDeps") as Boolean) {
otelJava {
minJavaVersionSupported.set(JavaVersion.VERSION_11)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,25 @@

import static io.opentelemetry.javaagent.instrumentation.graphql.v20_0.GraphqlSingletons.addInstrumentation;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.namedOneOf;
import static net.bytebuddy.matcher.ElementMatchers.returns;
import static net.bytebuddy.matcher.ElementMatchers.none;

import com.google.errorprone.annotations.CanIgnoreReturnValue;
import graphql.execution.instrumentation.Instrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.asm.AsmVisitorWrapper;
import net.bytebuddy.description.field.FieldDescription;
import net.bytebuddy.description.field.FieldList;
import net.bytebuddy.description.method.MethodList;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.implementation.Implementation;
import net.bytebuddy.matcher.ElementMatcher;
import net.bytebuddy.pool.TypePool;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;

class GraphqlInstrumentation implements TypeInstrumentation {

Expand All @@ -27,15 +37,78 @@ public ElementMatcher<TypeDescription> typeMatcher() {
@Override
public void transform(TypeTransformer transformer) {
transformer.applyAdviceToMethod(
namedOneOf("checkInstrumentationDefaultState", "checkInstrumentation")
.and(returns(named("graphql.execution.instrumentation.Instrumentation"))),
this.getClass().getName() + "$AddInstrumentationAdvice");
none(), this.getClass().getName() + "$AddInstrumentationAdvice");

transformer.applyTransformer(
(builder, typeDescription, classLoader, javaModule, protectionDomain) ->
builder.visit(
new AsmVisitorWrapper() {
@Override
public int mergeWriter(int flags) {
return flags;
}

@Override
@CanIgnoreReturnValue
public int mergeReader(int flags) {
return flags;
}

@Override
public ClassVisitor wrap(
TypeDescription instrumentedType,
ClassVisitor classVisitor,
Implementation.Context implementationContext,
TypePool typePool,
FieldList<FieldDescription.InDefinedShape> fields,
MethodList<?> methods,
int writerFlags,
int readerFlags) {
return new ClassVisitor(Opcodes.ASM9, classVisitor) {
@Override
public MethodVisitor visitMethod(
int access,
String name,
String descriptor,
String signature,
String[] exceptions) {
MethodVisitor mv =
super.visitMethod(access, name, descriptor, signature, exceptions);
if ("<init>".equals(name)
&& "(Lgraphql/GraphQL$Builder;)V".equals(descriptor)) {
return new MethodVisitor(api, mv) {
@Override
public void visitFieldInsn(
int opcode, String owner, String name, String descriptor) {
// Call GraphqlSingletons.addInstrumentation on the value before it is
// written to the instrumentation field
if (opcode == Opcodes.PUTFIELD
&& "instrumentation".equals(name)
&& "Lgraphql/execution/instrumentation/Instrumentation;"
.equals(descriptor)) {
mv.visitMethodInsn(
Opcodes.INVOKESTATIC,
Type.getInternalName(GraphqlSingletons.class),
"addInstrumentation",
"(Lgraphql/execution/instrumentation/Instrumentation;)Lgraphql/execution/instrumentation/Instrumentation;",
false);
}
super.visitFieldInsn(opcode, owner, name, descriptor);
}
};
}
return mv;
}
};
}
}));
}

@SuppressWarnings("unused")
public static class AddInstrumentationAdvice {
@Advice.OnMethodExit(suppress = Throwable.class)
public static void onExit(@Advice.Return(readOnly = false) Instrumentation instrumentation) {
// this advice is here only to get GraphqlSingletons injected and checked by muzzle
instrumentation = addInstrumentation(instrumentation);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,9 @@ dependencies {

testImplementation(project(":instrumentation:graphql-java:graphql-java-common:testing"))
}

if (findProperty("testLatestDeps") as Boolean) {
otelJava {
minJavaVersionSupported.set(JavaVersion.VERSION_11)
}
}

0 comments on commit 1da8f5e

Please sign in to comment.