diff --git a/instrumentation/apache-thrift/javaagent/build.gradle.kts b/instrumentation/apache-thrift/javaagent/build.gradle.kts new file mode 100644 index 000000000000..f6a86ec23978 --- /dev/null +++ b/instrumentation/apache-thrift/javaagent/build.gradle.kts @@ -0,0 +1,18 @@ +plugins { + id("otel.javaagent-instrumentation") +} + +muzzle { + pass { + group.set("org.apache.thrift") + module.set("libthrift") + versions.set("[0.9.3,)") + assertInverse.set(true) + } +} + + +dependencies { + implementation(project(":instrumentation:apache-thrift:library-autoconfigure")) + library("org.apache.thrift:libthrift:0.9.3") +} diff --git a/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/AsyncMethodCallConstructorAdvice.java b/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/AsyncMethodCallConstructorAdvice.java new file mode 100644 index 000000000000..123898dc5454 --- /dev/null +++ b/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/AsyncMethodCallConstructorAdvice.java @@ -0,0 +1,27 @@ +package io.opentelemetry.javaagent.instrumentation.apachethrift; + +import io.opentelemetry.instrumentation.apachethrift.ThriftAsyncMethodCallback; +import io.opentelemetry.instrumentation.apachethrift.ThriftConstants; +import net.bytebuddy.asm.Advice; +import org.apache.thrift.async.AsyncMethodCallback; +import org.apache.thrift.async.TAsyncMethodCall; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AsyncMethodCallConstructorAdvice { + private static final Logger logger = LoggerFactory.getLogger(AsyncMethodCallConstructorAdvice.class); + + @SuppressWarnings({"rawtypes","unchecked"}) + @Advice.OnMethodExit(suppress = Throwable.class) + public static void after(@Advice.This TAsyncMethodCall objInst + , @Advice.AllArguments Object[] args) { + if (args[3] instanceof AsyncMethodCallback) { + AsyncMethodCallback callback = (AsyncMethodCallback) args[3]; + try { + ThriftConstants.setValue(TAsyncMethodCall.class, objInst, "callback", new ThriftAsyncMethodCallback(callback,null)); + } catch (Exception e) { + logger.error("set value error:", e); + } + } + } +} diff --git a/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/AsyncMethodCallMethodAdvice.java b/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/AsyncMethodCallMethodAdvice.java new file mode 100644 index 000000000000..ac948dc7d625 --- /dev/null +++ b/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/AsyncMethodCallMethodAdvice.java @@ -0,0 +1,46 @@ +package io.opentelemetry.javaagent.instrumentation.apachethrift; + +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.instrumentation.apachethrift.TClientContext; +import io.opentelemetry.instrumentation.apachethrift.ThriftAsyncMethodCallback; +import io.opentelemetry.instrumentation.apachethrift.ThriftConstants; +import net.bytebuddy.asm.Advice; +import org.apache.thrift.async.AsyncMethodCallback; +import org.apache.thrift.async.TAsyncMethodCall; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static io.opentelemetry.instrumentation.apachethrift.ThriftConstants.CONTEXT_THREAD; +import static io.opentelemetry.instrumentation.apachethrift.ThriftSingletons.clientInstrumenter; +import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext; + + +public class AsyncMethodCallMethodAdvice { + public static final Logger logger = LoggerFactory.getLogger(AsyncMethodCallMethodAdvice.class); + + @SuppressWarnings({"unchecked","rawtypes","unused"}) + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter(@Advice.This TAsyncMethodCall methodCall, + @Advice.AllArguments Object[] args, + @Advice.FieldValue("callback") AsyncMethodCallback callback) { + Context parentContext = currentContext(); + TClientContext request = new TClientContext(methodCall.getClass().getName(),null); + if (!clientInstrumenter().shouldStart(parentContext, request)) { + return; + } + Context context = clientInstrumenter().start(parentContext, request); + Scope scope = context.makeCurrent(); + Span span = Span.fromContext(context); + CONTEXT_THREAD.set(request); + try { + ThriftConstants.setValue(TAsyncMethodCall.class, methodCall, "callback", new ThriftAsyncMethodCallback(callback, context)); + } catch (Exception e) { + if (logger.isDebugEnabled()){ + logger.debug("set value callback fail",e); + } + logger.error("set value callback fail",e); + } + } +} diff --git a/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/TAsyncClientConstructorAdvice.java b/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/TAsyncClientConstructorAdvice.java new file mode 100644 index 000000000000..35074fa1faf7 --- /dev/null +++ b/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/TAsyncClientConstructorAdvice.java @@ -0,0 +1,21 @@ +package io.opentelemetry.javaagent.instrumentation.apachethrift; + +import io.opentelemetry.instrumentation.apachethrift.CTProtocolFactory; +import io.opentelemetry.instrumentation.apachethrift.ThriftConstants; +import net.bytebuddy.asm.Advice; +import org.apache.thrift.async.TAsyncClient; +import org.apache.thrift.protocol.TProtocolFactory; + +public class TAsyncClientConstructorAdvice { + @Advice.OnMethodExit(suppress = Throwable.class) + public static void exit(@Advice.This TAsyncClient tAsyncClient + , @Advice.FieldValue("___protocolFactory") TProtocolFactory protocolFactory + ) throws NoSuchFieldException, IllegalAccessException { + ThriftConstants.setValue( + TAsyncClient.class, + tAsyncClient, + "___protocolFactory", + new CTProtocolFactory(protocolFactory) + ); + } +} diff --git a/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/TAsyncClientInstrumentation.java b/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/TAsyncClientInstrumentation.java new file mode 100644 index 000000000000..2535d21f960f --- /dev/null +++ b/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/TAsyncClientInstrumentation.java @@ -0,0 +1,24 @@ +package io.opentelemetry.javaagent.instrumentation.apachethrift; + +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +import static io.opentelemetry.instrumentation.apachethrift.ThriftConstants.TASYNC_CLIENT; +import static net.bytebuddy.matcher.ElementMatchers.isConstructor; +import static net.bytebuddy.matcher.ElementMatchers.named; + +public class TAsyncClientInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return named(TASYNC_CLIENT); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod(isConstructor() + ,this.getClass().getPackage().getName() + ".TAsyncClientConstructorAdvice"); + } +} diff --git a/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/TAsyncMethodCallInstrumentation.java b/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/TAsyncMethodCallInstrumentation.java new file mode 100644 index 000000000000..6bdc24ef6732 --- /dev/null +++ b/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/TAsyncMethodCallInstrumentation.java @@ -0,0 +1,33 @@ +package io.opentelemetry.javaagent.instrumentation.apachethrift; + +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +import static io.opentelemetry.instrumentation.apachethrift.ThriftConstants.T_ASYNC_METHOD_CALL; +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.extendsClass; +import static net.bytebuddy.matcher.ElementMatchers.isConstructor; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.isProtected; +import static net.bytebuddy.matcher.ElementMatchers.named; + +public class TAsyncMethodCallInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return extendsClass(named(T_ASYNC_METHOD_CALL)); + } + + @Override + public void transform(TypeTransformer transformer) { + + transformer.applyAdviceToMethod(isConstructor() + ,this.getClass().getPackage().getName()+ ".AsyncMethodCallConstructorAdvice"); + transformer.applyAdviceToMethod(isMethod() + .and(isProtected()) + .and(named("prepareMethodCall")) + ,this.getClass().getPackage().getName() + ".AsyncMethodCallMethodAdvice"); + } + +} diff --git a/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/TBaseAsyncProcessorInstrumentation.java b/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/TBaseAsyncProcessorInstrumentation.java new file mode 100644 index 000000000000..0b87880fd694 --- /dev/null +++ b/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/TBaseAsyncProcessorInstrumentation.java @@ -0,0 +1,53 @@ +package io.opentelemetry.javaagent.instrumentation.apachethrift; + +import io.opentelemetry.instrumentation.apachethrift.AsyncContext; +import io.opentelemetry.instrumentation.apachethrift.ServerInProtocolWrapper; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import org.apache.thrift.TBaseAsyncProcessor; +import org.apache.thrift.protocol.TProtocol; +import org.apache.thrift.server.AbstractNonblockingServer; + +import static io.opentelemetry.instrumentation.apachethrift.ThriftConstants.CONTEXT_THREAD; +import static io.opentelemetry.instrumentation.apachethrift.ThriftConstants.T_BASE_ASYNC_PROCESSOR; +import static io.opentelemetry.instrumentation.apachethrift.ThriftSingletons.serverInstrumenter; +import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext; +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.extendsClass; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.named; + +@SuppressWarnings("unchecked") +public class TBaseAsyncProcessorInstrumentation implements TypeInstrumentation { + @Override + public ElementMatcher typeMatcher() { + return extendsClass(named(T_BASE_ASYNC_PROCESSOR)); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod(isMethod() + .and(isPublic()) + .and(named("process")) + , getClass().getName() + "$AsyncProcessAdvice"); + } + + @SuppressWarnings({"unchecked","rawtypes"}) + public static class AsyncProcessAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter(@Advice.This TBaseAsyncProcessor tBaseAsyncProcessor + , @Advice.AllArguments Object[] args) { + TProtocol protocol = ((AbstractNonblockingServer.AsyncFrameBuffer) args[0]).getInputProtocol(); + ((ServerInProtocolWrapper) protocol).initial(new AsyncContext(tBaseAsyncProcessor.getProcessMapView()),currentContext()); + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void after(@Advice.Thrown Throwable throwable) { + serverInstrumenter().end(currentContext(), CONTEXT_THREAD.get(), null, throwable); + CONTEXT_THREAD.remove(); + } + } +} diff --git a/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/TBaseProcessorInstrumentation.java b/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/TBaseProcessorInstrumentation.java new file mode 100644 index 000000000000..a8e1fca153b0 --- /dev/null +++ b/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/TBaseProcessorInstrumentation.java @@ -0,0 +1,61 @@ +package io.opentelemetry.javaagent.instrumentation.apachethrift; + +import io.opentelemetry.context.Context; +import io.opentelemetry.instrumentation.apachethrift.ServerInProtocolWrapper; +import io.opentelemetry.instrumentation.apachethrift.ThriftContext; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import org.apache.thrift.TBaseProcessor; + +import static io.opentelemetry.instrumentation.apachethrift.ThriftConstants.CONTEXT_THREAD; +import static io.opentelemetry.instrumentation.apachethrift.ThriftConstants.T_BASE_PROCESSOR; +import static io.opentelemetry.instrumentation.apachethrift.ThriftSingletons.serverInstrumenter; +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.extendsClass; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.named; + +public class TBaseProcessorInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return extendsClass(named(T_BASE_PROCESSOR)); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod(isMethod() + .and(isPublic()) + .and(named("process")) + , getClass().getName() + "$ProcessAdvice"); + } + + @SuppressWarnings({"unchecked","rawtypes"}) + public static class ProcessAdvice { + + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void before(@Advice.This Object obj + , @Advice.AllArguments Object[] args) { + if (obj instanceof TBaseProcessor) { + Object in = args[0]; + if (in instanceof ServerInProtocolWrapper) { + TBaseProcessor tBaseProcessor = (TBaseProcessor) obj; + ((ServerInProtocolWrapper) in).initial(new ThriftContext(tBaseProcessor.getProcessMapView()),Context.current()); + } + } + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void after(@Advice.Thrown Throwable throwable) { + Context context = Context.current(); + if (context!=null) { + serverInstrumenter().end(Context.current(), CONTEXT_THREAD.get(), null, throwable); + CONTEXT_THREAD.remove(); + } + //todo end + } + } +} diff --git a/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/TClientConstructorAdvice.java b/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/TClientConstructorAdvice.java new file mode 100644 index 000000000000..5bc90e6b802d --- /dev/null +++ b/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/TClientConstructorAdvice.java @@ -0,0 +1,23 @@ +package io.opentelemetry.javaagent.instrumentation.apachethrift; + +import io.opentelemetry.instrumentation.apachethrift.ClientOutProtocolWrapper; +import io.opentelemetry.instrumentation.apachethrift.ThriftConstants; +import net.bytebuddy.asm.Advice; +import org.apache.thrift.TServiceClient; +import org.apache.thrift.protocol.TProtocol; + +public class TClientConstructorAdvice { + @Advice.OnMethodExit(suppress = Throwable.class) + public static void exit(@Advice.This TServiceClient tServiceClient + , @Advice.FieldValue("oprot_") TProtocol oprot + ) throws NoSuchFieldException, IllegalAccessException { + if (!(oprot instanceof ClientOutProtocolWrapper)) { + ThriftConstants.setValue( + TServiceClient.class, + tServiceClient, + "oprot_", + new ClientOutProtocolWrapper(oprot) + ); + } + } +} diff --git a/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/TClientInstrumentation.java b/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/TClientInstrumentation.java new file mode 100644 index 000000000000..5879ac7ebd29 --- /dev/null +++ b/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/TClientInstrumentation.java @@ -0,0 +1,94 @@ +package io.opentelemetry.javaagent.instrumentation.apachethrift; + +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.instrumentation.apachethrift.AbstractContext; +import io.opentelemetry.instrumentation.apachethrift.TClientContext; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import org.apache.thrift.TBase; +import org.apache.thrift.TServiceClient; + +import static io.opentelemetry.instrumentation.apachethrift.ThriftConstants.CLIENT_INJECT_THREAD; +import static io.opentelemetry.instrumentation.apachethrift.ThriftConstants.CONTEXT_THREAD; +import static io.opentelemetry.instrumentation.apachethrift.ThriftConstants.TSERVICE_CLIENT; +import static io.opentelemetry.instrumentation.apachethrift.ThriftSingletons.clientInstrumenter; +import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext; +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.extendsClass; +import static net.bytebuddy.matcher.ElementMatchers.isConstructor; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.isPrivate; +import static net.bytebuddy.matcher.ElementMatchers.isProtected; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; +import static net.bytebuddy.matcher.ElementMatchers.takesArguments; + +public class TClientInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return extendsClass(named(TSERVICE_CLIENT)); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod(isConstructor() + .and(takesArgument(1, named("org.apache.thrift.protocol.TProtocol"))) + , this.getClass().getPackage().getName() + ".TClientConstructorAdvice"); + + transformer.applyAdviceToMethod( + isMethod() + .and(isPrivate()) + .and(named("sendBase")) + .and(takesArguments(3)) + .and(takesArgument(0, String.class)) + .and(takesArgument(1, named("org.apache.thrift.TBase"))), + getClass().getName() + "$SendBaseAdvice"); + + transformer.applyAdviceToMethod( + isMethod() + .and(isProtected()) +// .and(takesArgument(1,String.class)) + .and(named("receiveBase")), + getClass().getName() + "$ReceiveBaseAdvice"); + } + + + @SuppressWarnings({"rawtypes","unused"}) + public static class SendBaseAdvice { + + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter(@Advice.This TServiceClient tServiceClient, + @Advice.Argument(0) String methodName, + @Advice.Argument(1) TBase tb, + @Advice.Local("otelContext") Context context + ) { + System.out.println("SendBaseAdvice"); + Context parentContext = currentContext(); + AbstractContext request = new TClientContext(methodName,tb); +// if (!clientInstrumenter().shouldStart(parentContext, request)) { +// return; +// } + context = clientInstrumenter().start(parentContext, request); + Scope scope = context.makeCurrent(); + Span span = Span.fromContext(context); + CONTEXT_THREAD.set(request); + System.out.println(span.getSpanContext().getTraceId()+"\t"+span.getSpanContext().getSpanId()); + } + } + + public static class ReceiveBaseAdvice { + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void stopSpan( + @Advice.Thrown Throwable throwable) { + clientInstrumenter().end(currentContext(), CONTEXT_THREAD.get(), null, throwable); + CLIENT_INJECT_THREAD.remove(); + CONTEXT_THREAD.remove(); + } + } +} diff --git a/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/TMultiplexedProcessorInstrumentation.java b/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/TMultiplexedProcessorInstrumentation.java new file mode 100644 index 000000000000..62b9d4253b77 --- /dev/null +++ b/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/TMultiplexedProcessorInstrumentation.java @@ -0,0 +1,98 @@ +package io.opentelemetry.javaagent.instrumentation.apachethrift; + +import io.opentelemetry.instrumentation.apachethrift.ServerInProtocolWrapper; +import io.opentelemetry.instrumentation.apachethrift.ThriftConstants; +import io.opentelemetry.instrumentation.apachethrift.ThriftContext; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import org.apache.thrift.ProcessFunction; +import org.apache.thrift.TMultiplexedProcessor; +import org.apache.thrift.TProcessor; +import org.apache.thrift.protocol.TProtocol; + +import java.util.HashMap; +import java.util.Map; + +import static io.opentelemetry.instrumentation.apachethrift.ThriftConstants.TM_M; +import static io.opentelemetry.instrumentation.apachethrift.ThriftConstants.T_MULTIPLEXED_PROCESSOR; +import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext; +import static net.bytebuddy.matcher.ElementMatchers.isConstructor; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.named; + +public class TMultiplexedProcessorInstrumentation implements TypeInstrumentation { + + + @Override + public ElementMatcher typeMatcher() { + return named(T_MULTIPLEXED_PROCESSOR); + } + + @Override + public void transform(TypeTransformer transformer) { + + transformer.applyAdviceToMethod(isConstructor() + , getClass().getName() + "$TMultiplexedProcessorConstructorAdvice"); + + transformer.applyAdviceToMethod(isMethod() + .and(isPublic()) + .and(named("process")) + , getClass().getName() + "$TMultiplexedProcessorProcessAdvice"); + transformer.applyAdviceToMethod(isMethod() + .and(isPublic()) + .and(named("registerProcessor")) + , getClass().getName() + "$TMultiplexedProcessorRegisterProcessAdvice"); + //0.12以上版本 + transformer.applyAdviceToMethod(isMethod() + .and(isPublic()) + .and(named("registerDefault")) + , getClass().getName() + "$TMultiplexedProcessorRegisterDefaultAdvice"); + } + + @SuppressWarnings("rawtypes") + public static class TMultiplexedProcessorConstructorAdvice { + @Advice.OnMethodExit(suppress = Throwable.class) + public static void after(@Advice.This TMultiplexedProcessor processor) { + TM_M.put(processor,new HashMap()); + } + } + + @SuppressWarnings({"rawtypes","unchecked"}) + public static class TMultiplexedProcessorProcessAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter(@Advice.This TMultiplexedProcessor processor, + @Advice.AllArguments Object[] args) { + TProtocol protocol = (TProtocol) args[0]; + ((ServerInProtocolWrapper) protocol).initial(new ThriftContext(TM_M.get(processor)),currentContext()); + } + } + + @SuppressWarnings("rawtypes") + public static class TMultiplexedProcessorRegisterProcessAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter(@Advice.This TMultiplexedProcessor obj, + @Advice.AllArguments Object[] allArguments) { + Map processMap = TM_M.get(obj); + String serviceName = (String) allArguments[0]; + TProcessor processor = (TProcessor) allArguments[1]; + processMap.putAll(ThriftConstants.getProcessMap(serviceName, processor)); + TM_M.put(obj,processMap); + } + } + + @SuppressWarnings("rawtypes") + public static class TMultiplexedProcessorRegisterDefaultAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter(@Advice.This TMultiplexedProcessor obj, + @Advice.AllArguments Object[] allArguments) { + Map processMap = TM_M.get(obj); + TProcessor processor = (TProcessor) allArguments[0]; + processMap.putAll(ThriftConstants.getProcessMap(processor)); + TM_M.put(obj,processMap); + } + } +} diff --git a/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/TProcessorInstrumentation.java b/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/TProcessorInstrumentation.java new file mode 100644 index 000000000000..1ca8616a17eb --- /dev/null +++ b/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/TProcessorInstrumentation.java @@ -0,0 +1,39 @@ +package io.opentelemetry.javaagent.instrumentation.apachethrift; + +import static io.opentelemetry.instrumentation.apachethrift.ThriftConstants.T_ASYNC_PROCESSOR; +import static io.opentelemetry.instrumentation.apachethrift.ThriftConstants.T_BASE_ASYNC_PROCESSOR; +import static io.opentelemetry.instrumentation.apachethrift.ThriftConstants.T_BASE_PROCESSOR; +import static io.opentelemetry.instrumentation.apachethrift.ThriftConstants.T_MULTIPLEXED_PROCESSOR; +import static io.opentelemetry.instrumentation.apachethrift.ThriftConstants.T_PROCESSOR; +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; +import static net.bytebuddy.matcher.ElementMatchers.not; + +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +public class TProcessorInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return implementsInterface(namedOneOf(T_PROCESSOR,T_ASYNC_PROCESSOR)) + .and(not(named(T_BASE_ASYNC_PROCESSOR))) + .and(not(named(T_BASE_PROCESSOR))) + .and(not(named(T_MULTIPLEXED_PROCESSOR))); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod(isMethod() + .and(isPublic()) + .and(named("process")) + , this.getClass().getPackage().getName() + ".TProcessorProcessAdvice"); + + } + +} diff --git a/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/TProcessorProcessAdvice.java b/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/TProcessorProcessAdvice.java new file mode 100644 index 000000000000..8d94d881c57e --- /dev/null +++ b/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/TProcessorProcessAdvice.java @@ -0,0 +1,33 @@ +package io.opentelemetry.javaagent.instrumentation.apachethrift; + +import io.opentelemetry.context.Context; +import io.opentelemetry.instrumentation.apachethrift.ServerInProtocolWrapper; +import io.opentelemetry.instrumentation.apachethrift.ThriftContext; +import net.bytebuddy.asm.Advice; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static io.opentelemetry.instrumentation.apachethrift.ThriftConstants.CONTEXT_THREAD; +import static io.opentelemetry.instrumentation.apachethrift.ThriftSingletons.serverInstrumenter; +import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext; + +public class TProcessorProcessAdvice { + public static final Logger logger = LoggerFactory.getLogger(TProcessorProcessAdvice.class); + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter(@Advice.This Object obj, @Advice.AllArguments Object[] args) { + logger.info("TProcessorProcessAdvice : " + obj.getClass().getName()); + Object in = args[0]; + if (in instanceof ServerInProtocolWrapper) { + ((ServerInProtocolWrapper) in).initial(new ThriftContext(null),currentContext()); + } + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void after(@Advice.Thrown Throwable throwable) { + Context context = Context.current(); + if (context!=null) { + serverInstrumenter().end(Context.current(), CONTEXT_THREAD.get(), null, throwable); + CONTEXT_THREAD.remove(); + } + } +} diff --git a/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/TServerConstructorAdvice.java b/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/TServerConstructorAdvice.java new file mode 100644 index 000000000000..d8fcb9561d77 --- /dev/null +++ b/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/TServerConstructorAdvice.java @@ -0,0 +1,31 @@ +package io.opentelemetry.javaagent.instrumentation.apachethrift; + +import io.opentelemetry.instrumentation.apachethrift.STProtocolFactory; +import io.opentelemetry.instrumentation.apachethrift.ThriftConstants; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.implementation.bytecode.assign.Assigner; +import org.apache.thrift.protocol.TProtocolFactory; +import org.apache.thrift.server.TServer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TServerConstructorAdvice { + private static final Logger logger = LoggerFactory.getLogger(TServerConstructorAdvice.class); + + @Advice.OnMethodExit(suppress = Throwable.class) + public static void onExit(@Advice.This(typing = Assigner.Typing.DYNAMIC) TServer tServer, + @Advice.FieldValue(value = "inputProtocolFactory_", readOnly = false, typing = Assigner.Typing.DYNAMIC) TProtocolFactory inputProtocolFactory + ) { + try { + TProtocolFactory trans = new STProtocolFactory(inputProtocolFactory); + ThriftConstants.setValue( + TServer.class, + tServer, + "inputProtocolFactory_", + trans + ); + } catch (Exception e) { + logger.debug("TServerConstructorAdvice exception:", e); + } + } +} diff --git a/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/TServerInstrumentation.java b/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/TServerInstrumentation.java new file mode 100644 index 000000000000..fe8631883467 --- /dev/null +++ b/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/TServerInstrumentation.java @@ -0,0 +1,25 @@ +package io.opentelemetry.javaagent.instrumentation.apachethrift; + +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import static io.opentelemetry.instrumentation.apachethrift.ThriftConstants.T_SERVER; +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.extendsClass; +import static net.bytebuddy.matcher.ElementMatchers.isConstructor; +import static net.bytebuddy.matcher.ElementMatchers.named; + +public class TServerInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return extendsClass(named(T_SERVER)); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod(isConstructor() + ,this.getClass().getPackage().getName() + ".TServerConstructorAdvice"); + } + +} diff --git a/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/ThriftInstrumentationModule.java b/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/ThriftInstrumentationModule.java new file mode 100644 index 000000000000..4defd07372c3 --- /dev/null +++ b/instrumentation/apache-thrift/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachethrift/ThriftInstrumentationModule.java @@ -0,0 +1,35 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.apachethrift; + +import com.google.auto.service.AutoService; +import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import java.util.List; + +import static java.util.Arrays.asList; + +@AutoService(InstrumentationModule.class) +public class ThriftInstrumentationModule extends InstrumentationModule { + public ThriftInstrumentationModule() { + super("alibaba-thrift", "thrift"); + } + + + @Override + public List typeInstrumentations() { + return asList( + new TClientInstrumentation(), + new TServerInstrumentation(), + new TAsyncMethodCallInstrumentation(), + new TAsyncClientInstrumentation(), + new TBaseProcessorInstrumentation(), + new TBaseAsyncProcessorInstrumentation(), + new TMultiplexedProcessorInstrumentation(), + new TProcessorInstrumentation() + ); + } +} diff --git a/instrumentation/apache-thrift/library-autoconfigure/build.gradle.kts b/instrumentation/apache-thrift/library-autoconfigure/build.gradle.kts new file mode 100644 index 000000000000..7fab38e4e454 --- /dev/null +++ b/instrumentation/apache-thrift/library-autoconfigure/build.gradle.kts @@ -0,0 +1,6 @@ +plugins { + id("otel.library-instrumentation") +} +dependencies { + library("org.apache.thrift:libthrift:0.9.3") +} diff --git a/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/AbstractContext.java b/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/AbstractContext.java new file mode 100644 index 000000000000..a587c963f441 --- /dev/null +++ b/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/AbstractContext.java @@ -0,0 +1,32 @@ +package io.opentelemetry.instrumentation.apachethrift; + +import java.util.HashMap; + +import static java.util.concurrent.TimeUnit.MILLISECONDS; + + +public abstract class AbstractContext extends HashMap { + private static final long serialVersionUID = -6872498296375172854L; + public String methodName; + public long startTime = 0L; + public boolean createdSpan = false; + + public abstract String getSpanType(); + + public abstract String getArguments(); + + public abstract String getOperatorName(); + + public final void setup(String methodName) { + this.methodName = methodName; + this.startTime = MILLISECONDS.toMicros(System.currentTimeMillis()); + } + + public boolean isCreatedSpan() { + return createdSpan; + } + + public void setCreatedSpan(boolean createdSpan) { + this.createdSpan = createdSpan; + } +} diff --git a/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/AsyncContext.java b/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/AsyncContext.java new file mode 100644 index 000000000000..958165c32f58 --- /dev/null +++ b/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/AsyncContext.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.opentelemetry.instrumentation.apachethrift; + +import java.util.Map; +import org.apache.thrift.AsyncProcessFunction; + +import static io.opentelemetry.instrumentation.apachethrift.ThriftConstants.INSTRUMENTATION_NAME_CLIENT; + +public class AsyncContext extends AbstractContext { + private static final long serialVersionUID = 6563600437989592949L; + private final Map> processMapView; + + public AsyncContext(Map> processMapView) { + this.processMapView = processMapView; + } + + @Override + public String getSpanType() { + return INSTRUMENTATION_NAME_CLIENT; + } + + @Override + public String getArguments() { +// for (Map.Entry entry : processMapView.entrySet()){ +// System.out.println("ARGS1:"+entry.getKey()+"\t"+entry.getValue().getClass().getName()); +// +// System.out.println("ARGS2:"+entry.getValue().getEmptyArgsInstance().toString()); +// } + if (processMapView==null){ + return null; + } + AsyncProcessFunction function = processMapView.get(methodName); + if (function==null){ + return null; + } + return function.getEmptyArgsInstance().toString(); + } + + @Override + public String getOperatorName() { + if (processMapView==null){ + return null; + } + AsyncProcessFunction function = processMapView.get(methodName); + if (function==null){ + return null; + } + return function.getClass().getName(); + } + +} diff --git a/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/CTProtocolFactory.java b/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/CTProtocolFactory.java new file mode 100644 index 000000000000..8c89d33956eb --- /dev/null +++ b/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/CTProtocolFactory.java @@ -0,0 +1,19 @@ +package io.opentelemetry.instrumentation.apachethrift; + +import org.apache.thrift.protocol.TProtocol; +import org.apache.thrift.protocol.TProtocolFactory; +import org.apache.thrift.transport.TTransport; + +public class CTProtocolFactory implements TProtocolFactory { + + private static final long serialVersionUID = 7848944258988155246L; + TProtocolFactory inputProtocolFactory; + public CTProtocolFactory(TProtocolFactory inputProtocolFactory){ + this.inputProtocolFactory = inputProtocolFactory; + } + @Override + public TProtocol getProtocol(TTransport tTransport) { + ClientOutProtocolWrapper wrapper = new ClientOutProtocolWrapper(inputProtocolFactory.getProtocol(tTransport)); + return wrapper; + } +} diff --git a/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/ClientOutProtocolWrapper.java b/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/ClientOutProtocolWrapper.java new file mode 100644 index 000000000000..8c03c5669a42 --- /dev/null +++ b/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/ClientOutProtocolWrapper.java @@ -0,0 +1,72 @@ +package io.opentelemetry.instrumentation.apachethrift; + +import static io.opentelemetry.instrumentation.apachethrift.ThriftConstants.CLIENT_INJECT_THREAD; +import static io.opentelemetry.instrumentation.apachethrift.ThriftConstants.CONTEXT_THREAD; +import static io.opentelemetry.instrumentation.apachethrift.ThriftConstants.THRIFT_MAGIC_FIELD; +import static io.opentelemetry.instrumentation.apachethrift.ThriftConstants.THRIFT_MAGIC_FIELD_ID; + +import java.util.Map; +import java.util.Set; +import org.apache.thrift.TException; +import org.apache.thrift.protocol.TField; +import org.apache.thrift.protocol.TMap; +import org.apache.thrift.protocol.TMessage; +import org.apache.thrift.protocol.TProtocol; +import org.apache.thrift.protocol.TProtocolDecorator; +import org.apache.thrift.protocol.TType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** + * Wrapping client output protocol for injecting and propagating the trace header. This is also safe even if the server + * doesn't deal with it. + */ +public class ClientOutProtocolWrapper extends TProtocolDecorator { + + private static final Logger log = LoggerFactory.getLogger(ClientOutProtocolWrapper.class); + + public ClientOutProtocolWrapper(TProtocol protocol) { + super(protocol); + } + + @Override + public final void writeMessageBegin(TMessage message) throws TException { + CLIENT_INJECT_THREAD.set(false); + super.writeMessageBegin(message); + } + + @Override + public final void writeFieldStop() throws TException { + boolean injected = CLIENT_INJECT_THREAD.get(); + if (!injected) { + try { + writeHeader(CONTEXT_THREAD.get()); + } catch (Throwable throwable) { + if (log.isDebugEnabled()) { + log.error("inject exception", throwable); + } + } finally { + CLIENT_INJECT_THREAD.set(true); + } + } + super.writeFieldStop(); + } + + private void writeHeader(Map header) throws TException { + super.writeFieldBegin(new TField(THRIFT_MAGIC_FIELD, TType.MAP, THRIFT_MAGIC_FIELD_ID)); + super.writeMapBegin(new TMap(TType.STRING, TType.STRING, header.size())); + + Set> entries = header.entrySet(); + for (Map.Entry entry : entries) { + super.writeString(entry.getKey()); + super.writeString(entry.getValue()); + if (log.isDebugEnabled()) { + log.debug("client header >> " + entry.getKey() + "\t=\t" + entry.getValue()); + } + } + + super.writeMapEnd(); + super.writeFieldEnd(); + } +} diff --git a/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/STProtocolFactory.java b/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/STProtocolFactory.java new file mode 100644 index 000000000000..10ce938baf03 --- /dev/null +++ b/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/STProtocolFactory.java @@ -0,0 +1,18 @@ +package io.opentelemetry.instrumentation.apachethrift; + +import org.apache.thrift.protocol.TProtocol; +import org.apache.thrift.protocol.TProtocolFactory; +import org.apache.thrift.transport.TTransport; + +public class STProtocolFactory implements TProtocolFactory { + private static final long serialVersionUID = 109860674394749646L; + TProtocolFactory inputProtocolFactory; + public STProtocolFactory(TProtocolFactory inputProtocolFactory){ + this.inputProtocolFactory = inputProtocolFactory; + } + @Override + public TProtocol getProtocol(TTransport tTransport) { + ServerInProtocolWrapper wrapper = new ServerInProtocolWrapper(inputProtocolFactory.getProtocol(tTransport)); + return wrapper; + } +} diff --git a/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/ServerInProtocolWrapper.java b/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/ServerInProtocolWrapper.java new file mode 100644 index 000000000000..d585805d0449 --- /dev/null +++ b/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/ServerInProtocolWrapper.java @@ -0,0 +1,94 @@ +package io.opentelemetry.instrumentation.apachethrift; + +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import org.apache.thrift.TException; +import org.apache.thrift.protocol.TField; +import org.apache.thrift.protocol.TMap; +import org.apache.thrift.protocol.TMessage; +import org.apache.thrift.protocol.TProtocol; +import org.apache.thrift.protocol.TProtocolDecorator; +import org.apache.thrift.protocol.TType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import static io.opentelemetry.instrumentation.apachethrift.ThriftConstants.CONTEXT_THREAD; +import static io.opentelemetry.instrumentation.apachethrift.ThriftSingletons.serverInstrumenter; + + +@SuppressWarnings({"unchecked","unused"}) +public class ServerInProtocolWrapper extends TProtocolDecorator { + public static final Logger log = LoggerFactory.getLogger(ServerInProtocolWrapper.class); + + public ServerInProtocolWrapper(TProtocol protocol) { + super(protocol); + } + + private Context parentContext; + public void initial(AbstractContext context,Context parentContext) { + CONTEXT_THREAD.set(context); + this.parentContext = parentContext; + } + + @Override + public TField readFieldBegin() throws TException { + TField field = super.readFieldBegin(); + if (field.id == ThriftConstants.THRIFT_MAGIC_FIELD_ID && field.type == TType.MAP) { + try { + TMap tMap = super.readMapBegin(); + Map header = new HashMap<>(tMap.size); + + for (int i = 0; i < tMap.size; i++) { + String key = readString(); + String value = readString(); + header.put(key, value); + if (log.isDebugEnabled()) { + log.debug("receive header >> " + key + "\t=\t" + value); + } + } + + AbstractContext context = CONTEXT_THREAD.get(); + context.setCreatedSpan(true); + context.putAll(header); + if (parentContext==null){ + parentContext = Context.current(); + } + if (serverInstrumenter().shouldStart(parentContext, context)) { + Context otelContext = serverInstrumenter().start(parentContext, context); + Scope scope = otelContext.makeCurrent(); + Span span = Span.fromContext(otelContext); + CONTEXT_THREAD.set(context); + } + } catch (Throwable throwable) { + log.error("readFieldBegin exception", throwable); + throw throwable; + } finally { + super.readMapEnd(); + super.readFieldEnd(); +// readFieldEnd(); + } + return readFieldBegin(); + } + + return field; + } + + @Override + public TMessage readMessageBegin() throws TException { + TMessage message = super.readMessageBegin(); + if (Objects.nonNull(message)) { + AbstractContext context = CONTEXT_THREAD.get(); + if (context == null) { + context = new ThriftContext(null); + CONTEXT_THREAD.set(context); + } + context.setup(message.name); + } + return message; + } + +} diff --git a/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/TClientContext.java b/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/TClientContext.java new file mode 100644 index 000000000000..90946a1d4f3c --- /dev/null +++ b/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/TClientContext.java @@ -0,0 +1,53 @@ +package io.opentelemetry.instrumentation.apachethrift; + +import static io.opentelemetry.instrumentation.apachethrift.ThriftConstants.INSTRUMENTATION_NAME_CLIENT; +import static io.opentelemetry.instrumentation.apachethrift.ThriftConstants.TAG_ARGS; +import static io.opentelemetry.instrumentation.apachethrift.ThriftConstants.TAG_METHOD; + +import org.apache.thrift.TBase; +import org.apache.thrift.TFieldIdEnum; + +@SuppressWarnings("rawtypes") +public class TClientContext extends AbstractContext { + + private static final long serialVersionUID = -2126788453042003420L; + + public TClientContext(String methodName, TBase tb) { + if (tb != null) { + put(TAG_ARGS, getArguments(methodName, tb)); + } + put(TAG_METHOD, methodName); + } + + private static String getArguments(String method, TBase base) { + int idx = 0; + StringBuilder buffer = new StringBuilder(method).append("("); + while (true) { + TFieldIdEnum field = base.fieldForId(++idx); + if (field == null) { + idx--; + break; + } + buffer.append(field.getFieldName()).append(", "); + } + if (idx > 0) { + buffer.delete(buffer.length() - 2, buffer.length()); + } + return buffer.append(")").toString(); + } + + @Override + public String getArguments() { + return get(TAG_ARGS); + } + + @Override + public String getOperatorName() { + return get(TAG_METHOD); + } + + @Override + public String getSpanType() { + return INSTRUMENTATION_NAME_CLIENT; + } +} diff --git a/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/ThriftAsyncMethodCallback.java b/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/ThriftAsyncMethodCallback.java new file mode 100644 index 000000000000..d0d679bf1ae2 --- /dev/null +++ b/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/ThriftAsyncMethodCallback.java @@ -0,0 +1,50 @@ +package io.opentelemetry.instrumentation.apachethrift; + + +import io.opentelemetry.context.Context; +import org.apache.thrift.async.AsyncMethodCallback; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static io.opentelemetry.instrumentation.apachethrift.ThriftConstants.CLIENT_INJECT_THREAD; +import static io.opentelemetry.instrumentation.apachethrift.ThriftConstants.CONTEXT_THREAD; +import static io.opentelemetry.instrumentation.apachethrift.ThriftSingletons.clientInstrumenter; + +@SuppressWarnings("cast") +public class ThriftAsyncMethodCallback implements AsyncMethodCallback { + public static final Logger logger = LoggerFactory.getLogger(ThriftAsyncMethodCallback.class); + final AsyncMethodCallback callback; + Context context; + + public ThriftAsyncMethodCallback(AsyncMethodCallback callback, Context context) { + this.callback = callback; + this.context = context; + } + + @Override + public void onComplete(T response) { + if (context==null){ + return; + } + try { + logger.debug("onComplete scope is not null,thread:" + Thread.currentThread().getName()); + clientInstrumenter().end(context, CONTEXT_THREAD.get(), null, null); + CLIENT_INJECT_THREAD.remove(); + } finally { + callback.onComplete(response); + } + } + + @Override + public void onError(Exception exception) { + if (context==null){ + return; + } + try { + clientInstrumenter().end(context, CONTEXT_THREAD.get(), null, exception); + CLIENT_INJECT_THREAD.remove(); + } finally { + callback.onError(exception); + } + } +} diff --git a/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/ThriftConstants.java b/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/ThriftConstants.java new file mode 100644 index 000000000000..b55618ae435b --- /dev/null +++ b/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/ThriftConstants.java @@ -0,0 +1,98 @@ +package io.opentelemetry.instrumentation.apachethrift; + +import org.apache.thrift.ProcessFunction; +import org.apache.thrift.TBaseAsyncProcessor; +import org.apache.thrift.TBaseProcessor; +import org.apache.thrift.TMultiplexedProcessor; +import org.apache.thrift.TProcessor; +import org.apache.thrift.protocol.TMultiplexedProtocol; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +@SuppressWarnings({"unchecked","rawtypes"}) +public class ThriftConstants { + + public static final Logger logger = LoggerFactory.getLogger(ThriftConstants.class); + + public static final String INSTRUMENTATION_NAME = "thrift"; + public static final String SPAN_NAME = "thrift"; + public static final String INSTRUMENTATION_NAME_CLIENT = "thrift-client"; + public static final String INSTRUMENTATION_NAME_SERVER = "thrift-server"; + public static final String TASYNC_CLIENT = "org.apache.thrift.async.TAsyncClient"; + public static final String T_ASYNC_METHOD_CALL = "org.apache.thrift.async.TAsyncMethodCall"; + public static final String TSERVICE_CLIENT = "org.apache.thrift.TServiceClient"; + public static final String T_BASE_PROCESSOR = "org.apache.thrift.TBaseProcessor"; + public static final String T_PROCESSOR = "org.apache.thrift.TProcessor"; + public static final String T_ASYNC_PROCESSOR = "org.apache.thrift.TAsyncProcessor"; + public static final String T_MULTIPLEXED_PROCESSOR = "org.apache.thrift.TMultiplexedProcessor"; + public static final String T_BASE_ASYNC_PROCESSOR = "org.apache.thrift.TBaseAsyncProcessor"; + public static final String T_SERVER = "org.apache.thrift.server.TServer"; + + public static final String THRIFT_MAGIC_FIELD = "THRIFT_MAGIC_FIELD"; // Field Name + public static final short THRIFT_MAGIC_FIELD_ID = 8888; // Field ID, a magic number + + public static final String THRIFT_CLIENT_COMPONENT = INSTRUMENTATION_NAME_CLIENT; + public static final String THRIFT_SERVER_COMPONENT = INSTRUMENTATION_NAME_SERVER; + + public static final ThreadLocal CONTEXT_THREAD = new ThreadLocal<>(); + public static final ThreadLocal CLIENT_INJECT_THREAD = new ThreadLocal<>(); + public static final ConcurrentHashMap> TM_M = new ConcurrentHashMap<>(); + + public static final String TAG_ARGS = "args"; + public static final String TAG_METHOD = "method"; + + @SuppressWarnings("rawtypes") + public static final void setValue(Class klass, Object instance, String name, Object value) throws NoSuchFieldException, IllegalAccessException { + Field field = klass.getDeclaredField(name); + field.setAccessible(true); + field.set(instance, value); + } + + @SuppressWarnings("rawtypes") + public static final Object getValue(Class klass, Object instance, String name) throws NoSuchFieldException, IllegalAccessException { + Field field = klass.getDeclaredField(name); + field.setAccessible(true); + return field.get(instance); + } + + public static Map getProcessMap(String serviceName, TProcessor processor) { + Map hashMap = new HashMap<>(); + if (processor instanceof TBaseProcessor) { + Map processMapView = ((TBaseProcessor) processor).getProcessMapView(); + processMapView.forEach((k, v) -> hashMap.put(serviceName + TMultiplexedProtocol.SEPARATOR + k, v)); + } else if (processor instanceof TBaseAsyncProcessor) { + Map processMapView = ((TBaseAsyncProcessor) processor).getProcessMapView(); + processMapView.forEach((k, v) -> hashMap.put(serviceName + TMultiplexedProtocol.SEPARATOR + k, v)); + } else { + + if (logger.isDebugEnabled()) { + logger.debug("Not support this processor:{},serviceName:{},super:{}", serviceName, processor.getClass().getName(),processor.getClass().getSuperclass().getName()); + } + } + return hashMap; + } + + public static Map getProcessMap(TProcessor processor) { + Map hashMap = new HashMap<>(); + if (processor instanceof TBaseProcessor || processor instanceof TBaseAsyncProcessor) { + Map processMapView = ((TBaseProcessor) processor).getProcessMapView(); + hashMap.putAll(processMapView); +// } else if (processor instanceof TBaseAsyncProcessor) { +// Map processMapView = ((TBaseProcessor) processor).getProcessMapView(); +// hashMap.putAll(processMapView); + } else { + if (logger.isDebugEnabled()) { + logger.debug("Not support this processor:{}", processor.getClass().getName()); + } + } + return hashMap; + } + + private ThriftConstants(){ + + } +} diff --git a/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/ThriftContext.java b/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/ThriftContext.java new file mode 100644 index 000000000000..b36884bf4b1a --- /dev/null +++ b/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/ThriftContext.java @@ -0,0 +1,56 @@ +package io.opentelemetry.instrumentation.apachethrift; + +import java.util.Map; +import org.apache.thrift.ProcessFunction; + +import static io.opentelemetry.instrumentation.apachethrift.ThriftConstants.INSTRUMENTATION_NAME_SERVER; +import static io.opentelemetry.instrumentation.apachethrift.ThriftConstants.TAG_ARGS; +import static io.opentelemetry.instrumentation.apachethrift.ThriftConstants.TAG_METHOD; + +@SuppressWarnings("rawtypes") +public class ThriftContext extends AbstractContext { + private static final long serialVersionUID = -2818758873846404694L; + private final Map processMapView; + + public ThriftContext(Map processMapView) { + this.processMapView = processMapView; + } + + @Override + public String getSpanType() { + return INSTRUMENTATION_NAME_SERVER; + } + + @Override + public String getArguments() { + String m = get(TAG_ARGS); + if (m!=null){ + return m; + } + if (processMapView==null){ + return null; + } + ProcessFunction function = processMapView.get(methodName); + if (function==null){ + return null; + } + return function.getEmptyArgsInstance().toString(); + } + + @Override + public String getOperatorName() { + String m = get(TAG_METHOD); + if (m!=null){ + return m; + } + if (processMapView==null){ + return null; + } + ProcessFunction function = processMapView.get(methodName); + if (function==null){ + return methodName; + } + return function.getClass().getName(); + } + +} diff --git a/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/ThriftGetter.java b/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/ThriftGetter.java new file mode 100644 index 000000000000..21500c3dbcc0 --- /dev/null +++ b/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/ThriftGetter.java @@ -0,0 +1,20 @@ +package io.opentelemetry.instrumentation.apachethrift; + + +import io.opentelemetry.context.propagation.TextMapGetter; +import javax.annotation.Nullable; + +enum ThriftGetter implements TextMapGetter { + INSTANCE; + + @Override + public Iterable keys(AbstractContext carrier) { + return carrier.keySet(); + } + + @Nullable + @Override + public String get(@Nullable AbstractContext carrier, String key) { + return carrier.get(key); + } +} diff --git a/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/ThriftRpcAttributesGetter.java b/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/ThriftRpcAttributesGetter.java new file mode 100644 index 000000000000..eaa38ddd858d --- /dev/null +++ b/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/ThriftRpcAttributesGetter.java @@ -0,0 +1,28 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.apachethrift; + +import io.opentelemetry.instrumentation.api.instrumenter.rpc.RpcAttributesGetter; + +//todo get value +enum ThriftRpcAttributesGetter implements RpcAttributesGetter { + INSTANCE; + + @Override + public String getSystem(AbstractContext request) { + return "apache_thrift"; + } + + @Override + public String getService(AbstractContext request) { + return request.getSpanType(); + } + + @Override + public String getMethod(AbstractContext request) { + return request.getOperatorName(); + } +} diff --git a/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/ThriftSetter.java b/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/ThriftSetter.java new file mode 100644 index 000000000000..ec0e95477598 --- /dev/null +++ b/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/ThriftSetter.java @@ -0,0 +1,14 @@ +package io.opentelemetry.instrumentation.apachethrift; + + +import io.opentelemetry.context.propagation.TextMapSetter; + +enum ThriftSetter implements TextMapSetter { + + INSTANCE; + + @Override + public void set( AbstractContext carrier, String key, String value) { + carrier.put(key, value); + } +} diff --git a/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/ThriftSingletons.java b/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/ThriftSingletons.java new file mode 100644 index 000000000000..4647a2636b14 --- /dev/null +++ b/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/ThriftSingletons.java @@ -0,0 +1,30 @@ +package io.opentelemetry.instrumentation.apachethrift; + +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; + +public final class ThriftSingletons { + + private static final Instrumenter SERVER_INSTRUMENTER; + private static final Instrumenter CLIENT_INSTRUMENTER; + + + static { + OpenTelemetry openTelemetry = GlobalOpenTelemetry.get(); + ThriftTelemetry thriftTelemetry = ThriftTelemetry.create(openTelemetry); + SERVER_INSTRUMENTER = thriftTelemetry.serverInstrumenter(); + CLIENT_INSTRUMENTER = thriftTelemetry.clientInstrumenter(); + } + + + public static Instrumenter serverInstrumenter(){ + return SERVER_INSTRUMENTER; + } + public static Instrumenter clientInstrumenter(){ + return CLIENT_INSTRUMENTER; + } + private ThriftSingletons(){ + + } +} diff --git a/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/ThriftTelemetry.java b/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/ThriftTelemetry.java new file mode 100644 index 000000000000..0fe89ff9602a --- /dev/null +++ b/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/ThriftTelemetry.java @@ -0,0 +1,43 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.apachethrift; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; + +/** Entrypoint for instrumenting Apache Dubbo servers and clients. */ +public final class ThriftTelemetry { + + /** Returns a new {@link ThriftTelemetry} configured with the given {@link OpenTelemetry}. */ + public static ThriftTelemetry create(OpenTelemetry openTelemetry) { + return builder(openTelemetry).build(); + } + + /** + * Returns a new {@link ThriftTelemetryBuilder} configured with the given {@link OpenTelemetry}. + */ + public static ThriftTelemetryBuilder builder(OpenTelemetry openTelemetry) { + return new ThriftTelemetryBuilder(openTelemetry); + } + + private final Instrumenter serverInstrumenter; + private final Instrumenter clientInstrumenter; + + ThriftTelemetry( + Instrumenter serverInstrumenter, + Instrumenter clientInstrumenter) { + this.serverInstrumenter = serverInstrumenter; + this.clientInstrumenter = clientInstrumenter; + } + + public Instrumenter serverInstrumenter(){ + return serverInstrumenter; + } + public Instrumenter clientInstrumenter(){ + return clientInstrumenter; + } + +} diff --git a/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/ThriftTelemetryBuilder.java b/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/ThriftTelemetryBuilder.java new file mode 100644 index 000000000000..4f3511eec4a9 --- /dev/null +++ b/instrumentation/apache-thrift/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/apachethrift/ThriftTelemetryBuilder.java @@ -0,0 +1,81 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.apachethrift; + +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder; +import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.rpc.RpcClientAttributesExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.rpc.RpcServerAttributesExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.rpc.RpcSpanNameExtractor; +import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; + +/** A builder of {@link ThriftTelemetry}. */ +public final class ThriftTelemetryBuilder { + + private static final String INSTRUMENTATION_NAME = "io.opentelemetry.apache-thrift"; + + private final OpenTelemetry openTelemetry; + @Nullable private String peerService; + private final List> attributesExtractors = + new ArrayList<>(); + + ThriftTelemetryBuilder(OpenTelemetry openTelemetry) { + this.openTelemetry = openTelemetry; + } + + /** Sets the {@code peer.service} attribute for http client spans. */ + public void setPeerService(String peerService) { + this.peerService = peerService; + } + + /** + * Adds an additional {@link AttributesExtractor} to invoke to set attributes to instrumented + * items. + */ + @CanIgnoreReturnValue + public ThriftTelemetryBuilder addAttributesExtractor( + AttributesExtractor attributesExtractor) { + attributesExtractors.add(attributesExtractor); + return this; + } + + /** + * Returns a new {@link ThriftTelemetry} with the settings of this {@link ThriftTelemetryBuilder}. + */ + public ThriftTelemetry build() { + ThriftRpcAttributesGetter rpcAttributesGetter = ThriftRpcAttributesGetter.INSTANCE; + SpanNameExtractor spanNameExtractor = + RpcSpanNameExtractor.create(rpcAttributesGetter); + + InstrumenterBuilder serverInstrumenterBuilder = + Instrumenter.builder( + openTelemetry, INSTRUMENTATION_NAME, spanNameExtractor) + .addAttributesExtractor(RpcServerAttributesExtractor.create(rpcAttributesGetter)) + .addAttributesExtractors(attributesExtractors); + + InstrumenterBuilder clientInstrumenterBuilder = + Instrumenter.builder( + openTelemetry, INSTRUMENTATION_NAME, spanNameExtractor) + .addAttributesExtractor(RpcClientAttributesExtractor.create(rpcAttributesGetter)) + .addAttributesExtractors(attributesExtractors); + + if (peerService != null) { + clientInstrumenterBuilder.addAttributesExtractor( + AttributesExtractor.constant(SemanticAttributes.PEER_SERVICE, peerService)); + } + + return new ThriftTelemetry( + serverInstrumenterBuilder.buildServerInstrumenter(ThriftGetter.INSTANCE), + clientInstrumenterBuilder.buildClientInstrumenter(ThriftSetter.INSTANCE)); + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 5c5794f217dd..f71568191df7 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -152,6 +152,9 @@ hideFromDependabot(":instrumentation:apache-httpclient:apache-httpclient-4.3:tes hideFromDependabot(":instrumentation:apache-httpclient:apache-httpclient-5.0:javaagent") hideFromDependabot(":instrumentation:apache-pulsar:apache-pulsar-2.8:javaagent") hideFromDependabot(":instrumentation:apache-pulsar:apache-pulsar-2.8:javaagent-unit-tests") +hideFromDependabot(":instrumentation:apache-thrift:javaagent") +hideFromDependabot(":instrumentation:apache-thrift:library-autoconfigure") + hideFromDependabot(":instrumentation:armeria-1.3:javaagent") hideFromDependabot(":instrumentation:armeria-1.3:library") hideFromDependabot(":instrumentation:armeria-1.3:testing")