diff --git a/instrumentation/thrift/thrift-0.9.1/javaagent/build.gradle.kts b/instrumentation/thrift/thrift-0.9.1/javaagent/build.gradle.kts new file mode 100644 index 000000000000..a91cd7bb0d75 --- /dev/null +++ b/instrumentation/thrift/thrift-0.9.1/javaagent/build.gradle.kts @@ -0,0 +1,51 @@ +plugins { + id("otel.javaagent-instrumentation") +} + +muzzle { + pass { + group.set("org.apache.thrift") + module.set("libthrift") + versions.set("[0.9.1,)") + } +} +val thriftExecutable = "./src/test/resources/thrift" +val thriftInputFile = "$projectDir/src/test/resources/ThriftService.thrift" +val thriftOutputDir = "$projectDir/src/test/java" + +var generateThrift = tasks.register("generateThrift") { + group = "build" + description = "Generate Java code from Thrift IDL files" + commandLine(thriftExecutable, "--gen", "java", "-out", thriftOutputDir, thriftInputFile) +} + +tasks.named("compileTestJava") { + dependsOn(generateThrift) + + doFirst { + source.forEach { file -> + if (file.absolutePath.contains("$thriftOutputDir/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/thrift/ThriftService.java")) { + options.compilerArgs.add("-nowarn") + options.compilerArgs.add("-Xlint:-unchecked") + } + } + } +} + +tasks.named("checkstyleTest") { + exclude("**/thrift/ThriftService.java") +} + +spotless { + java { + targetExclude("**/thrift/ThriftService.java") + } +} + +dependencies { + compileOnly("org.apache.thrift:libthrift:0.9.1") + implementation(project(":instrumentation:thrift:thrift-common:library")) + + testImplementation("org.apache.thrift:libthrift:0.9.1") + testImplementation("javax.annotation:javax.annotation-api:1.3.2") +} diff --git a/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/AbstractProtocolWrapper.java b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/AbstractProtocolWrapper.java new file mode 100644 index 000000000000..478493322327 --- /dev/null +++ b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/AbstractProtocolWrapper.java @@ -0,0 +1,22 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1; + +import org.apache.thrift.protocol.TProtocol; +import org.apache.thrift.protocol.TProtocolDecorator; + +/** + * Note that the 8888th field of record is reserved for transporting trace header. Because Thrift + * doesn't support to transport metadata. + */ +public abstract class AbstractProtocolWrapper extends TProtocolDecorator { + public static final String OT_MAGIC_FIELD = "OT_MAGIC_FIELD"; + public static final short OT_MAGIC_FIELD_ID = 8888; + + public AbstractProtocolWrapper(TProtocol protocol) { + super(protocol); + } +} diff --git a/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/AsyncMethodCallbackWrapper.java b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/AsyncMethodCallbackWrapper.java new file mode 100644 index 000000000000..cac2a854b3bd --- /dev/null +++ b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/AsyncMethodCallbackWrapper.java @@ -0,0 +1,67 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1; + +import static io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.ThriftSingletons.clientInstrumenter; +import static io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.ThriftSingletons.serverInstrumenter; + +import io.opentelemetry.context.Context; +import io.opentelemetry.instrumentation.thrift.common.RequestScopeContext; +import io.opentelemetry.instrumentation.thrift.common.ThriftRequest; +import org.apache.thrift.async.AsyncMethodCallback; + +public final class AsyncMethodCallbackWrapper implements AsyncMethodCallback { + private final AsyncMethodCallback delegate; + private RequestScopeContext requestScopeContext; + private final boolean isServer; + + public AsyncMethodCallbackWrapper(AsyncMethodCallback methodCallback, boolean isServer) { + this.delegate = methodCallback; + this.isServer = isServer; + } + + public void setRequestScopeContext(RequestScopeContext requestScopeContext) { + this.requestScopeContext = requestScopeContext; + } + + @Override + public void onComplete(T t) { + try { + if (this.requestScopeContext == null) { + return; + } + this.requestScopeContext.close(); + Context context = this.requestScopeContext.getContext(); + ThriftRequest request = this.requestScopeContext.getRequest(); + if (isServer) { + serverInstrumenter().end(context, request, 0, null); + } else { + clientInstrumenter().end(context, request, 0, null); + } + } finally { + this.delegate.onComplete(t); + } + } + + @Override + public void onError(Exception e) { + try { + if (this.requestScopeContext == null) { + return; + } + this.requestScopeContext.close(); + Context context = this.requestScopeContext.getContext(); + ThriftRequest request = this.requestScopeContext.getRequest(); + if (isServer) { + serverInstrumenter().end(context, request, 1, e); + } else { + clientInstrumenter().end(context, request, 1, e); + } + } finally { + this.delegate.onError(e); + } + } +} diff --git a/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/ThriftSingletons.java b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/ThriftSingletons.java new file mode 100644 index 000000000000..c22dd1b56304 --- /dev/null +++ b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/ThriftSingletons.java @@ -0,0 +1,29 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1; + +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import io.opentelemetry.instrumentation.thrift.common.ThriftInstrumenterFactory; +import io.opentelemetry.instrumentation.thrift.common.ThriftRequest; + +public final class ThriftSingletons { + private static final String INSTRUMENTATION_NAME = "io.opentelemetry.thrift-0.9.1"; + + private static final Instrumenter CLIENT_INSTRUMENTER = + ThriftInstrumenterFactory.clientInstrumenter(INSTRUMENTATION_NAME); + private static final Instrumenter SERVER_INSTRUMENTER = + ThriftInstrumenterFactory.serverInstrumenter(INSTRUMENTATION_NAME); + + public static Instrumenter clientInstrumenter() { + return CLIENT_INSTRUMENTER; + } + + public static Instrumenter serverInstrumenter() { + return SERVER_INSTRUMENTER; + } + + private ThriftSingletons() {} +} diff --git a/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/client/ClientOutProtocolWrapper.java b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/client/ClientOutProtocolWrapper.java new file mode 100644 index 000000000000..71a73f6f6097 --- /dev/null +++ b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/client/ClientOutProtocolWrapper.java @@ -0,0 +1,143 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.client; + +import static io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.ThriftSingletons.clientInstrumenter; + +import io.opentelemetry.context.Context; +import io.opentelemetry.instrumentation.thrift.common.RequestScopeContext; +import io.opentelemetry.instrumentation.thrift.common.SocketAccessor; +import io.opentelemetry.instrumentation.thrift.common.ThriftRequest; +import io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge; +import io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.AbstractProtocolWrapper; +import java.net.Socket; +import java.util.HashMap; +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.TMessageType; +import org.apache.thrift.protocol.TProtocol; +import org.apache.thrift.protocol.TType; +import org.apache.thrift.transport.TTransport; + +@SuppressWarnings("all") +public final class ClientOutProtocolWrapper extends AbstractProtocolWrapper { + public static final String ONE_WAY_METHOD_NAME_PREFIX = "recv_"; + private volatile RequestScopeContext requestScopeContext; + public TTransport transport; + private boolean injected = true; + private String methodName; + private final Set voidMethodNames; + private String serviceName; + private byte type = -1; + private byte originType; + + public ClientOutProtocolWrapper( + TProtocol protocol, String serviceName, Set voidMethodNames) { + super(protocol); + this.serviceName = serviceName; + this.voidMethodNames = voidMethodNames; + } + + @Override + public void writeMessageBegin(TMessage message) throws TException { + this.injected = false; + this.methodName = message.name; + this.originType = message.type; + // Compatible with version 0.9.1 and 0.9.2 asynchronous logic + if (message.type == TMessageType.ONEWAY || this.type == -1) { + this.type = message.type; + } + if (!this.isOneway()) { + if (this.voidMethodNames != null + && this.voidMethodNames.contains(this.methodName) + && !this.voidMethodNames.contains(ONE_WAY_METHOD_NAME_PREFIX + this.methodName)) { + this.type = TMessageType.ONEWAY; + } + } + try { + if (this.requestScopeContext == null) { + Socket socket = SocketAccessor.getSocket(super.getTransport()); + if (socket == null) { + socket = SocketAccessor.getSocket(this.transport); + } + ThriftRequest request = + ThriftRequest.create(this.serviceName, this.methodName, socket, new HashMap<>()); + Context parentContext = Java8BytecodeBridge.currentContext(); + if (!clientInstrumenter().shouldStart(parentContext, request)) { + return; + } + Context context = clientInstrumenter().start(parentContext, request); + this.requestScopeContext = RequestScopeContext.create(request, null, context); + } + } finally { + if (this.isOneway() && message.type != TMessageType.ONEWAY) { + TMessage onewayMessage = new TMessage(message.name, TMessageType.ONEWAY, message.seqid); + super.writeMessageBegin(onewayMessage); + } else { + super.writeMessageBegin(message); + } + } + } + + @Override + public void writeFieldStop() throws TException { + try { + if (!this.injected && this.requestScopeContext != null) { + ThriftRequest request = this.requestScopeContext.getRequest(); + this.writeHeader(request.getHeader()); + } + } finally { + this.injected = true; + super.writeFieldStop(); + } + } + + public void writeHeader(Map header) throws TException { + super.writeFieldBegin(new TField(OT_MAGIC_FIELD, TType.MAP, OT_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()); + } + + super.writeMapEnd(); + super.writeFieldEnd(); + } + + public boolean isOneway() { + return this.type == TMessageType.ONEWAY; + } + + public boolean isChangeToOneway() { + return this.type != this.originType; + } + + public void updateTransport(TTransport transport) { + this.transport = transport; + } + + public RequestScopeContext getRequestScopeContext() { + return requestScopeContext; + } + + public void setRequestScopeContext(RequestScopeContext requestScopeContext) { + this.requestScopeContext = requestScopeContext; + } + + public void setServiceName(String serviceName) { + this.serviceName = serviceName; + } + + public void setType(byte type) { + this.type = type; + } +} diff --git a/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/client/ClientProtocolFactoryWrapper.java b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/client/ClientProtocolFactoryWrapper.java new file mode 100644 index 000000000000..0e869b5be690 --- /dev/null +++ b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/client/ClientProtocolFactoryWrapper.java @@ -0,0 +1,41 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.client; + +import org.apache.thrift.protocol.TProtocol; +import org.apache.thrift.protocol.TProtocolFactory; +import org.apache.thrift.transport.TTransport; + +@SuppressWarnings({"serial"}) +public final class ClientProtocolFactoryWrapper implements TProtocolFactory { + public TProtocolFactory delegate; + public TTransport transport; + public String serviceName; + + @Override + public TProtocol getProtocol(TTransport transport) { + TProtocol protocol = this.delegate.getProtocol(transport); + if (protocol instanceof ClientOutProtocolWrapper) { + if (transport != null) { + ((ClientOutProtocolWrapper) protocol).updateTransport(this.transport); + } + ((ClientOutProtocolWrapper) protocol).setServiceName(this.serviceName); + return protocol; + } + protocol = new ClientOutProtocolWrapper(protocol, this.serviceName, null); + if (transport != null) { + ((ClientOutProtocolWrapper) protocol).updateTransport(this.transport); + } + return protocol; + } + + public ClientProtocolFactoryWrapper( + TProtocolFactory protocolFactory, TTransport transport, String serviceName) { + this.delegate = protocolFactory; + this.transport = transport; + this.serviceName = serviceName; + } +} diff --git a/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/client/ThriftAsyncClientInstrumentation.java b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/client/ThriftAsyncClientInstrumentation.java new file mode 100644 index 000000000000..22cd63a452cc --- /dev/null +++ b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/client/ThriftAsyncClientInstrumentation.java @@ -0,0 +1,44 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.client; + +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.extendsClass; +import static net.bytebuddy.matcher.ElementMatchers.isConstructor; +import static net.bytebuddy.matcher.ElementMatchers.named; + +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.protocol.TProtocolFactory; +import org.apache.thrift.transport.TTransport; + +public final class ThriftAsyncClientInstrumentation implements TypeInstrumentation { + @Override + public ElementMatcher typeMatcher() { + return extendsClass(named("org.apache.thrift.async.TAsyncClient")); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + isConstructor(), ThriftAsyncClientInstrumentation.class.getName() + "$ConstructorAdvice"); + } + + public static class ConstructorAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter( + @Advice.Origin("#t") String serviceName, + @Advice.Argument(value = 0, readOnly = false) TProtocolFactory factory, + @Advice.Argument(value = 2) TTransport transport) { + if (factory instanceof ClientProtocolFactoryWrapper) { + return; + } + factory = new ClientProtocolFactoryWrapper(factory, transport, serviceName); + } + } +} diff --git a/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/client/ThriftAsyncMethodCallInstrumentation.java b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/client/ThriftAsyncMethodCallInstrumentation.java new file mode 100644 index 000000000000..9d189c9a02df --- /dev/null +++ b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/client/ThriftAsyncMethodCallInstrumentation.java @@ -0,0 +1,64 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.client; + +import static net.bytebuddy.matcher.ElementMatchers.isConstructor; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; + +import io.opentelemetry.instrumentation.api.util.VirtualField; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.AsyncMethodCallbackWrapper; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import org.apache.thrift.async.AsyncMethodCallback; +import org.apache.thrift.async.TAsyncMethodCall; + +public final class ThriftAsyncMethodCallInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return named("org.apache.thrift.async.TAsyncMethodCall"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + isConstructor().and(takesArgument(3, named("org.apache.thrift.async.AsyncMethodCallback"))), + ThriftAsyncMethodCallInstrumentation.class.getName() + "$ConstructorAdvice"); + + transformer.applyAdviceToMethod( + isMethod().and(named("prepareMethodCall")), + ThriftAsyncMethodCallInstrumentation.class.getName() + "$MethodCallAdvice"); + } + + public static class ConstructorAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter( + @Advice.Argument(value = 3, readOnly = false) AsyncMethodCallback callback) { + if (callback instanceof AsyncMethodCallbackWrapper) { + return; + } + callback = new AsyncMethodCallbackWrapper<>(callback, false); + } + } + + public static class MethodCallAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void methodEnter( + @Advice.This TAsyncMethodCall thiz, + @Advice.FieldValue(value = "callback") AsyncMethodCallback callback) { + if (callback instanceof AsyncMethodCallbackWrapper) { + VirtualField, AsyncMethodCallback> virtualField = + VirtualField.find(TAsyncMethodCall.class, AsyncMethodCallback.class); + virtualField.set(thiz, callback); + } + } + } +} diff --git a/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/client/ThriftAsyncWriteArgsInstrumentation.java b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/client/ThriftAsyncWriteArgsInstrumentation.java new file mode 100644 index 000000000000..895489f6a0ac --- /dev/null +++ b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/client/ThriftAsyncWriteArgsInstrumentation.java @@ -0,0 +1,87 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.client; + +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.extendsClass; +import static io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.ThriftSingletons.clientInstrumenter; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.named; + +import io.opentelemetry.context.Context; +import io.opentelemetry.instrumentation.api.util.VirtualField; +import io.opentelemetry.instrumentation.thrift.common.RequestScopeContext; +import io.opentelemetry.instrumentation.thrift.common.client.MethodAccessor; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.AsyncMethodCallbackWrapper; +import java.util.Set; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import org.apache.thrift.async.AsyncMethodCallback; +import org.apache.thrift.async.TAsyncMethodCall; +import org.apache.thrift.protocol.TMessageType; +import org.apache.thrift.protocol.TProtocol; + +public final class ThriftAsyncWriteArgsInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return extendsClass(named("org.apache.thrift.async.TAsyncMethodCall")); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + isMethod().and(named("write_args")), + ThriftAsyncWriteArgsInstrumentation.class.getName() + "$WriteArgsAdvice"); + } + + public static class WriteArgsAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void methodEnter( + @Advice.Origin("#t") String serviceName, @Advice.Argument(value = 0) TProtocol protocol) { + if (protocol instanceof ClientOutProtocolWrapper) { + Set methodNames = MethodAccessor.voidMethodNames(serviceName); + // Compatible with asynchronous oneway method + if (methodNames.contains("getResult")) { + ClientOutProtocolWrapper wrapper = (ClientOutProtocolWrapper) protocol; + wrapper.setType(TMessageType.ONEWAY); + } + } + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void methodExit( + @Advice.This TAsyncMethodCall methodCall, + @Advice.Argument(value = 0) TProtocol protocol, + @Advice.Thrown Throwable throwable) { + if (protocol instanceof ClientOutProtocolWrapper) { + ClientOutProtocolWrapper wrapper = (ClientOutProtocolWrapper) protocol; + RequestScopeContext requestScopeContext = wrapper.getRequestScopeContext(); + if (requestScopeContext == null) { + return; + } + // wrapper.isChangeToOneway() judgment logic is for compatibility with version 0.9.1 + // the return value is void but is not oneway method + if (throwable != null) { + requestScopeContext.close(); + Context context = requestScopeContext.getContext(); + clientInstrumenter().end(context, requestScopeContext.getRequest(), null, throwable); + wrapper.setRequestScopeContext(null); + return; + } + + VirtualField, AsyncMethodCallback> callbackVirtualField = + VirtualField.find(TAsyncMethodCall.class, AsyncMethodCallback.class); + AsyncMethodCallback callback = callbackVirtualField.get(methodCall); + if (callback instanceof AsyncMethodCallbackWrapper) { + ((AsyncMethodCallbackWrapper) callback).setRequestScopeContext(requestScopeContext); + } + } + } + } +} diff --git a/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/client/ThriftClientCommonInstrumentationModule.java b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/client/ThriftClientCommonInstrumentationModule.java new file mode 100644 index 000000000000..70055624500f --- /dev/null +++ b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/client/ThriftClientCommonInstrumentationModule.java @@ -0,0 +1,36 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.client; + +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; +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 java.util.List; +import net.bytebuddy.matcher.ElementMatcher; + +@AutoService(InstrumentationModule.class) +public final class ThriftClientCommonInstrumentationModule extends InstrumentationModule { + + public ThriftClientCommonInstrumentationModule() { + super("thrift", "thrift-0.9.1", "thrift-0.9.1-client"); + } + + @Override + public ElementMatcher.Junction classLoaderMatcher() { + return hasClassesNamed("org.apache.thrift.protocol.TProtocolDecorator"); + } + + @Override + public List typeInstrumentations() { + return asList( + new ThriftAsyncClientInstrumentation(), + new ThriftAsyncMethodCallInstrumentation(), + new ThriftAsyncWriteArgsInstrumentation()); + } +} diff --git a/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/client/ThriftClientInstrumentation.java b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/client/ThriftClientInstrumentation.java new file mode 100644 index 000000000000..d991f84ce16f --- /dev/null +++ b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/client/ThriftClientInstrumentation.java @@ -0,0 +1,128 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.client; + +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.extendsClass; +import static io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.ThriftSingletons.clientInstrumenter; +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; +import static net.bytebuddy.matcher.ElementMatchers.takesArguments; + +import io.opentelemetry.context.Context; +import io.opentelemetry.instrumentation.thrift.common.RequestScopeContext; +import io.opentelemetry.instrumentation.thrift.common.client.MethodAccessor; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import java.util.Set; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import org.apache.thrift.protocol.TProtocol; + +public final class ThriftClientInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return extendsClass(named("org.apache.thrift.TServiceClient")); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + isConstructor().and(takesArguments(1)), + ThriftClientInstrumentation.class.getName() + "$ConstructorOneAdvice"); + + transformer.applyAdviceToMethod( + isConstructor().and(takesArguments(2)), + ThriftClientInstrumentation.class.getName() + "$ConstructorTowAdvice"); + + transformer.applyAdviceToMethod( + isMethod().and(isProtected()).and(named("sendBase")), + ThriftClientInstrumentation.class.getName() + "$ClientSendAdvice"); + + transformer.applyAdviceToMethod( + isMethod().and(named("receiveBase")), + ThriftClientInstrumentation.class.getName() + "$ClientReceiveAdvice"); + } + + public static class ConstructorOneAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter( + @Advice.Origin("#t") String serviceName, + @Advice.Argument(value = 0, readOnly = false) TProtocol inProtocol) { + Set voidMethodNames = MethodAccessor.voidMethodNames(serviceName); + if (!(inProtocol instanceof ClientOutProtocolWrapper)) { + inProtocol = new ClientOutProtocolWrapper(inProtocol, serviceName, voidMethodNames); + } + } + } + + public static class ConstructorTowAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter( + @Advice.Origin("#t") String serviceName, + @Advice.Argument(value = 0, readOnly = false) TProtocol inProtocol, + @Advice.Argument(value = 1, readOnly = false) TProtocol outProtocol) { + Set voidMethodNames = MethodAccessor.voidMethodNames(serviceName); + if (!(inProtocol instanceof ClientOutProtocolWrapper)) { + inProtocol = new ClientOutProtocolWrapper(inProtocol, serviceName, voidMethodNames); + } + if (!(outProtocol instanceof ClientOutProtocolWrapper)) { + outProtocol = new ClientOutProtocolWrapper(outProtocol, serviceName, voidMethodNames); + } + } + } + + public static class ClientSendAdvice { + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void methodExit( + @Advice.FieldValue(value = "oprot_") TProtocol outProtocol, + @Advice.Thrown Throwable throwable) { + if (outProtocol != null && outProtocol instanceof ClientOutProtocolWrapper) { + ClientOutProtocolWrapper wrapper = (ClientOutProtocolWrapper) outProtocol; + RequestScopeContext requestScopeContext = wrapper.getRequestScopeContext(); + if (requestScopeContext == null) { + return; + } + + Context context = requestScopeContext.getContext(); + if (throwable != null) { + requestScopeContext.close(); + clientInstrumenter().end(context, requestScopeContext.getRequest(), null, throwable); + wrapper.setRequestScopeContext(null); + return; + } + + if (wrapper.isOneway()) { + requestScopeContext.close(); + clientInstrumenter().end(context, requestScopeContext.getRequest(), 0, null); + wrapper.setRequestScopeContext(null); + } + } + } + } + + public static class ClientReceiveAdvice { + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void methodExit( + @Advice.Thrown Throwable throwable, + @Advice.FieldValue(value = "oprot_") TProtocol outProtocol) { + if (outProtocol != null && outProtocol instanceof ClientOutProtocolWrapper) { + ClientOutProtocolWrapper wrapper = (ClientOutProtocolWrapper) outProtocol; + RequestScopeContext requestScopeContext = wrapper.getRequestScopeContext(); + if (requestScopeContext == null) { + return; + } + requestScopeContext.close(); + Context context = requestScopeContext.getContext(); + clientInstrumenter().end(context, requestScopeContext.getRequest(), null, throwable); + wrapper.setRequestScopeContext(null); + } + } + } +} diff --git a/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/client/ThriftClientInstrumentationModule.java b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/client/ThriftClientInstrumentationModule.java new file mode 100644 index 000000000000..18b786f31260 --- /dev/null +++ b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/client/ThriftClientInstrumentationModule.java @@ -0,0 +1,35 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.client; + +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; +import static java.util.Arrays.asList; +import static net.bytebuddy.matcher.ElementMatchers.not; + +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 net.bytebuddy.matcher.ElementMatcher; + +@AutoService(InstrumentationModule.class) +public final class ThriftClientInstrumentationModule extends InstrumentationModule { + + public ThriftClientInstrumentationModule() { + super("thrift", "thrift-0.9.1", "thrift-0.9.1-client"); + } + + @Override + public ElementMatcher.Junction classLoaderMatcher() { + return hasClassesNamed("org.apache.thrift.protocol.TProtocolDecorator") + .and(not(hasClassesNamed("org.apache.thrift.TAsyncProcessor"))); + } + + @Override + public List typeInstrumentations() { + return asList(new ThriftClientInstrumentation()); + } +} diff --git a/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/client/v3/ThriftClientInstrumentation.java b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/client/v3/ThriftClientInstrumentation.java new file mode 100644 index 000000000000..8687a5f55457 --- /dev/null +++ b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/client/v3/ThriftClientInstrumentation.java @@ -0,0 +1,129 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.client.v3; + +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.extendsClass; +import static io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.ThriftSingletons.clientInstrumenter; +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.named; +import static net.bytebuddy.matcher.ElementMatchers.takesArguments; + +import io.opentelemetry.context.Context; +import io.opentelemetry.instrumentation.thrift.common.RequestScopeContext; +import io.opentelemetry.instrumentation.thrift.common.client.MethodAccessor; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.client.ClientOutProtocolWrapper; +import java.util.Set; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import org.apache.thrift.protocol.TProtocol; + +public final class ThriftClientInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return extendsClass(named("org.apache.thrift.TServiceClient")); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + isConstructor().and(takesArguments(1)), + ThriftClientInstrumentation.class.getName() + "$ConstructorOneAdvice"); + + transformer.applyAdviceToMethod( + isConstructor().and(takesArguments(2)), + ThriftClientInstrumentation.class.getName() + "$ConstructorTowAdvice"); + + transformer.applyAdviceToMethod( + isMethod().and(isPrivate()).and(named("sendBase")), + ThriftClientInstrumentation.class.getName() + "$ClientSendAdvice"); + + transformer.applyAdviceToMethod( + isMethod().and(named("receiveBase")), + ThriftClientInstrumentation.class.getName() + "$ClientReceiveAdvice"); + } + + public static class ConstructorOneAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter( + @Advice.Origin("#t") String serviceName, + @Advice.Argument(value = 0, readOnly = false) TProtocol inProtocol) { + Set voidMethodNames = MethodAccessor.voidMethodNames(serviceName); + if (!(inProtocol instanceof ClientOutProtocolWrapper)) { + inProtocol = new ClientOutProtocolWrapper(inProtocol, serviceName, voidMethodNames); + } + } + } + + public static class ConstructorTowAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter( + @Advice.Origin("#t") String serviceName, + @Advice.Argument(value = 0, readOnly = false) TProtocol inProtocol, + @Advice.Argument(value = 1, readOnly = false) TProtocol outProtocol) { + Set voidMethodNames = MethodAccessor.voidMethodNames(serviceName); + if (!(inProtocol instanceof ClientOutProtocolWrapper)) { + inProtocol = new ClientOutProtocolWrapper(inProtocol, serviceName, voidMethodNames); + } + if (!(outProtocol instanceof ClientOutProtocolWrapper)) { + outProtocol = new ClientOutProtocolWrapper(outProtocol, serviceName, voidMethodNames); + } + } + } + + public static class ClientSendAdvice { + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void methodExit( + @Advice.FieldValue(value = "oprot_") TProtocol outProtocol, + @Advice.Thrown Throwable throwable) { + if (outProtocol != null && outProtocol instanceof ClientOutProtocolWrapper) { + ClientOutProtocolWrapper wrapper = (ClientOutProtocolWrapper) outProtocol; + RequestScopeContext requestScopeContext = wrapper.getRequestScopeContext(); + if (requestScopeContext == null) { + return; + } + + Context context = requestScopeContext.getContext(); + if (throwable != null) { + requestScopeContext.close(); + clientInstrumenter().end(context, requestScopeContext.getRequest(), null, throwable); + wrapper.setRequestScopeContext(null); + return; + } + + if (wrapper.isOneway()) { + requestScopeContext.close(); + clientInstrumenter().end(context, requestScopeContext.getRequest(), 0, null); + wrapper.setRequestScopeContext(null); + } + } + } + } + + public static class ClientReceiveAdvice { + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void methodExit( + @Advice.Thrown Throwable throwable, + @Advice.FieldValue(value = "oprot_") TProtocol outProtocol) { + if (outProtocol != null && outProtocol instanceof ClientOutProtocolWrapper) { + ClientOutProtocolWrapper wrapper = (ClientOutProtocolWrapper) outProtocol; + RequestScopeContext requestScopeContext = wrapper.getRequestScopeContext(); + if (requestScopeContext == null) { + return; + } + requestScopeContext.close(); + Context context = requestScopeContext.getContext(); + clientInstrumenter().end(context, requestScopeContext.getRequest(), null, throwable); + wrapper.setRequestScopeContext(null); + } + } + } +} diff --git a/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/client/v3/ThriftClientInstrumentationModule.java b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/client/v3/ThriftClientInstrumentationModule.java new file mode 100644 index 000000000000..34f86ab1354b --- /dev/null +++ b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/client/v3/ThriftClientInstrumentationModule.java @@ -0,0 +1,34 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.client.v3; + +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; +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 java.util.List; +import net.bytebuddy.matcher.ElementMatcher; + +@AutoService(InstrumentationModule.class) +public final class ThriftClientInstrumentationModule extends InstrumentationModule { + + public ThriftClientInstrumentationModule() { + super("thrift", "thrift-0.9.1", "thrift-0.9.3-client"); + } + + @Override + public ElementMatcher.Junction classLoaderMatcher() { + return hasClassesNamed("org.apache.thrift.protocol.TProtocolDecorator") + .and(hasClassesNamed("org.apache.thrift.TAsyncProcessor")); + } + + @Override + public List typeInstrumentations() { + return asList(new ThriftClientInstrumentation()); + } +} diff --git a/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ServerInProtocolWrapper.java b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ServerInProtocolWrapper.java new file mode 100644 index 000000000000..5fdfa9fb37a4 --- /dev/null +++ b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ServerInProtocolWrapper.java @@ -0,0 +1,133 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.server; + +import static io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.ThriftSingletons.serverInstrumenter; + +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.instrumentation.api.internal.Timer; +import io.opentelemetry.instrumentation.thrift.common.RequestScopeContext; +import io.opentelemetry.instrumentation.thrift.common.SocketAccessor; +import io.opentelemetry.instrumentation.thrift.common.ThriftRequest; +import io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge; +import io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.AbstractProtocolWrapper; +import java.net.Socket; +import java.util.HashMap; +import java.util.Map; +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.TMessageType; +import org.apache.thrift.protocol.TProtocol; +import org.apache.thrift.protocol.TType; +import org.apache.thrift.transport.TTransport; + +public final class ServerInProtocolWrapper extends AbstractProtocolWrapper { + + private volatile RequestScopeContext requestScopeContext; + private String methodName; + private String serviceName; + public TTransport transport; + private byte type; + private Timer timer; + + public ServerInProtocolWrapper(TProtocol protocol) { + super(protocol); + } + + @Override + public TMessage readMessageBegin() throws TException { + TMessage message = super.readMessageBegin(); + this.methodName = message.name; + this.type = message.type; + this.timer = Timer.start(); + return message; + } + + @Override + public TField readFieldBegin() throws TException { + TField field = super.readFieldBegin(); + if (field.id == OT_MAGIC_FIELD_ID && field.type == TType.MAP) { + try { + TMap map = super.readMapBegin(); + Map header = new HashMap<>(map.size); + + for (int i = 0; i < map.size; i++) { + header.put(readString(), readString()); + } + + Socket socket = SocketAccessor.getSocket(super.getTransport()); + if (socket == null) { + socket = SocketAccessor.getSocket(this.transport); + } + ThriftRequest request = + ThriftRequest.create(this.serviceName, this.methodName, socket, header); + Context parentContext = Java8BytecodeBridge.currentContext(); + if (!serverInstrumenter().shouldStart(parentContext, request)) { + return field; + } + Context context = serverInstrumenter().start(parentContext, request); + this.requestScopeContext = RequestScopeContext.create(request, null, context); + } finally { + super.readMapEnd(); + super.readFieldEnd(); + } + return this.readFieldBegin(); + } + return field; + } + + @Override + public void readMessageEnd() throws TException { + super.readMessageEnd(); + if (this.requestScopeContext == null) { + Socket socket = SocketAccessor.getSocket(super.getTransport()); + ThriftRequest request = + ThriftRequest.create(this.serviceName, this.methodName, socket, new HashMap<>()); + Context parentContext = Java8BytecodeBridge.currentContext(); + if (!serverInstrumenter().shouldStart(parentContext, request)) { + return; + } + Context context = serverInstrumenter().start(parentContext, request); + Scope scope = context.makeCurrent(); + this.requestScopeContext = RequestScopeContext.create(request, scope, context); + } + } + + public String getMethodName() { + return methodName; + } + + public boolean isOneway() { + return type == TMessageType.ONEWAY; + } + + public RequestScopeContext getRequestScopeContext() { + return requestScopeContext; + } + + public void setRequestScopeContext(RequestScopeContext requestScopeContext) { + this.requestScopeContext = requestScopeContext; + } + + public Timer getTimer() { + return timer; + } + + public String getServiceName() { + return serviceName; + } + + public void setServiceName(String serviceName) { + this.serviceName = serviceName; + } + + public void setTransport(TTransport transport) { + this.transport = transport; + } +} diff --git a/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ServerProtocolFactoryWrapper.java b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ServerProtocolFactoryWrapper.java new file mode 100644 index 000000000000..b860eea52397 --- /dev/null +++ b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ServerProtocolFactoryWrapper.java @@ -0,0 +1,28 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.server; + +import org.apache.thrift.protocol.TProtocol; +import org.apache.thrift.protocol.TProtocolFactory; +import org.apache.thrift.transport.TTransport; + +@SuppressWarnings({"serial"}) +public final class ServerProtocolFactoryWrapper implements TProtocolFactory { + public TProtocolFactory delegate; + + @Override + public TProtocol getProtocol(TTransport transport) { + TProtocol protocol = delegate.getProtocol(transport); + if (protocol instanceof ServerInProtocolWrapper) { + return protocol; + } + return new ServerInProtocolWrapper(protocol); + } + + public ServerProtocolFactoryWrapper(TProtocolFactory protocolFactory) { + this.delegate = protocolFactory; + } +} diff --git a/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ThriftAsyncProcessInstrumentation.java b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ThriftAsyncProcessInstrumentation.java new file mode 100644 index 000000000000..64717331f879 --- /dev/null +++ b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ThriftAsyncProcessInstrumentation.java @@ -0,0 +1,58 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.server; + +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.extendsClass; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.named; + +import io.opentelemetry.instrumentation.thrift.common.RequestScopeContext; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.AsyncMethodCallbackWrapper; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import org.apache.thrift.async.AsyncMethodCallback; +import org.apache.thrift.protocol.TProtocol; +import org.apache.thrift.server.AbstractNonblockingServer; + +public final class ThriftAsyncProcessInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return extendsClass(named("org.apache.thrift.AsyncProcessFunction")); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + isMethod().and(named("getResultHandler")), + ThriftAsyncProcessInstrumentation.class.getName() + "$GetResultHandlerAdvice"); + } + + public static class GetResultHandlerAdvice { + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void methodExit( + @Advice.Argument(value = 0) AbstractNonblockingServer.AsyncFrameBuffer fb, + @Advice.Return(readOnly = false) AsyncMethodCallback callback) { + TProtocol inProtocol = fb.getInputProtocol(); + if (inProtocol instanceof ServerInProtocolWrapper) { + ServerInProtocolWrapper wrapper = (ServerInProtocolWrapper) inProtocol; + RequestScopeContext requestScopeContext = wrapper.getRequestScopeContext(); + if (requestScopeContext == null) { + return; + } + + AsyncMethodCallbackWrapper callbackWrapper = + new AsyncMethodCallbackWrapper<>(callback, true); + callbackWrapper.setRequestScopeContext(requestScopeContext); + callback = callbackWrapper; + } + } + } +} diff --git a/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ThriftBaseAsyncProcessorInstrumentation.java b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ThriftBaseAsyncProcessorInstrumentation.java new file mode 100644 index 000000000000..52ec4f2de55a --- /dev/null +++ b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ThriftBaseAsyncProcessorInstrumentation.java @@ -0,0 +1,73 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.server; + +import static io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.ThriftSingletons.serverInstrumenter; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesArguments; + +import io.opentelemetry.context.Context; +import io.opentelemetry.instrumentation.thrift.common.RequestScopeContext; +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.protocol.TProtocol; +import org.apache.thrift.server.AbstractNonblockingServer; + +public final class ThriftBaseAsyncProcessorInstrumentation implements TypeInstrumentation { + @Override + public ElementMatcher typeMatcher() { + return named("org.apache.thrift.TBaseAsyncProcessor"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + isMethod().and(named("process")).and(takesArguments(1)), + ThriftBaseAsyncProcessorInstrumentation.class.getName() + "$ProcessAdvice"); + } + + public static class ProcessAdvice { + + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void methodEnter( + @Advice.Argument(0) AbstractNonblockingServer.AsyncFrameBuffer fb, + @Advice.FieldValue(value = "iface") Object iface) { + String serviceName = iface.getClass().getName(); + TProtocol inProtocol = fb.getInputProtocol(); + if (inProtocol instanceof ServerInProtocolWrapper) { + ServerInProtocolWrapper wrapper = (ServerInProtocolWrapper) inProtocol; + wrapper.setServiceName(serviceName); + } + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void methodExit( + @Advice.Argument(0) AbstractNonblockingServer.AsyncFrameBuffer fb, + @Advice.Thrown Throwable throwable) { + TProtocol inProtocol = fb.getInputProtocol(); + if (inProtocol instanceof ServerInProtocolWrapper) { + ServerInProtocolWrapper wrapper = (ServerInProtocolWrapper) inProtocol; + if (throwable == null && !wrapper.isOneway()) { + return; + } + + RequestScopeContext requestScopeContext = wrapper.getRequestScopeContext(); + if (requestScopeContext == null) { + return; + } + + requestScopeContext.close(); + Context context = requestScopeContext.getContext(); + serverInstrumenter().end(context, requestScopeContext.getRequest(), null, throwable); + wrapper.setRequestScopeContext(null); + } + } + } +} diff --git a/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ThriftBaseProcessorInstrumentation.java b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ThriftBaseProcessorInstrumentation.java new file mode 100644 index 000000000000..1c38bf51e084 --- /dev/null +++ b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ThriftBaseProcessorInstrumentation.java @@ -0,0 +1,83 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.server; + +import static io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.ThriftSingletons.serverInstrumenter; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.named; + +import io.opentelemetry.context.Context; +import io.opentelemetry.instrumentation.thrift.common.RequestScopeContext; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import java.lang.reflect.Field; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import org.apache.thrift.protocol.TProtocol; +import org.apache.thrift.protocol.TProtocolDecorator; + +public final class ThriftBaseProcessorInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return named("org.apache.thrift.TBaseProcessor"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + isMethod().and(named("process")), + ThriftBaseProcessorInstrumentation.class.getName() + "$ProcessAdvice"); + } + + public static class ProcessAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void methodEnter( + @Advice.Argument(value = 0) TProtocol inProtocol, + @Advice.FieldValue(value = "iface") Object iface) { + String serviceName = iface.getClass().getName(); + if (inProtocol instanceof ServerInProtocolWrapper) { + ServerInProtocolWrapper wrapper = (ServerInProtocolWrapper) inProtocol; + wrapper.setServiceName(serviceName); + } else if (inProtocol instanceof TProtocolDecorator) { + // TMultiplexedProcessor compatible + Field field = null; + try { + field = TProtocolDecorator.class.getDeclaredField("concreteProtocol"); + field.setAccessible(true); + Object obj = field.get(inProtocol); + if (obj != null && obj instanceof ServerInProtocolWrapper) { + ServerInProtocolWrapper wrapper = (ServerInProtocolWrapper) obj; + wrapper.setServiceName(serviceName); + } + } catch (Throwable ignored) { + // reflection error; in practice should never happen, we can ignore it + } + } + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void methodExit( + @Advice.Argument(value = 0) TProtocol inProtocol, @Advice.Thrown Throwable throwable) { + if (inProtocol instanceof ServerInProtocolWrapper) { + ServerInProtocolWrapper wrapper = (ServerInProtocolWrapper) inProtocol; + String methodName = wrapper.getMethodName(); + if (methodName == null || methodName.isEmpty()) { + return; + } + RequestScopeContext requestScopeContext = wrapper.getRequestScopeContext(); + if (requestScopeContext == null) { + return; + } + requestScopeContext.close(); + Context context = requestScopeContext.getContext(); + serverInstrumenter().end(context, requestScopeContext.getRequest(), null, throwable); + wrapper.setRequestScopeContext(null); + } + } + } +} diff --git a/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ThriftFrameBufferInstrumentation.java b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ThriftFrameBufferInstrumentation.java new file mode 100644 index 000000000000..07f495d9ba75 --- /dev/null +++ b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ThriftFrameBufferInstrumentation.java @@ -0,0 +1,45 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.server; + +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.named; + +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.protocol.TProtocol; +import org.apache.thrift.transport.TNonblockingTransport; + +public final class ThriftFrameBufferInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return named("org.apache.thrift.server.AbstractNonblockingServer$FrameBuffer") + .or(named("org.apache.thrift.server.AbstractNonblockingServer$AsyncFrameBuffer")); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + isMethod().and(named("invoke")), + ThriftFrameBufferInstrumentation.class.getName() + "$FrameBufferConstructorAdvice"); + } + + public static class FrameBufferConstructorAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void methodEnter( + @Advice.FieldValue(value = "inProt_", readOnly = false) TProtocol inProtocol, + @Advice.FieldValue(value = "trans_") TNonblockingTransport transport) { + if (inProtocol instanceof ServerInProtocolWrapper) { + ServerInProtocolWrapper wrapper = (ServerInProtocolWrapper) inProtocol; + wrapper.setTransport(transport); + } + } + } +} diff --git a/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ThriftMutiplexedProcessorInstrumentation.java b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ThriftMutiplexedProcessorInstrumentation.java new file mode 100644 index 000000000000..3667dbad0dca --- /dev/null +++ b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ThriftMutiplexedProcessorInstrumentation.java @@ -0,0 +1,84 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.server; + +import static io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.ThriftSingletons.serverInstrumenter; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.named; + +import io.opentelemetry.context.Context; +import io.opentelemetry.instrumentation.api.internal.InstrumenterUtil; +import io.opentelemetry.instrumentation.api.internal.Timer; +import io.opentelemetry.instrumentation.thrift.common.RequestScopeContext; +import io.opentelemetry.instrumentation.thrift.common.SocketAccessor; +import io.opentelemetry.instrumentation.thrift.common.ThriftRequest; +import io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import java.net.Socket; +import java.util.HashMap; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import org.apache.thrift.protocol.TProtocol; + +public final class ThriftMutiplexedProcessorInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return named("org.apache.thrift.TMultiplexedProcessor"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + isMethod().and(named("process")), + ThriftMutiplexedProcessorInstrumentation.class.getName() + "$ProcessAdvice"); + } + + public static class ProcessAdvice { + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void methodExit( + @Advice.Argument(value = 0) TProtocol inProtocol, @Advice.Thrown Throwable throwable) { + if (inProtocol instanceof ServerInProtocolWrapper) { + ServerInProtocolWrapper wrapper = (ServerInProtocolWrapper) inProtocol; + String methodName = wrapper.getMethodName(); + if (methodName == null || methodName.isEmpty()) { + return; + } + + RequestScopeContext requestScopeContext = wrapper.getRequestScopeContext(); + if (requestScopeContext == null) { + if (throwable != null) { + Timer timer = wrapper.getTimer(); + Socket socket = SocketAccessor.getSocket(wrapper.getTransport()); + ThriftRequest request = + ThriftRequest.create( + wrapper.getServiceName(), wrapper.getMethodName(), socket, new HashMap<>()); + Context parentContext = Java8BytecodeBridge.currentContext(); + if (serverInstrumenter().shouldStart(parentContext, request)) { + InstrumenterUtil.startAndEnd( + serverInstrumenter(), + parentContext, + request, + null, + throwable, + timer.startTime(), + timer.now()); + wrapper.setRequestScopeContext(null); + } + } + return; + } + + requestScopeContext.close(); + Context context = requestScopeContext.getContext(); + serverInstrumenter().end(context, requestScopeContext.getRequest(), null, throwable); + } + } + } +} diff --git a/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ThriftServerInstrumentation.java b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ThriftServerInstrumentation.java new file mode 100644 index 000000000000..fd8f14ebf118 --- /dev/null +++ b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ThriftServerInstrumentation.java @@ -0,0 +1,44 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.server; + +import static net.bytebuddy.matcher.ElementMatchers.isConstructor; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesArguments; + +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.protocol.TProtocolFactory; + +public final class ThriftServerInstrumentation implements TypeInstrumentation { + @Override + public ElementMatcher typeMatcher() { + return named("org.apache.thrift.server.TServer"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + isConstructor().and(takesArguments(1)), + ThriftServerInstrumentation.class.getName() + "$ServerConstructorAdvice"); + } + + public static class ServerConstructorAdvice { + + @Advice.OnMethodExit(suppress = Throwable.class) + public static void onExit( + @Advice.FieldValue(value = "inputProtocolFactory_", readOnly = false) + TProtocolFactory factory) { + if (factory instanceof ServerProtocolFactoryWrapper) { + return; + } + factory = new ServerProtocolFactoryWrapper(factory); + } + } +} diff --git a/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ThriftServerInstrumentationModule.java b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ThriftServerInstrumentationModule.java new file mode 100644 index 000000000000..c5fc96c892a7 --- /dev/null +++ b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ThriftServerInstrumentationModule.java @@ -0,0 +1,40 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.server; + +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; +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 java.util.List; +import net.bytebuddy.matcher.ElementMatcher; + +@AutoService(InstrumentationModule.class) +public final class ThriftServerInstrumentationModule extends InstrumentationModule { + + public ThriftServerInstrumentationModule() { + super("thrift", "thrift-0.9.1", "thrift-0.9.1-server"); + } + + @Override + public ElementMatcher.Junction classLoaderMatcher() { + return hasClassesNamed("org.apache.thrift.protocol.TProtocolDecorator"); + } + + @Override + public List typeInstrumentations() { + return asList( + new ThriftServerInstrumentation(), + new ThriftServletInstrumentation(), + new ThriftAsyncProcessInstrumentation(), + new ThriftFrameBufferInstrumentation(), + new ThriftBaseProcessorInstrumentation(), + new ThriftMutiplexedProcessorInstrumentation(), + new ThriftBaseAsyncProcessorInstrumentation()); + } +} diff --git a/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ThriftServletInstrumentation.java b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ThriftServletInstrumentation.java new file mode 100644 index 000000000000..126235073983 --- /dev/null +++ b/instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ThriftServletInstrumentation.java @@ -0,0 +1,43 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.server; + +import static net.bytebuddy.matcher.ElementMatchers.isConstructor; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesArguments; + +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.protocol.TProtocolFactory; + +public final class ThriftServletInstrumentation implements TypeInstrumentation { + @Override + public ElementMatcher typeMatcher() { + return named("org.apache.thrift.server.TServlet"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + isConstructor().and(takesArguments(1)), + ThriftServletInstrumentation.class.getName() + "$ServerConstructorAdvice"); + } + + public static class ServerConstructorAdvice { + + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter( + @Advice.Argument(value = 1, readOnly = false) TProtocolFactory factory) { + if (factory instanceof ServerProtocolFactoryWrapper) { + return; + } + factory = new ServerProtocolFactoryWrapper(factory); + } + } +} diff --git a/instrumentation/thrift/thrift-0.9.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/NoReturnTest.java b/instrumentation/thrift/thrift-0.9.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/NoReturnTest.java new file mode 100644 index 000000000000..66c0e3de239e --- /dev/null +++ b/instrumentation/thrift/thrift-0.9.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/NoReturnTest.java @@ -0,0 +1,1051 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.thrift.ThriftService; +import java.io.IOException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import org.apache.thrift.TException; +import org.apache.thrift.async.AsyncMethodCallback; +import org.apache.thrift.async.TAsyncClientManager; +import org.apache.thrift.protocol.TBinaryProtocol; +import org.apache.thrift.protocol.TMultiplexedProtocol; +import org.apache.thrift.protocol.TProtocol; +import org.apache.thrift.protocol.TProtocolFactory; +import org.apache.thrift.transport.TFastFramedTransport; +import org.apache.thrift.transport.TFramedTransport; +import org.apache.thrift.transport.TNonblockingSocket; +import org.apache.thrift.transport.TNonblockingTransport; +import org.apache.thrift.transport.TSocket; +import org.apache.thrift.transport.TTransport; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + +public class NoReturnTest extends ThriftBaseTest { + + @Test + public void syncClientSyncSimpleServerNoReturn() throws TException { + int port = super.getPort(); + this.startSyncSimpleServer(port); + this.syncClientNoReturn(port); + this.waitAndAssertTracesClientSyncServerSync(port, "noReturn", 1); + } + + @Test + public void syncClientSyncSimpleServerNoReturnMuti() throws TException { + int port = super.getPort(); + this.startSyncSimpleServer(port); + for (int i = 0; i < 5; ++i) { + this.syncClientNoReturn(port); + } + this.waitAndAssertTracesClientSyncServerSync(port, "noReturn", 5); + } + + @Test + public void syncClientSyncSimpleServerNoReturnParallel() throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncSimpleServer(port); + AtomicInteger count = new AtomicInteger(0); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncClientNoReturn(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncClientSimpleServerNoReturnParallel field: " + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + latch.await(); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerSync(port, "noReturn", threadCount); + } + + @Test + public void syncClientSyncThreadPoolServerNoReturn() throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncThreadPoolServer(port); + this.syncClientNoReturn(port); + this.waitAndAssertTracesClientSyncServerSync(port, "noReturn", 1); + } + + @Test + public void syncClientSyncThreadPoolServerNoReturnMuti() throws TException { + int port = super.getPort(); + this.startSyncThreadPoolServer(port); + for (int i = 0; i < 5; ++i) { + this.syncClientNoReturn(port); + } + this.waitAndAssertTracesClientSyncServerSync(port, "noReturn", 5); + } + + @Test + public void syncClientSyncThreadPoolServerNoReturnParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncThreadPoolServer(port); + AtomicInteger count = new AtomicInteger(0); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncClientNoReturn(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncClientSimpleServerNoReturnParallel field: " + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + latch.await(); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerSync(port, "noReturn", threadCount); + } + + @Test + public void syncClientMutiSyncSimpleServerNoReturn() throws TException { + int port = super.getPort(); + this.startMultiSimpleServer(port); + this.syncClientMultiNoReturn(port); + this.waitAndAssertTracesClientSyncServerSync(port, "noReturn", "syncHelloWorld:noReturn", 1); + } + + @Test + public void syncClientMutiSyncSimpleServerNoReturnMuti() throws TException { + int port = super.getPort(); + this.startMultiSimpleServer(port); + for (int i = 0; i < 5; ++i) { + this.syncClientMultiNoReturn(port); + } + this.waitAndAssertTracesClientSyncServerSync(port, "noReturn", "syncHelloWorld:noReturn", 5); + } + + @Test + public void syncClientMutiSyncSimpleServerNoReturnParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startMultiSimpleServer(port); + AtomicInteger count = new AtomicInteger(0); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncClientMultiNoReturn(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncClientSimpleServerNoReturnParallel field: " + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + latch.await(); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerSync( + port, "noReturn", "syncHelloWorld:noReturn", threadCount); + } + + @Test + public void syncFramedClientAsyncThreadedSelectorServerNoReturn() throws TException { + int port = super.getPort(); + this.startAsyncThreadedSelectorServer(port); + this.syncFramedClientNoReturn(port); + this.waitAndAssertTracesClientSyncServerAsync(port, "noReturn", 1); + } + + @Test + public void syncFastFramedClientAsyncThreadedSelectorServerNoReturn() throws TException { + int port = super.getPort(); + this.startAsyncThreadedSelectorServer(port); + this.syncFastFramedClientNoReturn(port); + this.waitAndAssertTracesClientSyncServerAsync(port, "noReturn", 1); + } + + @Test + public void syncFramedClientAsyncThreadedSelectorFastServerNoReturn() throws TException { + int port = super.getPort(); + this.startAsyncThreadedSelectorFastServer(port); + this.syncFramedClientNoReturn(port); + this.waitAndAssertTracesClientSyncServerAsync(port, "noReturn", 1); + } + + @Test + public void syncFastFramedClientAsyncThreadedSelectorFastServerNoReturn() throws TException { + int port = super.getPort(); + this.startAsyncThreadedSelectorFastServer(port); + this.syncFastFramedClientNoReturn(port); + this.waitAndAssertTracesClientSyncServerAsync(port, "noReturn", 1); + } + + @Test + public void syncFramedClientAsyncThreadedSelectorServerNoReturnMuti() throws TException { + int port = super.getPort(); + this.startAsyncThreadedSelectorServer(port); + + for (int i = 0; i < 5; ++i) { + this.syncFramedClientNoReturn(port); + } + + this.waitAndAssertTracesClientSyncServerAsync(port, "noReturn", 5); + } + + @Test + public void syncFramedClientAsyncThreadedSelectorServerNoReturnParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startAsyncThreadedSelectorServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncFramedClientNoReturn(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncFramedClientAsyncThreadedSelectorServerNoReturnParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerAsync(port, "noReturn", threadCount); + } + + @Test + public void syncFramedClientAsyncMutiThreadedSelectorServerNoReturn() throws TException { + int port = super.getPort(); + this.startMultiThreadedSelectorServer(port); + this.syncFramedClientMultiNoReturn(port); + this.waitAndAssertTracesClientSyncServerSync(port, "noReturn", "syncHelloWorld:noReturn", 1); + } + + @Test + public void syncFramedClientAsyncMutiThreadedSelectorServerNoReturnMuti() throws TException { + int port = super.getPort(); + this.startMultiThreadedSelectorServer(port); + for (int i = 0; i < 5; ++i) { + this.syncFramedClientMultiNoReturn(port); + } + this.waitAndAssertTracesClientSyncServerSync(port, "noReturn", "syncHelloWorld:noReturn", 5); + } + + @Test + public void syncFramedClientAsyncMutiThreadedSelectorServerNoReturnParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startMultiThreadedSelectorServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncFramedClientMultiNoReturn(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncFramedClientAsyncThreadedSelectorServerNoReturnParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerSync( + port, "noReturn", "syncHelloWorld:noReturn", threadCount); + } + + @Test + public void syncFramedClientSyncThreadedSelectorServerNoReturn() throws TException { + int port = super.getPort(); + this.startSyncThreadedSelectorServer(port); + this.syncFramedClientNoReturn(port); + this.waitAndAssertTracesClientSyncServerSync(port, "noReturn", 1); + } + + @Test + public void syncFastFramedClientSyncThreadedSelectorServerNoReturn() throws TException { + int port = super.getPort(); + this.startSyncThreadedSelectorServer(port); + this.syncFastFramedClientNoReturn(port); + this.waitAndAssertTracesClientSyncServerSync(port, "noReturn", 1); + } + + @Test + public void syncFramedClientSyncThreadedSelectorFastServerNoReturn() throws TException { + int port = super.getPort(); + this.startSyncThreadedSelectorFastServer(port); + this.syncFramedClientNoReturn(port); + this.waitAndAssertTracesClientSyncServerSync(port, "noReturn", 1); + } + + @Test + public void syncFastFramedClientSyncThreadedSelectorFastServerNoReturn() throws TException { + int port = super.getPort(); + this.startSyncThreadedSelectorFastServer(port); + this.syncFastFramedClientNoReturn(port); + this.waitAndAssertTracesClientSyncServerSync(port, "noReturn", 1); + } + + @Test + public void syncFramedClientSyncThreadedSelectorServerNoReturnMuti() throws TException { + int port = super.getPort(); + this.startSyncThreadedSelectorServer(port); + for (int i = 0; i < 5; ++i) { + this.syncFramedClientNoReturn(port); + } + this.waitAndAssertTracesClientSyncServerSync(port, "noReturn", 5); + } + + @Test + public void syncFramedClientSyncThreadedSelectorServerNoReturnParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncThreadedSelectorServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncFramedClientNoReturn(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncFramedClientSyncThreadedSelectorServerNoReturnParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerSync(port, "noReturn", threadCount); + } + + @Test + public void nonBlockClientAsyncThreadedSelectorServerNoReturn() throws TException, IOException { + int port = super.getPort(); + this.startAsyncThreadedSelectorServer(port); + this.nonBlockClientNoReturn(port); + this.waitAndAssertTracesClientAsyncServerAsync(port, "noReturn", 1); + } + + @Test + public void nonBlockClientAsyncThreadedSelectorServerNoReturnMuti() + throws TException, IOException { + int port = super.getPort(); + this.startAsyncThreadedSelectorServer(port); + for (int i = 0; i < 5; ++i) { + this.nonBlockClientNoReturn(port); + } + this.waitAndAssertTracesClientAsyncServerAsync(port, "noReturn", 5); + } + + @Test + public void nonBlockClientAsyncThreadedSelectorServerNoReturnParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startAsyncThreadedSelectorServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.nonBlockClientNoReturn(port); + } catch (IOException | TException e) { + count.incrementAndGet(); + Assertions.fail( + "nonBlockClientAsyncThreadedSelectorServerNoReturnParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientAsyncServerAsync(port, "noReturn", threadCount); + } + + @Test + public void nonBlockClientSyncThreadedSelectorServerNoReturn() throws TException, IOException { + int port = super.getPort(); + this.startSyncThreadedSelectorServer(port); + this.nonBlockClientNoReturn(port); + this.waitAndAssertTracesClientAsyncServerSync(port, "noReturn", 1); + } + + @Test + public void nonBlockClientSyncThreadedSelectorServerNoReturnMuti() + throws TException, IOException { + int port = super.getPort(); + this.startSyncThreadedSelectorServer(port); + for (int i = 0; i < 5; ++i) { + this.nonBlockClientNoReturn(port); + } + this.waitAndAssertTracesClientAsyncServerSync(port, "noReturn", 5); + } + + @Test + public void nonBlockClientSyncThreadedSelectorServerNoReturnParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncThreadedSelectorServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.nonBlockClientNoReturn(port); + } catch (IOException | TException e) { + count.incrementAndGet(); + Assertions.fail( + "nonBlockClientSyncThreadedSelectorServerNoReturnParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientAsyncServerSync(port, "noReturn", threadCount); + } + + @Test + public void syncFramedClientSyncNonblockingServerNoReturn() throws TException { + int port = super.getPort(); + this.startSyncNonblockingServer(port); + this.syncFramedClientNoReturn(port); + this.waitAndAssertTracesClientSyncServerSync(port, "noReturn", 1); + } + + @Test + public void syncFastFramedClientSyncNonblockingServerNoReturn() throws TException { + int port = super.getPort(); + this.startSyncNonblockingServer(port); + this.syncFastFramedClientNoReturn(port); + this.waitAndAssertTracesClientSyncServerSync(port, "noReturn", 1); + } + + @Test + public void syncFramedClientSyncNonblockingFastServerNoReturn() throws TException { + int port = super.getPort(); + this.startSyncNonblockingFastServer(port); + this.syncFramedClientNoReturn(port); + this.waitAndAssertTracesClientSyncServerSync(port, "noReturn", 1); + } + + @Test + public void syncFastFramedClientSyncNonblockingFastServerNoReturn() throws TException { + int port = super.getPort(); + this.startSyncNonblockingFastServer(port); + this.syncFastFramedClientNoReturn(port); + this.waitAndAssertTracesClientSyncServerSync(port, "noReturn", 1); + } + + @Test + public void syncFramedClientSyncNonblockingServerNoReturnMuti() throws TException { + int port = super.getPort(); + this.startSyncNonblockingServer(port); + for (int i = 0; i < 5; ++i) { + this.syncFramedClientNoReturn(port); + } + this.waitAndAssertTracesClientSyncServerSync(port, "noReturn", 5); + } + + @Test + public void syncFramedClientSyncNonblockingServerNoReturnParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncNonblockingServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncFramedClientNoReturn(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncFramedClientSyncNonblockingServerNoReturnParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerSync(port, "noReturn", threadCount); + } + + @Test + public void syncFramedClientSyncHsHaServerNoReturn() throws TException { + int port = super.getPort(); + this.startSyncHsHaServer(port); + this.syncFramedClientNoReturn(port); + this.waitAndAssertTracesClientSyncServerSync(port, "noReturn", 1); + } + + @Test + public void syncFastFramedClientSyncHsHaServerNoReturn() throws TException { + int port = super.getPort(); + this.startSyncHsHaServer(port); + this.syncFastFramedClientNoReturn(port); + this.waitAndAssertTracesClientSyncServerSync(port, "noReturn", 1); + } + + @Test + public void syncFramedClientSyncHsHaFastServerNoReturn() throws TException { + int port = super.getPort(); + this.startSyncHsHaFastServer(port); + this.syncFramedClientNoReturn(port); + this.waitAndAssertTracesClientSyncServerSync(port, "noReturn", 1); + } + + @Test + public void syncFastFramedClientSyncHsHaFastServerNoReturn() throws TException { + int port = super.getPort(); + this.startSyncHsHaFastServer(port); + this.syncFastFramedClientNoReturn(port); + this.waitAndAssertTracesClientSyncServerSync(port, "noReturn", 1); + } + + @Test + public void syncFramedClientSyncHsHaServerNoReturnMuti() throws TException { + int port = super.getPort(); + this.startSyncHsHaServer(port); + + for (int i = 0; i < 5; ++i) { + this.syncFramedClientNoReturn(port); + } + + this.waitAndAssertTracesClientSyncServerSync(port, "noReturn", 5); + } + + @Test + public void syncFramedClientSyncHsHaServerNoReturnParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncHsHaServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncFramedClientNoReturn(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncFramedClientSyncHsHaServerNoReturnParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerSync(port, "noReturn", threadCount); + } + + @Test + public void syncFramedClientAsyncNonblockingServerNoReturn() throws TException { + int port = super.getPort(); + this.startAsyncNonblockingServer(port); + this.syncFramedClientNoReturn(port); + this.waitAndAssertTracesClientSyncServerAsync(port, "noReturn", 1); + } + + @Test + public void syncFastFramedClientAsyncNonblockingServerNoReturn() throws TException { + int port = super.getPort(); + this.startAsyncNonblockingServer(port); + this.syncFastFramedClientNoReturn(port); + this.waitAndAssertTracesClientSyncServerAsync(port, "noReturn", 1); + } + + @Test + public void syncFramedClientAsyncNonblockingServerNoReturnMuti() throws TException { + int port = super.getPort(); + this.startAsyncNonblockingServer(port); + + for (int i = 0; i < 5; ++i) { + this.syncFramedClientNoReturn(port); + } + + this.waitAndAssertTracesClientSyncServerAsync(port, "noReturn", 5); + } + + @Test + public void syncFramedClientAsyncNonblockingServerNoReturnParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startAsyncNonblockingServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncFramedClientNoReturn(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncFramedClientAsyncNonblockingServerNoReturnParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerAsync(port, "noReturn", threadCount); + } + + @Test + public void syncFramedClientAsyncHsHaServerNoReturn() throws TException { + int port = super.getPort(); + this.startAsyncHsHaServer(port); + this.syncFramedClientNoReturn(port); + this.waitAndAssertTracesClientSyncServerAsync(port, "noReturn", 1); + } + + @Test + public void syncFastFramedClientAsyncHsHaServerNoReturn() throws TException { + int port = super.getPort(); + this.startAsyncHsHaServer(port); + this.syncFastFramedClientNoReturn(port); + this.waitAndAssertTracesClientSyncServerAsync(port, "noReturn", 1); + } + + @Test + public void syncFramedClientAsyncHsHaFastServerNoReturn() throws TException { + int port = super.getPort(); + this.startAsyncHsHaFastServer(port); + this.syncFramedClientNoReturn(port); + this.waitAndAssertTracesClientSyncServerAsync(port, "noReturn", 1); + } + + @Test + public void syncFastFramedClientAsyncHsHaFastServerNoReturn() throws TException { + int port = super.getPort(); + this.startAsyncHsHaFastServer(port); + this.syncFastFramedClientNoReturn(port); + this.waitAndAssertTracesClientSyncServerAsync(port, "noReturn", 1); + } + + @Test + public void syncFramedClientAsyncHsHaServerNoReturnMuti() throws TException { + int port = super.getPort(); + this.startAsyncHsHaServer(port); + + for (int i = 0; i < 5; ++i) { + this.syncFramedClientNoReturn(port); + } + + this.waitAndAssertTracesClientSyncServerAsync(port, "noReturn", 5); + } + + @Test + public void syncFramedClientAsyncHsHaServerNoReturnParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startAsyncHsHaServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncFramedClientNoReturn(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncFramedClientAsyncHsHaServerNoReturnParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerAsync(port, "noReturn", threadCount); + } + + @Test + public void nonBlockClientSyncNonblockingServerNoReturn() throws TException, IOException { + int port = super.getPort(); + this.startSyncNonblockingServer(port); + this.nonBlockClientNoReturn(port); + this.waitAndAssertTracesClientAsyncServerSync(port, "noReturn", 1); + } + + @Test + public void nonBlockClientSyncNonblockingServerNoReturnMuti() throws TException, IOException { + int port = super.getPort(); + this.startSyncNonblockingServer(port); + + for (int i = 0; i < 5; ++i) { + this.nonBlockClientNoReturn(port); + } + + this.waitAndAssertTracesClientAsyncServerSync(port, "noReturn", 5); + } + + @Test + public void nonBlockClientSyncNonblockingServerNoReturnParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncNonblockingServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.nonBlockClientNoReturn(port); + } catch (IOException | TException e) { + count.incrementAndGet(); + Assertions.fail( + "nonBlockClientSyncNonblockingServerNoReturnParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientAsyncServerSync(port, "noReturn", threadCount); + } + + @Test + public void nonBlockClientSyncHsHaServerNoReturn() throws TException, IOException { + int port = super.getPort(); + this.startSyncHsHaServer(port); + this.nonBlockClientNoReturn(port); + this.waitAndAssertTracesClientAsyncServerSync(port, "noReturn", 1); + } + + @Test + public void nonBlockClientSyncHsHaServerNoReturnMuti() throws TException, IOException { + int port = super.getPort(); + this.startSyncHsHaServer(port); + + for (int i = 0; i < 5; ++i) { + this.nonBlockClientNoReturn(port); + } + + this.waitAndAssertTracesClientAsyncServerSync(port, "noReturn", 5); + } + + @Test + public void nonBlockClientSyncHsHaServerNoReturnParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncHsHaServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.nonBlockClientNoReturn(port); + } catch (IOException | TException e) { + count.incrementAndGet(); + Assertions.fail( + "nonBlockClientSyncHsHaServerNoReturnParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientAsyncServerSync(port, "noReturn", threadCount); + } + + @Test + public void nonBlockClientAsyncNonblockingServerNoReturn() throws TException, IOException { + int port = super.getPort(); + this.startAsyncNonblockingServer(port); + this.nonBlockClientNoReturn(port); + this.waitAndAssertTracesClientAsyncServerAsync(port, "noReturn", 1); + } + + @Test + public void nonBlockClientAsyncNonblockingServerNoReturnMuti() throws TException, IOException { + int port = super.getPort(); + this.startAsyncNonblockingServer(port); + + for (int i = 0; i < 5; ++i) { + this.nonBlockClientNoReturn(port); + } + + this.waitAndAssertTracesClientAsyncServerAsync(port, "noReturn", 5); + } + + @Test + public void nonBlockClientAsyncNonblockingServerNoReturnParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startAsyncNonblockingServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.nonBlockClientNoReturn(port); + } catch (IOException | TException e) { + count.incrementAndGet(); + Assertions.fail( + "nonBlockClientAsyncNonblockingServerNoReturnParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientAsyncServerAsync(port, "noReturn", threadCount); + } + + @Test + public void nonBlockClientAsyncHsHaServerNoReturn() throws TException, IOException { + int port = super.getPort(); + this.startAsyncHsHaServer(port); + this.nonBlockClientNoReturn(port); + this.waitAndAssertTracesClientAsyncServerAsync(port, "noReturn", 1); + } + + @Test + public void nonBlockClientAsyncHsHaServerNoReturnMuti() throws TException, IOException { + int port = super.getPort(); + this.startAsyncHsHaServer(port); + + for (int i = 0; i < 5; ++i) { + this.nonBlockClientNoReturn(port); + } + + this.waitAndAssertTracesClientAsyncServerAsync(port, "noReturn", 5); + } + + @Test + public void nonBlockClientAsyncHsHaServerNoReturnParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startAsyncHsHaServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.nonBlockClientNoReturn(port); + } catch (IOException | TException e) { + count.incrementAndGet(); + Assertions.fail( + "nonBlockClientAsyncHsHaServerNoReturnParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientAsyncServerAsync(port, "noReturn", threadCount); + } + + public void syncClientNoReturn(int port) throws TException { + TTransport transport = null; + try { + transport = new TSocket("localhost", port); + transport.open(); + TProtocol protocol = new TBinaryProtocol(transport); + ThriftService.Client client = new ThriftService.Client(protocol); + this.testing().runWithSpan("parent", () -> client.noReturn(1)); + } finally { + if (transport != null) { + transport.close(); + } + } + } + + public void syncClientMultiNoReturn(int port) throws TException { + TTransport transport = null; + try { + transport = new TSocket("localhost", port); + transport.open(); + TProtocol protocol = new TBinaryProtocol(transport); + TMultiplexedProtocol multiplexedProtocol = + new TMultiplexedProtocol(protocol, "syncHelloWorld"); + ThriftService.Client client = new ThriftService.Client(multiplexedProtocol); + this.testing().runWithSpan("parent", () -> client.noReturn(1)); + } finally { + if (transport != null) { + transport.close(); + } + } + } + + public void nonBlockClientNoReturn(int port) throws TException, IOException { + TNonblockingTransport transport = new TNonblockingSocket("localhost", port); + TAsyncClientManager clientManager = new TAsyncClientManager(); + TProtocolFactory protocolFactory = new TBinaryProtocol.Factory(); + ThriftService.AsyncClient.Factory factory = + new ThriftService.AsyncClient.Factory(clientManager, protocolFactory); + ThriftService.AsyncClient asyClient = factory.getAsyncClient(transport); + AsyncMethodCallback callback = + new AsyncMethodCallback() { + @Override + public void onComplete(ThriftService.AsyncClient.noReturn_call s) {} + + @Override + public void onError(Exception e) { + assertThat(e.getMessage()).isEqualTo("Read call frame size failed"); + } + }; + this.testing().runWithSpan("parent", () -> asyClient.noReturn(1, callback)); + } + + public void syncFramedClientNoReturn(int port) throws TException { + TTransport transport = null; + try { + transport = new TSocket("localhost", port); + TFramedTransport framedTransport = new TFramedTransport(transport); + framedTransport.open(); + TProtocol protocol = new TBinaryProtocol(framedTransport); + ThriftService.Client client = new ThriftService.Client(protocol); + this.testing().runWithSpan("parent", () -> client.noReturn(1)); + } finally { + if (transport != null) { + transport.close(); + } + } + } + + public void syncFastFramedClientNoReturn(int port) throws TException { + TTransport transport = null; + try { + transport = new TSocket("localhost", port); + TFastFramedTransport framedTransport = new TFastFramedTransport(transport); + framedTransport.open(); + TProtocol protocol = new TBinaryProtocol(framedTransport); + ThriftService.Client client = new ThriftService.Client(protocol); + this.testing().runWithSpan("parent", () -> client.noReturn(1)); + } finally { + if (transport != null) { + transport.close(); + } + } + } + + public void syncFramedClientMultiNoReturn(int port) throws TException { + TTransport transport = null; + try { + transport = new TSocket("localhost", port); + TFramedTransport framedTransport = new TFramedTransport(transport); + framedTransport.open(); + TProtocol protocol = new TBinaryProtocol(framedTransport); + TMultiplexedProtocol multiplexedProtocol = + new TMultiplexedProtocol(protocol, "syncHelloWorld"); + ThriftService.Client client = new ThriftService.Client(multiplexedProtocol); + this.testing().runWithSpan("parent", () -> client.noReturn(1)); + } finally { + if (transport != null) { + transport.close(); + } + } + } +} diff --git a/instrumentation/thrift/thrift-0.9.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/OneWayErrorTest.java b/instrumentation/thrift/thrift-0.9.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/OneWayErrorTest.java new file mode 100644 index 000000000000..a29bcca11157 --- /dev/null +++ b/instrumentation/thrift/thrift-0.9.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/OneWayErrorTest.java @@ -0,0 +1,935 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.thrift.ThriftService; +import java.io.IOException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import org.apache.thrift.TException; +import org.apache.thrift.async.AsyncMethodCallback; +import org.apache.thrift.async.TAsyncClientManager; +import org.apache.thrift.protocol.TBinaryProtocol; +import org.apache.thrift.protocol.TMultiplexedProtocol; +import org.apache.thrift.protocol.TProtocol; +import org.apache.thrift.protocol.TProtocolFactory; +import org.apache.thrift.transport.TFramedTransport; +import org.apache.thrift.transport.TNonblockingSocket; +import org.apache.thrift.transport.TNonblockingTransport; +import org.apache.thrift.transport.TSocket; +import org.apache.thrift.transport.TTransport; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + +public class OneWayErrorTest extends ThriftBaseTest { + + @Test + public void syncClientSyncSimpleServerOneWayWithError() throws TException { + int port = super.getPort(); + this.startSyncSimpleServer(port); + this.syncClientOneWayWithError(port); + this.waitAndAssertTracesClientSyncServerSyncOnewayError(port, "oneWayWithError", 1); + } + + @Test + public void syncClientSyncSimpleServerOneWayWithErrorMuti() throws TException { + int port = super.getPort(); + this.startSyncSimpleServer(port); + for (int i = 0; i < 5; ++i) { + this.syncClientOneWayWithError(port); + } + this.waitAndAssertTracesClientSyncServerSyncOnewayError(port, "oneWayWithError", 5); + } + + @Test + public void syncClientSyncSimpleServerOneWayWithErrorParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncSimpleServer(port); + AtomicInteger count = new AtomicInteger(0); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncClientOneWayWithError(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncClientSimpleServerOneWayWithErrorParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + latch.await(); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerSyncOnewayError(port, "oneWayWithError", threadCount); + } + + @Test + public void syncClientSyncThreadPoolServerOneWayWithError() + throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncThreadPoolServer(port); + this.syncClientOneWayWithError(port); + this.waitAndAssertTracesClientSyncServerSyncOnewayError(port, "oneWayWithError", 1); + } + + @Test + public void syncClientSyncThreadPoolServerOneWayWithErrorMuti() throws TException { + int port = super.getPort(); + this.startSyncThreadPoolServer(port); + for (int i = 0; i < 5; ++i) { + this.syncClientOneWayWithError(port); + } + this.waitAndAssertTracesClientSyncServerSyncOnewayError(port, "oneWayWithError", 5); + } + + @Test + public void syncClientSyncThreadPoolServerOneWayWithErrorParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncThreadPoolServer(port); + AtomicInteger count = new AtomicInteger(0); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncClientOneWayWithError(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncClientSimpleServerOneWayWithErrorParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + latch.await(); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerSyncOnewayError(port, "oneWayWithError", threadCount); + } + + @Test + public void syncClientMutiSyncSimpleServerOneWayWithError() throws TException { + int port = super.getPort(); + this.startMultiSimpleServer(port); + this.syncClientMultiOneWayWithError(port); + this.waitAndAssertTracesClientSyncServerSyncOnewayError( + port, "oneWayWithError", "syncHelloWorld:oneWayWithError", 1); + } + + @Test + public void syncClientMutiSyncSimpleServerOneWayWithErrorMuti() throws TException { + int port = super.getPort(); + this.startMultiSimpleServer(port); + for (int i = 0; i < 5; ++i) { + this.syncClientMultiOneWayWithError(port); + } + this.waitAndAssertTracesClientSyncServerSyncOnewayError( + port, "oneWayWithError", "syncHelloWorld:oneWayWithError", 5); + } + + @Test + public void syncClientMutiSyncSimpleServerOneWayWithErrorParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startMultiSimpleServer(port); + AtomicInteger count = new AtomicInteger(0); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncClientMultiOneWayWithError(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncClientSimpleServerOneWayWithErrorParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + latch.await(); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerSyncOnewayError( + port, "oneWayWithError", "syncHelloWorld:oneWayWithError", threadCount); + } + + @Test + public void syncFramedClientAsyncThreadedSelectorServerOneWayWithError() throws TException { + int port = super.getPort(); + this.startAsyncThreadedSelectorServer(port); + this.syncFramedClientOneWayWithError(port); + this.waitAndAssertTracesClientSyncServerAsyncError(port, "oneWayWithError", 1); + } + + @Test + public void syncFramedClientAsyncThreadedSelectorServerOneWayWithErrorMuti() throws TException { + int port = super.getPort(); + this.startAsyncThreadedSelectorServer(port); + + for (int i = 0; i < 5; ++i) { + this.syncFramedClientOneWayWithError(port); + } + + this.waitAndAssertTracesClientSyncServerAsyncError(port, "oneWayWithError", 5); + } + + @Test + public void syncFramedClientAsyncThreadedSelectorServerOneWayWithErrorParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startAsyncThreadedSelectorServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncFramedClientOneWayWithError(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncFramedClientAsyncThreadedSelectorServerOneWayWithErrorParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerAsyncError(port, "oneWayWithError", threadCount); + } + + @Test + public void syncFramedClientAsyncMutiThreadedSelectorServerOneWayWithError() throws TException { + int port = super.getPort(); + this.startMultiThreadedSelectorServer(port); + this.syncFramedClientMultiOneWayWithError(port); + this.waitAndAssertTracesClientSyncServerSyncOnewayError( + port, "oneWayWithError", "syncHelloWorld:oneWayWithError", 1); + } + + @Test + public void syncFramedClientAsyncMutiThreadedSelectorServerOneWayWithErrorMuti() + throws TException { + int port = super.getPort(); + this.startMultiThreadedSelectorServer(port); + + for (int i = 0; i < 5; ++i) { + this.syncFramedClientMultiOneWayWithError(port); + } + + this.waitAndAssertTracesClientSyncServerSyncOnewayError( + port, "oneWayWithError", "syncHelloWorld:oneWayWithError", 5); + } + + @Test + public void syncFramedClientAsyncMutiThreadedSelectorServerOneWayWithErrorParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startMultiThreadedSelectorServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncFramedClientMultiOneWayWithError(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncFramedClientAsyncThreadedSelectorServerOneWayWithErrorParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerSyncOnewayError( + port, "oneWayWithError", "syncHelloWorld:oneWayWithError", threadCount); + } + + @Test + public void syncFramedClientSyncThreadedSelectorServerOneWayWithError() throws TException { + int port = super.getPort(); + this.startSyncThreadedSelectorServer(port); + this.syncFramedClientOneWayWithError(port); + this.waitAndAssertTracesClientSyncServerSyncOnewayError(port, "oneWayWithError", 1); + } + + @Test + public void syncFramedClientSyncThreadedSelectorServerOneWayWithErrorMuti() throws TException { + int port = super.getPort(); + this.startSyncThreadedSelectorServer(port); + + for (int i = 0; i < 5; ++i) { + this.syncFramedClientOneWayWithError(port); + } + + this.waitAndAssertTracesClientSyncServerSyncOnewayError(port, "oneWayWithError", 5); + } + + @Test + public void syncFramedClientSyncThreadedSelectorServerOneWayWithErrorParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncThreadedSelectorServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncFramedClientOneWayWithError(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncFramedClientSyncThreadedSelectorServerOneWayWithErrorParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerSyncOnewayError(port, "oneWayWithError", threadCount); + } + + @Test + public void nonBlockClientAsyncThreadedSelectorServerOneWayWithError() + throws TException, IOException { + int port = super.getPort(); + this.startAsyncThreadedSelectorServer(port); + this.nonBlockClientOneWayWithError(port); + this.waitAndAssertTracesClientAsyncServerAsyncError(port, "oneWayWithError", 1); + } + + @Test + public void nonBlockClientAsyncThreadedSelectorServerOneWayWithErrorMuti() + throws TException, IOException { + int port = super.getPort(); + this.startAsyncThreadedSelectorServer(port); + + for (int i = 0; i < 5; ++i) { + this.nonBlockClientOneWayWithError(port); + } + + this.waitAndAssertTracesClientAsyncServerAsyncError(port, "oneWayWithError", 5); + } + + @Test + public void nonBlockClientAsyncThreadedSelectorServerOneWayWithErrorParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startAsyncThreadedSelectorServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.nonBlockClientOneWayWithError(port); + } catch (IOException | TException e) { + count.incrementAndGet(); + Assertions.fail( + "nonBlockClientAsyncThreadedSelectorServerOneWayWithErrorParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientAsyncServerAsyncError(port, "oneWayWithError", threadCount); + } + + @Test + public void nonBlockClientSyncThreadedSelectorServerOneWayWithError() + throws TException, IOException { + int port = super.getPort(); + this.startSyncThreadedSelectorServer(port); + this.nonBlockClientOneWayWithError(port); + this.waitAndAssertTracesClientAsyncServerSyncOnewayError(port, "oneWayWithError", 1); + } + + @Test + public void nonBlockClientSyncThreadedSelectorServerOneWayWithErrorMuti() + throws TException, IOException { + int port = super.getPort(); + this.startSyncThreadedSelectorServer(port); + + for (int i = 0; i < 5; ++i) { + this.nonBlockClientOneWayWithError(port); + } + + this.waitAndAssertTracesClientAsyncServerSyncOnewayError(port, "oneWayWithError", 5); + } + + @Test + public void nonBlockClientSyncThreadedSelectorServerOneWayWithErrorParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncThreadedSelectorServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.nonBlockClientOneWayWithError(port); + } catch (IOException | TException e) { + count.incrementAndGet(); + Assertions.fail( + "nonBlockClientSyncThreadedSelectorServerOneWayWithErrorParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientAsyncServerSyncOnewayError(port, "oneWayWithError", threadCount); + } + + @Test + public void syncFramedClientSyncNonblockingServerOneWayWithError() throws TException { + int port = super.getPort(); + this.startSyncNonblockingServer(port); + this.syncFramedClientOneWayWithError(port); + this.waitAndAssertTracesClientSyncServerSyncOnewayError(port, "oneWayWithError", 1); + } + + @Test + public void syncFramedClientSyncNonblockingServerOneWayWithErrorMuti() throws TException { + int port = super.getPort(); + this.startSyncNonblockingServer(port); + + for (int i = 0; i < 5; ++i) { + this.syncFramedClientOneWayWithError(port); + } + + this.waitAndAssertTracesClientSyncServerSyncOnewayError(port, "oneWayWithError", 5); + } + + @Test + public void syncFramedClientSyncNonblockingServerOneWayWithErrorParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncNonblockingServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncFramedClientOneWayWithError(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncFramedClientSyncNonblockingServerOneWayWithErrorParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerSyncOnewayError(port, "oneWayWithError", threadCount); + } + + @Test + public void syncFramedClientSyncHsHaServerOneWayWithError() throws TException { + int port = super.getPort(); + this.startSyncHsHaServer(port); + this.syncFramedClientOneWayWithError(port); + this.waitAndAssertTracesClientSyncServerSyncOnewayError(port, "oneWayWithError", 1); + } + + @Test + public void syncFramedClientSyncHsHaServerOneWayWithErrorMuti() throws TException { + int port = super.getPort(); + this.startSyncHsHaServer(port); + + for (int i = 0; i < 5; ++i) { + this.syncFramedClientOneWayWithError(port); + } + + this.waitAndAssertTracesClientSyncServerSyncOnewayError(port, "oneWayWithError", 5); + } + + @Test + public void syncFramedClientSyncHsHaServerOneWayWithErrorParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncHsHaServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncFramedClientOneWayWithError(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncFramedClientSyncHsHaServerOneWayWithErrorParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerSyncOnewayError(port, "oneWayWithError", threadCount); + } + + @Test + public void syncFramedClientAsyncNonblockingServerOneWayWithError() throws TException { + int port = super.getPort(); + this.startAsyncNonblockingServer(port); + this.syncFramedClientOneWayWithError(port); + this.waitAndAssertTracesClientSyncServerAsyncError(port, "oneWayWithError", 1); + } + + @Test + public void syncFramedClientAsyncNonblockingServerOneWayWithErrorMuti() throws TException { + int port = super.getPort(); + this.startAsyncNonblockingServer(port); + + for (int i = 0; i < 5; ++i) { + this.syncFramedClientOneWayWithError(port); + } + + this.waitAndAssertTracesClientSyncServerAsyncError(port, "oneWayWithError", 5); + } + + @Test + public void syncFramedClientAsyncNonblockingServerOneWayWithErrorParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startAsyncNonblockingServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncFramedClientOneWayWithError(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncFramedClientAsyncNonblockingServerOneWayWithErrorParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerAsyncError(port, "oneWayWithError", threadCount); + } + + @Test + public void syncFramedClientAsyncHsHaServerOneWayWithError() throws TException { + int port = super.getPort(); + this.startAsyncHsHaServer(port); + this.syncFramedClientOneWayWithError(port); + this.waitAndAssertTracesClientSyncServerAsyncError(port, "oneWayWithError", 1); + } + + @Test + public void syncFramedClientAsyncHsHaServerOneWayWithErrorMuti() throws TException { + int port = super.getPort(); + this.startAsyncHsHaServer(port); + + for (int i = 0; i < 5; ++i) { + this.syncFramedClientOneWayWithError(port); + } + + this.waitAndAssertTracesClientSyncServerAsyncError(port, "oneWayWithError", 5); + } + + @Test + public void syncFramedClientAsyncHsHaServerOneWayWithErrorParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startAsyncHsHaServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncFramedClientOneWayWithError(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncFramedClientAsyncHsHaServerOneWayWithErrorParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerAsyncError(port, "oneWayWithError", threadCount); + } + + @Test + public void nonBlockClientSyncNonblockingServerOneWayWithError() throws TException, IOException { + int port = super.getPort(); + this.startSyncNonblockingServer(port); + this.nonBlockClientOneWayWithError(port); + this.waitAndAssertTracesClientAsyncServerSyncOnewayError(port, "oneWayWithError", 1); + } + + @Test + public void nonBlockClientSyncNonblockingServerOneWayWithErrorMuti() + throws TException, IOException { + int port = super.getPort(); + this.startSyncNonblockingServer(port); + + for (int i = 0; i < 5; ++i) { + this.nonBlockClientOneWayWithError(port); + } + + this.waitAndAssertTracesClientAsyncServerSyncOnewayError(port, "oneWayWithError", 5); + } + + @Test + public void nonBlockClientSyncNonblockingServerOneWayWithErrorParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncNonblockingServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.nonBlockClientOneWayWithError(port); + } catch (IOException | TException e) { + count.incrementAndGet(); + Assertions.fail( + "nonBlockClientSyncNonblockingServerOneWayWithErrorParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientAsyncServerSyncOnewayError(port, "oneWayWithError", threadCount); + } + + @Test + public void nonBlockClientSyncHsHaServerOneWayWithError() throws TException, IOException { + int port = super.getPort(); + this.startSyncHsHaServer(port); + this.nonBlockClientOneWayWithError(port); + this.waitAndAssertTracesClientAsyncServerSyncOnewayError(port, "oneWayWithError", 1); + } + + @Test + public void nonBlockClientSyncHsHaServerOneWayWithErrorMuti() throws TException, IOException { + int port = super.getPort(); + this.startSyncHsHaServer(port); + + for (int i = 0; i < 5; ++i) { + this.nonBlockClientOneWayWithError(port); + } + + this.waitAndAssertTracesClientAsyncServerSyncOnewayError(port, "oneWayWithError", 5); + } + + @Test + public void nonBlockClientSyncHsHaServerOneWayWithErrorParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncHsHaServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.nonBlockClientOneWayWithError(port); + } catch (IOException | TException e) { + count.incrementAndGet(); + Assertions.fail( + "nonBlockClientSyncHsHaServerOneWayWithErrorParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientAsyncServerSyncOnewayError(port, "oneWayWithError", threadCount); + } + + @Test + public void nonBlockClientAsyncNonblockingServerOneWayWithError() throws TException, IOException { + int port = super.getPort(); + this.startAsyncNonblockingServer(port); + this.nonBlockClientOneWayWithError(port); + this.waitAndAssertTracesClientAsyncServerAsyncError(port, "oneWayWithError", 1); + } + + @Test + public void nonBlockClientAsyncNonblockingServerOneWayWithErrorMuti() + throws TException, IOException { + int port = super.getPort(); + this.startAsyncNonblockingServer(port); + + for (int i = 0; i < 5; ++i) { + this.nonBlockClientOneWayWithError(port); + } + + this.waitAndAssertTracesClientAsyncServerAsyncError(port, "oneWayWithError", 5); + } + + @Test + public void nonBlockClientAsyncNonblockingServerOneWayWithErrorParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startAsyncNonblockingServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.nonBlockClientOneWayWithError(port); + } catch (IOException | TException e) { + count.incrementAndGet(); + Assertions.fail( + "nonBlockClientAsyncNonblockingServerOneWayWithErrorParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientAsyncServerAsyncError(port, "oneWayWithError", threadCount); + } + + @Test + public void nonBlockClientAsyncHsHaServerOneWayWithError() throws TException, IOException { + int port = super.getPort(); + this.startAsyncHsHaServer(port); + this.nonBlockClientOneWayWithError(port); + this.waitAndAssertTracesClientAsyncServerAsyncError(port, "oneWayWithError", 1); + } + + @Test + public void nonBlockClientAsyncHsHaServerOneWayWithErrorMuti() throws TException, IOException { + int port = super.getPort(); + this.startAsyncHsHaServer(port); + + for (int i = 0; i < 5; ++i) { + this.nonBlockClientOneWayWithError(port); + } + + this.waitAndAssertTracesClientAsyncServerAsyncError(port, "oneWayWithError", 5); + } + + @Test + public void nonBlockClientAsyncHsHaServerOneWayWithErrorParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startAsyncHsHaServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.nonBlockClientOneWayWithError(port); + } catch (IOException | TException e) { + count.incrementAndGet(); + Assertions.fail( + "nonBlockClientAsyncHsHaServerOneWayWithErrorParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientAsyncServerAsyncError(port, "oneWayWithError", threadCount); + } + + public void syncClientOneWayWithError(int port) throws TException { + TTransport transport = null; + try { + transport = new TSocket("localhost", port); + transport.open(); + TProtocol protocol = new TBinaryProtocol(transport); + ThriftService.Client client = new ThriftService.Client(protocol); + this.testing().runWithSpan("parent", () -> client.oneWayWithError()); + } finally { + if (transport != null) { + transport.close(); + } + } + } + + public void syncClientMultiOneWayWithError(int port) throws TException { + TTransport transport = null; + try { + transport = new TSocket("localhost", port); + transport.open(); + TProtocol protocol = new TBinaryProtocol(transport); + TMultiplexedProtocol multiplexedProtocol = + new TMultiplexedProtocol(protocol, "syncHelloWorld"); + ThriftService.Client client = new ThriftService.Client(multiplexedProtocol); + this.testing().runWithSpan("parent", () -> client.oneWayWithError()); + } finally { + if (transport != null) { + transport.close(); + } + } + } + + public void nonBlockClientOneWayWithError(int port) throws TException, IOException { + TNonblockingTransport transport = new TNonblockingSocket("localhost", port); + TAsyncClientManager clientManager = new TAsyncClientManager(); + TProtocolFactory protocolFactory = new TBinaryProtocol.Factory(); + ThriftService.AsyncClient.Factory factory = + new ThriftService.AsyncClient.Factory(clientManager, protocolFactory); + ThriftService.AsyncClient asyClient = factory.getAsyncClient(transport); + AsyncMethodCallback callback = + new AsyncMethodCallback() { + @Override + public void onComplete(ThriftService.AsyncClient.oneWayWithError_call no) {} + + @Override + public void onError(Exception e) { + assertThat(e.getMessage()).isEqualTo("Read call frame size failed"); + } + }; + this.testing().runWithSpan("parent", () -> asyClient.oneWayWithError(callback)); + } + + public void syncFramedClientOneWayWithError(int port) throws TException { + TTransport transport = null; + try { + transport = new TSocket("localhost", port); + TFramedTransport framedTransport = new TFramedTransport(transport); + framedTransport.open(); + TProtocol protocol = new TBinaryProtocol(framedTransport); + ThriftService.Client client = new ThriftService.Client(protocol); + this.testing().runWithSpan("parent", () -> client.oneWayWithError()); + } finally { + if (transport != null) { + transport.close(); + } + } + } + + public void syncFramedClientMultiOneWayWithError(int port) throws TException { + TTransport transport = null; + try { + transport = new TSocket("localhost", port); + TFramedTransport framedTransport = new TFramedTransport(transport); + framedTransport.open(); + TProtocol protocol = new TBinaryProtocol(framedTransport); + TMultiplexedProtocol multiplexedProtocol = + new TMultiplexedProtocol(protocol, "syncHelloWorld"); + ThriftService.Client client = new ThriftService.Client(multiplexedProtocol); + this.testing().runWithSpan("parent", () -> client.oneWayWithError()); + } finally { + if (transport != null) { + transport.close(); + } + } + } +} diff --git a/instrumentation/thrift/thrift-0.9.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/OneWayTest.java b/instrumentation/thrift/thrift-0.9.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/OneWayTest.java new file mode 100644 index 000000000000..431f1ff3dd4c --- /dev/null +++ b/instrumentation/thrift/thrift-0.9.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/OneWayTest.java @@ -0,0 +1,918 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.thrift.ThriftService; +import java.io.IOException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import org.apache.thrift.TException; +import org.apache.thrift.async.AsyncMethodCallback; +import org.apache.thrift.async.TAsyncClientManager; +import org.apache.thrift.protocol.TBinaryProtocol; +import org.apache.thrift.protocol.TMultiplexedProtocol; +import org.apache.thrift.protocol.TProtocol; +import org.apache.thrift.protocol.TProtocolFactory; +import org.apache.thrift.transport.TFramedTransport; +import org.apache.thrift.transport.TNonblockingSocket; +import org.apache.thrift.transport.TNonblockingTransport; +import org.apache.thrift.transport.TSocket; +import org.apache.thrift.transport.TTransport; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + +public class OneWayTest extends ThriftBaseTest { + + @Test + public void syncClientSyncSimpleServerOneWay() throws TException { + int port = super.getPort(); + this.startSyncSimpleServer(port); + this.syncClientOneWay(port); + this.waitAndAssertTracesClientSyncServerSync(port, "oneWay", 1); + } + + @Test + public void syncClientSyncSimpleServerOneWayMuti() throws TException { + int port = super.getPort(); + this.startSyncSimpleServer(port); + for (int i = 0; i < 5; ++i) { + this.syncClientOneWay(port); + } + this.waitAndAssertTracesClientSyncServerSync(port, "oneWay", 5); + } + + @Test + public void syncClientSyncSimpleServerOneWayParallel() throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncSimpleServer(port); + AtomicInteger count = new AtomicInteger(0); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncClientOneWay(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncClientSimpleServerOneWayParallel field: " + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + latch.await(); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerSync(port, "oneWay", threadCount); + } + + @Test + public void syncClientSyncThreadPoolServerOneWay() throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncThreadPoolServer(port); + this.syncClientOneWay(port); + this.waitAndAssertTracesClientSyncServerSync(port, "oneWay", 1); + } + + @Test + public void syncClientSyncThreadPoolServerOneWayMuti() throws TException { + int port = super.getPort(); + this.startSyncThreadPoolServer(port); + for (int i = 0; i < 5; ++i) { + this.syncClientOneWay(port); + } + this.waitAndAssertTracesClientSyncServerSync(port, "oneWay", 5); + } + + @Test + public void syncClientSyncThreadPoolServerOneWayParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncThreadPoolServer(port); + AtomicInteger count = new AtomicInteger(0); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncClientOneWay(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncClientSimpleServerOneWayParallel field: " + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + latch.await(); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerSync(port, "oneWay", threadCount); + } + + @Test + public void syncClientMutiSyncSimpleServerOneWay() throws TException { + int port = super.getPort(); + this.startMultiSimpleServer(port); + this.syncClientMultiOneWay(port); + this.waitAndAssertTracesClientSyncServerSync(port, "oneWay", "syncHelloWorld:oneWay", 1); + } + + @Test + public void syncClientMutiSyncSimpleServerOneWayMuti() throws TException { + int port = super.getPort(); + this.startMultiSimpleServer(port); + for (int i = 0; i < 5; ++i) { + this.syncClientMultiOneWay(port); + } + this.waitAndAssertTracesClientSyncServerSync(port, "oneWay", "syncHelloWorld:oneWay", 5); + } + + @Test + public void syncClientMutiSyncSimpleServerOneWayParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startMultiSimpleServer(port); + AtomicInteger count = new AtomicInteger(0); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncClientMultiOneWay(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncClientSimpleServerOneWayParallel field: " + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + latch.await(); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerSync( + port, "oneWay", "syncHelloWorld:oneWay", threadCount); + } + + @Test + public void syncFramedClientAsyncThreadedSelectorServerOneWay() throws TException { + int port = super.getPort(); + this.startAsyncThreadedSelectorServer(port); + this.syncFramedClientOneWay(port); + this.waitAndAssertTracesClientSyncServerAsync(port, "oneWay", 1); + } + + @Test + public void syncFramedClientAsyncThreadedSelectorServerOneWayMuti() throws TException { + int port = super.getPort(); + this.startAsyncThreadedSelectorServer(port); + + for (int i = 0; i < 5; ++i) { + this.syncFramedClientOneWay(port); + } + + this.waitAndAssertTracesClientSyncServerAsync(port, "oneWay", 5); + } + + @Test + public void syncFramedClientAsyncThreadedSelectorServerOneWayParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startAsyncThreadedSelectorServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncFramedClientOneWay(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncFramedClientAsyncThreadedSelectorServerOneWayParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerAsync(port, "oneWay", threadCount); + } + + @Test + public void syncFramedClientAsyncMutiThreadedSelectorServerOneWay() throws TException { + int port = super.getPort(); + this.startMultiThreadedSelectorServer(port); + this.syncFramedClientMultiOneWay(port); + this.waitAndAssertTracesClientSyncServerSync(port, "oneWay", "syncHelloWorld:oneWay", 1); + } + + @Test + public void syncFramedClientAsyncMutiThreadedSelectorServerOneWayMuti() throws TException { + int port = super.getPort(); + this.startMultiThreadedSelectorServer(port); + + for (int i = 0; i < 5; ++i) { + this.syncFramedClientMultiOneWay(port); + } + + this.waitAndAssertTracesClientSyncServerSync(port, "oneWay", "syncHelloWorld:oneWay", 5); + } + + @Test + public void syncFramedClientAsyncMutiThreadedSelectorServerOneWayParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startMultiThreadedSelectorServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncFramedClientMultiOneWay(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncFramedClientAsyncThreadedSelectorServerOneWayParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerSync( + port, "oneWay", "syncHelloWorld:oneWay", threadCount); + } + + @Test + public void syncFramedClientSyncThreadedSelectorServerOneWay() throws TException { + int port = super.getPort(); + this.startSyncThreadedSelectorServer(port); + this.syncFramedClientOneWay(port); + this.waitAndAssertTracesClientSyncServerSync(port, "oneWay", 1); + } + + @Test + public void syncFramedClientSyncThreadedSelectorServerOneWayMuti() throws TException { + int port = super.getPort(); + this.startSyncThreadedSelectorServer(port); + + for (int i = 0; i < 5; ++i) { + this.syncFramedClientOneWay(port); + } + + this.waitAndAssertTracesClientSyncServerSync(port, "oneWay", 5); + } + + @Test + public void syncFramedClientSyncThreadedSelectorServerOneWayParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncThreadedSelectorServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncFramedClientOneWay(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncFramedClientSyncThreadedSelectorServerOneWayParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerSync(port, "oneWay", threadCount); + } + + @Test + public void nonBlockClientAsyncThreadedSelectorServerOneWay() throws TException, IOException { + int port = super.getPort(); + this.startAsyncThreadedSelectorServer(port); + this.nonBlockClientOneWay(port); + this.waitAndAssertTracesClientAsyncServerAsync(port, "oneWay", 1); + } + + @Test + public void nonBlockClientAsyncThreadedSelectorServerOneWayMuti() throws TException, IOException { + int port = super.getPort(); + this.startAsyncThreadedSelectorServer(port); + + for (int i = 0; i < 5; ++i) { + this.nonBlockClientOneWay(port); + } + + this.waitAndAssertTracesClientAsyncServerAsync(port, "oneWay", 5); + } + + @Test + public void nonBlockClientAsyncThreadedSelectorServerOneWayParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startAsyncThreadedSelectorServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.nonBlockClientOneWay(port); + } catch (IOException | TException e) { + count.incrementAndGet(); + Assertions.fail( + "nonBlockClientAsyncThreadedSelectorServerOneWayParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientAsyncServerAsync(port, "oneWay", threadCount); + } + + @Test + public void nonBlockClientSyncThreadedSelectorServerOneWay() throws TException, IOException { + int port = super.getPort(); + this.startSyncThreadedSelectorServer(port); + this.nonBlockClientOneWay(port); + this.waitAndAssertTracesClientAsyncServerSync(port, "oneWay", 1); + } + + @Test + public void nonBlockClientSyncThreadedSelectorServerOneWayMuti() throws TException, IOException { + int port = super.getPort(); + this.startSyncThreadedSelectorServer(port); + + for (int i = 0; i < 5; ++i) { + this.nonBlockClientOneWay(port); + } + + this.waitAndAssertTracesClientAsyncServerSync(port, "oneWay", 5); + } + + @Test + public void nonBlockClientSyncThreadedSelectorServerOneWayParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncThreadedSelectorServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.nonBlockClientOneWay(port); + } catch (IOException | TException e) { + count.incrementAndGet(); + Assertions.fail( + "nonBlockClientSyncThreadedSelectorServerOneWayParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientAsyncServerSync(port, "oneWay", threadCount); + } + + @Test + public void syncFramedClientSyncNonblockingServerOneWay() throws TException { + int port = super.getPort(); + this.startSyncNonblockingServer(port); + this.syncFramedClientOneWay(port); + this.waitAndAssertTracesClientSyncServerSync(port, "oneWay", 1); + } + + @Test + public void syncFramedClientSyncNonblockingServerOneWayMuti() throws TException { + int port = super.getPort(); + this.startSyncNonblockingServer(port); + + for (int i = 0; i < 5; ++i) { + this.syncFramedClientOneWay(port); + } + + this.waitAndAssertTracesClientSyncServerSync(port, "oneWay", 5); + } + + @Test + public void syncFramedClientSyncNonblockingServerOneWayParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncNonblockingServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncFramedClientOneWay(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncFramedClientSyncNonblockingServerOneWayParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerSync(port, "oneWay", threadCount); + } + + @Test + public void syncFramedClientSyncHsHaServerOneWay() throws TException { + int port = super.getPort(); + this.startSyncHsHaServer(port); + this.syncFramedClientOneWay(port); + this.waitAndAssertTracesClientSyncServerSync(port, "oneWay", 1); + } + + @Test + public void syncFramedClientSyncHsHaServerOneWayMuti() throws TException { + int port = super.getPort(); + this.startSyncHsHaServer(port); + + for (int i = 0; i < 5; ++i) { + this.syncFramedClientOneWay(port); + } + + this.waitAndAssertTracesClientSyncServerSync(port, "oneWay", 5); + } + + @Test + public void syncFramedClientSyncHsHaServerOneWayParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncHsHaServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncFramedClientOneWay(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncFramedClientSyncHsHaServerOneWayParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerSync(port, "oneWay", threadCount); + } + + @Test + public void syncFramedClientAsyncNonblockingServerOneWay() throws TException { + int port = super.getPort(); + this.startAsyncNonblockingServer(port); + this.syncFramedClientOneWay(port); + this.waitAndAssertTracesClientSyncServerAsync(port, "oneWay", 1); + } + + @Test + public void syncFramedClientAsyncNonblockingServerOneWayMuti() throws TException { + int port = super.getPort(); + this.startAsyncNonblockingServer(port); + + for (int i = 0; i < 5; ++i) { + this.syncFramedClientOneWay(port); + } + + this.waitAndAssertTracesClientSyncServerAsync(port, "oneWay", 5); + } + + @Test + public void syncFramedClientAsyncNonblockingServerOneWayParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startAsyncNonblockingServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncFramedClientOneWay(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncFramedClientAsyncNonblockingServerOneWayParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerAsync(port, "oneWay", threadCount); + } + + @Test + public void syncFramedClientAsyncHsHaServerOneWay() throws TException { + int port = super.getPort(); + this.startAsyncHsHaServer(port); + this.syncFramedClientOneWay(port); + this.waitAndAssertTracesClientSyncServerAsync(port, "oneWay", 1); + } + + @Test + public void syncFramedClientAsyncHsHaServerOneWayMuti() throws TException { + int port = super.getPort(); + this.startAsyncHsHaServer(port); + + for (int i = 0; i < 5; ++i) { + this.syncFramedClientOneWay(port); + } + + this.waitAndAssertTracesClientSyncServerAsync(port, "oneWay", 5); + } + + @Test + public void syncFramedClientAsyncHsHaServerOneWayParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startAsyncHsHaServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncFramedClientOneWay(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncFramedClientAsyncHsHaServerOneWayParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerAsync(port, "oneWay", threadCount); + } + + @Test + public void nonBlockClientSyncNonblockingServerOneWay() throws TException, IOException { + int port = super.getPort(); + this.startSyncNonblockingServer(port); + this.nonBlockClientOneWay(port); + this.waitAndAssertTracesClientAsyncServerSync(port, "oneWay", 1); + } + + @Test + public void nonBlockClientSyncNonblockingServerOneWayMuti() throws TException, IOException { + int port = super.getPort(); + this.startSyncNonblockingServer(port); + + for (int i = 0; i < 5; ++i) { + this.nonBlockClientOneWay(port); + } + + this.waitAndAssertTracesClientAsyncServerSync(port, "oneWay", 5); + } + + @Test + public void nonBlockClientSyncNonblockingServerOneWayParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncNonblockingServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.nonBlockClientOneWay(port); + } catch (IOException | TException e) { + count.incrementAndGet(); + Assertions.fail( + "nonBlockClientSyncNonblockingServerOneWayParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientAsyncServerSync(port, "oneWay", threadCount); + } + + @Test + public void nonBlockClientSyncHsHaServerOneWay() throws TException, IOException { + int port = super.getPort(); + this.startSyncHsHaServer(port); + this.nonBlockClientOneWay(port); + this.waitAndAssertTracesClientAsyncServerSync(port, "oneWay", 1); + } + + @Test + public void nonBlockClientSyncHsHaServerOneWayMuti() throws TException, IOException { + int port = super.getPort(); + this.startSyncHsHaServer(port); + + for (int i = 0; i < 5; ++i) { + this.nonBlockClientOneWay(port); + } + + this.waitAndAssertTracesClientAsyncServerSync(port, "oneWay", 5); + } + + @Test + public void nonBlockClientSyncHsHaServerOneWayParallel() throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncHsHaServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.nonBlockClientOneWay(port); + } catch (IOException | TException e) { + count.incrementAndGet(); + Assertions.fail( + "nonBlockClientSyncHsHaServerOneWayParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientAsyncServerSync(port, "oneWay", threadCount); + } + + @Test + public void nonBlockClientAsyncNonblockingServerOneWay() throws TException, IOException { + int port = super.getPort(); + this.startAsyncNonblockingServer(port); + this.nonBlockClientOneWay(port); + this.waitAndAssertTracesClientAsyncServerAsync(port, "oneWay", 1); + } + + @Test + public void nonBlockClientAsyncNonblockingServerOneWayMuti() throws TException, IOException { + int port = super.getPort(); + this.startAsyncNonblockingServer(port); + + for (int i = 0; i < 5; ++i) { + this.nonBlockClientOneWay(port); + } + + this.waitAndAssertTracesClientAsyncServerAsync(port, "oneWay", 5); + } + + @Test + public void nonBlockClientAsyncNonblockingServerOneWayParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startAsyncNonblockingServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.nonBlockClientOneWay(port); + } catch (IOException | TException e) { + count.incrementAndGet(); + Assertions.fail( + "nonBlockClientAsyncNonblockingServerOneWayParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientAsyncServerAsync(port, "oneWay", threadCount); + } + + @Test + public void nonBlockClientAsyncHsHaServerOneWay() throws TException, IOException { + int port = super.getPort(); + this.startAsyncHsHaServer(port); + this.nonBlockClientOneWay(port); + this.waitAndAssertTracesClientAsyncServerAsync(port, "oneWay", 1); + } + + @Test + public void nonBlockClientAsyncHsHaServerOneWayMuti() throws TException, IOException { + int port = super.getPort(); + this.startAsyncHsHaServer(port); + + for (int i = 0; i < 5; ++i) { + this.nonBlockClientOneWay(port); + } + + this.waitAndAssertTracesClientAsyncServerAsync(port, "oneWay", 5); + } + + @Test + public void nonBlockClientAsyncHsHaServerOneWayParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startAsyncHsHaServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.nonBlockClientOneWay(port); + } catch (IOException | TException e) { + count.incrementAndGet(); + Assertions.fail( + "nonBlockClientAsyncHsHaServerOneWayParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientAsyncServerAsync(port, "oneWay", threadCount); + } + + public void syncClientOneWay(int port) throws TException { + TTransport transport = null; + try { + transport = new TSocket("localhost", port); + transport.open(); + TProtocol protocol = new TBinaryProtocol(transport); + ThriftService.Client client = new ThriftService.Client(protocol); + this.testing().runWithSpan("parent", () -> client.oneWay()); + } finally { + if (transport != null) { + transport.close(); + } + } + } + + public void syncClientMultiOneWay(int port) throws TException { + TTransport transport = null; + try { + transport = new TSocket("localhost", port); + transport.open(); + TProtocol protocol = new TBinaryProtocol(transport); + TMultiplexedProtocol multiplexedProtocol = + new TMultiplexedProtocol(protocol, "syncHelloWorld"); + ThriftService.Client client = new ThriftService.Client(multiplexedProtocol); + this.testing().runWithSpan("parent", () -> client.oneWay()); + } finally { + if (transport != null) { + transport.close(); + } + } + } + + public void nonBlockClientOneWay(int port) throws TException, IOException { + TNonblockingTransport transport = new TNonblockingSocket("localhost", port); + TAsyncClientManager clientManager = new TAsyncClientManager(); + TProtocolFactory protocolFactory = new TBinaryProtocol.Factory(); + ThriftService.AsyncClient.Factory factory = + new ThriftService.AsyncClient.Factory(clientManager, protocolFactory); + ThriftService.AsyncClient asyClient = factory.getAsyncClient(transport); + AsyncMethodCallback callback = + new AsyncMethodCallback() { + @Override + public void onComplete(ThriftService.AsyncClient.oneWay_call no) {} + + @Override + public void onError(Exception e) { + assertThat(e.getMessage()).isEqualTo("Read call frame size failed"); + } + }; + this.testing().runWithSpan("parent", () -> asyClient.oneWay(callback)); + } + + public void syncFramedClientOneWay(int port) throws TException { + TTransport transport = null; + try { + transport = new TSocket("localhost", port); + TFramedTransport framedTransport = new TFramedTransport(transport); + framedTransport.open(); + TProtocol protocol = new TBinaryProtocol(framedTransport); + ThriftService.Client client = new ThriftService.Client(protocol); + this.testing().runWithSpan("parent", () -> client.oneWay()); + } finally { + if (transport != null) { + transport.close(); + } + } + } + + public void syncFramedClientMultiOneWay(int port) throws TException { + TTransport transport = null; + try { + transport = new TSocket("localhost", port); + TFramedTransport framedTransport = new TFramedTransport(transport); + framedTransport.open(); + TProtocol protocol = new TBinaryProtocol(framedTransport); + TMultiplexedProtocol multiplexedProtocol = + new TMultiplexedProtocol(protocol, "syncHelloWorld"); + ThriftService.Client client = new ThriftService.Client(multiplexedProtocol); + this.testing().runWithSpan("parent", () -> client.oneWay()); + } finally { + if (transport != null) { + transport.close(); + } + } + } +} diff --git a/instrumentation/thrift/thrift-0.9.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/SayHelloTest.java b/instrumentation/thrift/thrift-0.9.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/SayHelloTest.java new file mode 100644 index 000000000000..a579632f3898 --- /dev/null +++ b/instrumentation/thrift/thrift-0.9.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/SayHelloTest.java @@ -0,0 +1,1064 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.thrift.ThriftService; +import java.io.IOException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import org.apache.thrift.TException; +import org.apache.thrift.async.AsyncMethodCallback; +import org.apache.thrift.async.TAsyncClientManager; +import org.apache.thrift.protocol.TBinaryProtocol; +import org.apache.thrift.protocol.TMultiplexedProtocol; +import org.apache.thrift.protocol.TProtocol; +import org.apache.thrift.protocol.TProtocolFactory; +import org.apache.thrift.transport.TFastFramedTransport; +import org.apache.thrift.transport.TFramedTransport; +import org.apache.thrift.transport.TNonblockingSocket; +import org.apache.thrift.transport.TNonblockingTransport; +import org.apache.thrift.transport.TSocket; +import org.apache.thrift.transport.TTransport; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; +import org.testcontainers.shaded.com.google.common.base.VerifyException; + +public class SayHelloTest extends ThriftBaseTest { + + @Test + public void syncClientSyncSimpleServerSayHello() throws TException { + int port = super.getPort(); + this.startSyncSimpleServer(port); + this.syncClientSayHello(port); + this.waitAndAssertTracesClientSyncServerSync(port, "sayHello", 1); + } + + @Test + public void syncClientSyncSimpleServerSayHelloMuti() throws TException { + int port = super.getPort(); + this.startSyncSimpleServer(port); + for (int i = 0; i < 5; ++i) { + this.syncClientSayHello(port); + } + this.waitAndAssertTracesClientSyncServerSync(port, "sayHello", 5); + } + + @Test + public void syncClientSyncSimpleServerSayHelloParallel() throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncSimpleServer(port); + AtomicInteger count = new AtomicInteger(0); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncClientSayHello(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncClientSimpleServerSayHelloParallel field: " + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + latch.await(); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerSync(port, "sayHello", threadCount); + } + + @Test + public void syncClientSyncThreadPoolServerSayHello() throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncThreadPoolServer(port); + this.syncClientSayHello(port); + this.waitAndAssertTracesClientSyncServerSync(port, "sayHello", 1); + } + + @Test + public void syncClientSyncThreadPoolServerSayHelloMuti() throws TException { + int port = super.getPort(); + this.startSyncThreadPoolServer(port); + for (int i = 0; i < 5; ++i) { + this.syncClientSayHello(port); + } + this.waitAndAssertTracesClientSyncServerSync(port, "sayHello", 5); + } + + @Test + public void syncClientSyncThreadPoolServerSayHelloParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncThreadPoolServer(port); + AtomicInteger count = new AtomicInteger(0); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncClientSayHello(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncClientSimpleServerSayHelloParallel field: " + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + latch.await(); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerSync(port, "sayHello", threadCount); + } + + @Test + public void syncClientMutiSyncSimpleServerSayHello() throws TException { + int port = super.getPort(); + this.startMultiSimpleServer(port); + this.syncClientMultiSayHello(port); + this.waitAndAssertTracesClientSyncServerSync(port, "sayHello", "syncHelloWorld:sayHello", 1); + } + + @Test + public void syncClientMutiSyncSimpleServerSayHelloMuti() throws TException { + int port = super.getPort(); + this.startMultiSimpleServer(port); + for (int i = 0; i < 5; ++i) { + this.syncClientMultiSayHello(port); + } + this.waitAndAssertTracesClientSyncServerSync(port, "sayHello", "syncHelloWorld:sayHello", 5); + } + + @Test + public void syncClientMutiSyncSimpleServerSayHelloParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startMultiSimpleServer(port); + AtomicInteger count = new AtomicInteger(0); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncClientMultiSayHello(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncClientSimpleServerSayHelloParallel field: " + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + latch.await(); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerSync( + port, "sayHello", "syncHelloWorld:sayHello", threadCount); + } + + @Test + public void syncFramedClientAsyncThreadedSelectorServerSayHello() throws TException { + int port = super.getPort(); + this.startAsyncThreadedSelectorServer(port); + this.syncFramedClientSayHello(port); + this.waitAndAssertTracesClientSyncServerAsync(port, "sayHello", 1); + } + + @Test + public void syncFastFramedClientAsyncThreadedSelectorServerSayHello() throws TException { + int port = super.getPort(); + this.startAsyncThreadedSelectorServer(port); + this.syncFastFramedClientSayHello(port); + this.waitAndAssertTracesClientSyncServerAsync(port, "sayHello", 1); + } + + @Test + public void syncFramedClientAsyncThreadedSelectorFastServerSayHello() throws TException { + int port = super.getPort(); + this.startAsyncThreadedSelectorFastServer(port); + this.syncFramedClientSayHello(port); + this.waitAndAssertTracesClientSyncServerAsync(port, "sayHello", 1); + } + + @Test + public void syncFastFramedClientAsyncThreadedSelectorFastServerSayHello() throws TException { + int port = super.getPort(); + this.startAsyncThreadedSelectorFastServer(port); + this.syncFastFramedClientSayHello(port); + this.waitAndAssertTracesClientSyncServerAsync(port, "sayHello", 1); + } + + @Test + public void syncFramedClientAsyncThreadedSelectorServerSayHelloMuti() throws TException { + int port = super.getPort(); + this.startAsyncThreadedSelectorServer(port); + + for (int i = 0; i < 5; ++i) { + this.syncFramedClientSayHello(port); + } + + this.waitAndAssertTracesClientSyncServerAsync(port, "sayHello", 5); + } + + @Test + public void syncFramedClientAsyncThreadedSelectorServerSayHelloParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startAsyncThreadedSelectorServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncFramedClientSayHello(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncFramedClientAsyncThreadedSelectorServerSayHelloParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerAsync(port, "sayHello", threadCount); + } + + @Test + public void syncFramedClientAsyncMutiThreadedSelectorServerSayHello() throws TException { + int port = super.getPort(); + this.startMultiThreadedSelectorServer(port); + this.syncFramedClientMultiSayHello(port); + this.waitAndAssertTracesClientSyncServerSync(port, "sayHello", "syncHelloWorld:sayHello", 1); + } + + @Test + public void syncFramedClientAsyncMutiThreadedSelectorServerSayHelloMuti() throws TException { + int port = super.getPort(); + this.startMultiThreadedSelectorServer(port); + for (int i = 0; i < 5; ++i) { + this.syncFramedClientMultiSayHello(port); + } + this.waitAndAssertTracesClientSyncServerSync(port, "sayHello", "syncHelloWorld:sayHello", 5); + } + + @Test + public void syncFramedClientAsyncMutiThreadedSelectorServerSayHelloParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startMultiThreadedSelectorServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncFramedClientMultiSayHello(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncFramedClientAsyncThreadedSelectorServerSayHelloParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerSync( + port, "sayHello", "syncHelloWorld:sayHello", threadCount); + } + + @Test + public void syncFramedClientSyncThreadedSelectorServerSayHello() throws TException { + int port = super.getPort(); + this.startSyncThreadedSelectorServer(port); + this.syncFramedClientSayHello(port); + this.waitAndAssertTracesClientSyncServerSync(port, "sayHello", 1); + } + + @Test + public void syncFastFramedClientSyncThreadedSelectorServerSayHello() throws TException { + int port = super.getPort(); + this.startSyncThreadedSelectorServer(port); + this.syncFastFramedClientSayHello(port); + this.waitAndAssertTracesClientSyncServerSync(port, "sayHello", 1); + } + + @Test + public void syncFramedClientSyncThreadedSelectorFastServerSayHello() throws TException { + int port = super.getPort(); + this.startSyncThreadedSelectorFastServer(port); + this.syncFramedClientSayHello(port); + this.waitAndAssertTracesClientSyncServerSync(port, "sayHello", 1); + } + + @Test + public void syncFastFramedClientSyncThreadedSelectorFastServerSayHello() throws TException { + int port = super.getPort(); + this.startSyncThreadedSelectorFastServer(port); + this.syncFastFramedClientSayHello(port); + this.waitAndAssertTracesClientSyncServerSync(port, "sayHello", 1); + } + + @Test + public void syncFramedClientSyncThreadedSelectorServerSayHelloMuti() throws TException { + int port = super.getPort(); + this.startSyncThreadedSelectorServer(port); + for (int i = 0; i < 5; ++i) { + this.syncFramedClientSayHello(port); + } + this.waitAndAssertTracesClientSyncServerSync(port, "sayHello", 5); + } + + @Test + public void syncFramedClientSyncThreadedSelectorServerSayHelloParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncThreadedSelectorServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncFramedClientSayHello(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncFramedClientSyncThreadedSelectorServerSayHelloParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerSync(port, "sayHello", threadCount); + } + + @Test + public void nonBlockClientAsyncThreadedSelectorServerSayHello() throws TException, IOException { + int port = super.getPort(); + this.startAsyncThreadedSelectorServer(port); + this.nonBlockClientSayHello(port); + this.waitAndAssertTracesClientAsyncServerAsync(port, "sayHello", 1); + } + + @Test + public void nonBlockClientAsyncThreadedSelectorServerSayHelloMuti() + throws TException, IOException { + int port = super.getPort(); + this.startAsyncThreadedSelectorServer(port); + for (int i = 0; i < 5; ++i) { + this.nonBlockClientSayHello(port); + } + this.waitAndAssertTracesClientAsyncServerAsync(port, "sayHello", 5); + } + + @Test + public void nonBlockClientAsyncThreadedSelectorServerSayHelloParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startAsyncThreadedSelectorServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.nonBlockClientSayHello(port); + } catch (IOException | TException e) { + count.incrementAndGet(); + Assertions.fail( + "nonBlockClientAsyncThreadedSelectorServerSayHelloParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientAsyncServerAsync(port, "sayHello", threadCount); + } + + @Test + public void nonBlockClientSyncThreadedSelectorServerSayHello() throws TException, IOException { + int port = super.getPort(); + this.startSyncThreadedSelectorServer(port); + this.nonBlockClientSayHello(port); + this.waitAndAssertTracesClientAsyncServerSync(port, "sayHello", 1); + } + + @Test + public void nonBlockClientSyncThreadedSelectorServerSayHelloMuti() + throws TException, IOException { + int port = super.getPort(); + this.startSyncThreadedSelectorServer(port); + for (int i = 0; i < 5; ++i) { + this.nonBlockClientSayHello(port); + } + this.waitAndAssertTracesClientAsyncServerSync(port, "sayHello", 5); + } + + @Test + public void nonBlockClientSyncThreadedSelectorServerSayHelloParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncThreadedSelectorServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.nonBlockClientSayHello(port); + } catch (IOException | TException e) { + count.incrementAndGet(); + Assertions.fail( + "nonBlockClientSyncThreadedSelectorServerSayHelloParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientAsyncServerSync(port, "sayHello", threadCount); + } + + @Test + public void syncFramedClientSyncNonblockingServerSayHello() throws TException { + int port = super.getPort(); + this.startSyncNonblockingServer(port); + this.syncFramedClientSayHello(port); + this.waitAndAssertTracesClientSyncServerSync(port, "sayHello", 1); + } + + @Test + public void syncFastFramedClientSyncNonblockingServerSayHello() throws TException { + int port = super.getPort(); + this.startSyncNonblockingServer(port); + this.syncFastFramedClientSayHello(port); + this.waitAndAssertTracesClientSyncServerSync(port, "sayHello", 1); + } + + @Test + public void syncFramedClientSyncNonblockingFastServerSayHello() throws TException { + int port = super.getPort(); + this.startSyncNonblockingFastServer(port); + this.syncFramedClientSayHello(port); + this.waitAndAssertTracesClientSyncServerSync(port, "sayHello", 1); + } + + @Test + public void syncFastFramedClientSyncNonblockingFastServerSayHello() throws TException { + int port = super.getPort(); + this.startSyncNonblockingFastServer(port); + this.syncFastFramedClientSayHello(port); + this.waitAndAssertTracesClientSyncServerSync(port, "sayHello", 1); + } + + @Test + public void syncFramedClientSyncNonblockingServerSayHelloMuti() throws TException { + int port = super.getPort(); + this.startSyncNonblockingServer(port); + for (int i = 0; i < 5; ++i) { + this.syncFramedClientSayHello(port); + } + this.waitAndAssertTracesClientSyncServerSync(port, "sayHello", 5); + } + + @Test + public void syncFramedClientSyncNonblockingServerSayHelloParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncNonblockingServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncFramedClientSayHello(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncFramedClientSyncNonblockingServerSayHelloParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerSync(port, "sayHello", threadCount); + } + + @Test + public void syncFramedClientSyncHsHaServerSayHello() throws TException { + int port = super.getPort(); + this.startSyncHsHaServer(port); + this.syncFramedClientSayHello(port); + this.waitAndAssertTracesClientSyncServerSync(port, "sayHello", 1); + } + + @Test + public void syncFastFramedClientSyncHsHaServerSayHello() throws TException { + int port = super.getPort(); + this.startSyncHsHaServer(port); + this.syncFastFramedClientSayHello(port); + this.waitAndAssertTracesClientSyncServerSync(port, "sayHello", 1); + } + + @Test + public void syncFramedClientSyncHsHaFastServerSayHello() throws TException { + int port = super.getPort(); + this.startSyncHsHaFastServer(port); + this.syncFramedClientSayHello(port); + this.waitAndAssertTracesClientSyncServerSync(port, "sayHello", 1); + } + + @Test + public void syncFastFramedClientSyncHsHaFastServerSayHello() throws TException { + int port = super.getPort(); + this.startSyncHsHaFastServer(port); + this.syncFastFramedClientSayHello(port); + this.waitAndAssertTracesClientSyncServerSync(port, "sayHello", 1); + } + + @Test + public void syncFramedClientSyncHsHaServerSayHelloMuti() throws TException { + int port = super.getPort(); + this.startSyncHsHaServer(port); + + for (int i = 0; i < 5; ++i) { + this.syncFramedClientSayHello(port); + } + + this.waitAndAssertTracesClientSyncServerSync(port, "sayHello", 5); + } + + @Test + public void syncFramedClientSyncHsHaServerSayHelloParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncHsHaServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncFramedClientSayHello(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncFramedClientSyncHsHaServerSayHelloParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerSync(port, "sayHello", threadCount); + } + + @Test + public void syncFramedClientAsyncNonblockingServerSayHello() throws TException { + int port = super.getPort(); + this.startAsyncNonblockingServer(port); + this.syncFramedClientSayHello(port); + this.waitAndAssertTracesClientSyncServerAsync(port, "sayHello", 1); + } + + @Test + public void syncFastFramedClientAsyncNonblockingServerSayHello() throws TException { + int port = super.getPort(); + this.startAsyncNonblockingServer(port); + this.syncFastFramedClientSayHello(port); + this.waitAndAssertTracesClientSyncServerAsync(port, "sayHello", 1); + } + + @Test + public void syncFramedClientAsyncNonblockingServerSayHelloMuti() throws TException { + int port = super.getPort(); + this.startAsyncNonblockingServer(port); + + for (int i = 0; i < 5; ++i) { + this.syncFramedClientSayHello(port); + } + + this.waitAndAssertTracesClientSyncServerAsync(port, "sayHello", 5); + } + + @Test + public void syncFramedClientAsyncNonblockingServerSayHelloParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startAsyncNonblockingServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncFramedClientSayHello(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncFramedClientAsyncNonblockingServerSayHelloParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerAsync(port, "sayHello", threadCount); + } + + @Test + public void syncFramedClientAsyncHsHaServerSayHello() throws TException { + int port = super.getPort(); + this.startAsyncHsHaServer(port); + this.syncFramedClientSayHello(port); + this.waitAndAssertTracesClientSyncServerAsync(port, "sayHello", 1); + } + + @Test + public void syncFastFramedClientAsyncHsHaServerSayHello() throws TException { + int port = super.getPort(); + this.startAsyncHsHaServer(port); + this.syncFastFramedClientSayHello(port); + this.waitAndAssertTracesClientSyncServerAsync(port, "sayHello", 1); + } + + @Test + public void syncFramedClientAsyncHsHaFastServerSayHello() throws TException { + int port = super.getPort(); + this.startAsyncHsHaFastServer(port); + this.syncFramedClientSayHello(port); + this.waitAndAssertTracesClientSyncServerAsync(port, "sayHello", 1); + } + + @Test + public void syncFastFramedClientAsyncHsHaFastServerSayHello() throws TException { + int port = super.getPort(); + this.startAsyncHsHaFastServer(port); + this.syncFastFramedClientSayHello(port); + this.waitAndAssertTracesClientSyncServerAsync(port, "sayHello", 1); + } + + @Test + public void syncFramedClientAsyncHsHaServerSayHelloMuti() throws TException { + int port = super.getPort(); + this.startAsyncHsHaServer(port); + + for (int i = 0; i < 5; ++i) { + this.syncFramedClientSayHello(port); + } + + this.waitAndAssertTracesClientSyncServerAsync(port, "sayHello", 5); + } + + @Test + public void syncFramedClientAsyncHsHaServerSayHelloParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startAsyncHsHaServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncFramedClientSayHello(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncFramedClientAsyncHsHaServerSayHelloParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerAsync(port, "sayHello", threadCount); + } + + @Test + public void nonBlockClientSyncNonblockingServerSayHello() throws TException, IOException { + int port = super.getPort(); + this.startSyncNonblockingServer(port); + this.nonBlockClientSayHello(port); + this.waitAndAssertTracesClientAsyncServerSync(port, "sayHello", 1); + } + + @Test + public void nonBlockClientSyncNonblockingServerSayHelloMuti() throws TException, IOException { + int port = super.getPort(); + this.startSyncNonblockingServer(port); + + for (int i = 0; i < 5; ++i) { + this.nonBlockClientSayHello(port); + } + + this.waitAndAssertTracesClientAsyncServerSync(port, "sayHello", 5); + } + + @Test + public void nonBlockClientSyncNonblockingServerSayHelloParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncNonblockingServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.nonBlockClientSayHello(port); + } catch (IOException | TException e) { + count.incrementAndGet(); + Assertions.fail( + "nonBlockClientSyncNonblockingServerSayHelloParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientAsyncServerSync(port, "sayHello", threadCount); + } + + @Test + public void nonBlockClientSyncHsHaServerSayHello() throws TException, IOException { + int port = super.getPort(); + this.startSyncHsHaServer(port); + this.nonBlockClientSayHello(port); + this.waitAndAssertTracesClientAsyncServerSync(port, "sayHello", 1); + } + + @Test + public void nonBlockClientSyncHsHaServerSayHelloMuti() throws TException, IOException { + int port = super.getPort(); + this.startSyncHsHaServer(port); + + for (int i = 0; i < 5; ++i) { + this.nonBlockClientSayHello(port); + } + + this.waitAndAssertTracesClientAsyncServerSync(port, "sayHello", 5); + } + + @Test + public void nonBlockClientSyncHsHaServerSayHelloParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncHsHaServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.nonBlockClientSayHello(port); + } catch (IOException | TException e) { + count.incrementAndGet(); + Assertions.fail( + "nonBlockClientSyncHsHaServerSayHelloParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientAsyncServerSync(port, "sayHello", threadCount); + } + + @Test + public void nonBlockClientAsyncNonblockingServerSayHello() throws TException, IOException { + int port = super.getPort(); + this.startAsyncNonblockingServer(port); + this.nonBlockClientSayHello(port); + this.waitAndAssertTracesClientAsyncServerAsync(port, "sayHello", 1); + } + + @Test + public void nonBlockClientAsyncNonblockingServerSayHelloMuti() throws TException, IOException { + int port = super.getPort(); + this.startAsyncNonblockingServer(port); + + for (int i = 0; i < 5; ++i) { + this.nonBlockClientSayHello(port); + } + + this.waitAndAssertTracesClientAsyncServerAsync(port, "sayHello", 5); + } + + @Test + public void nonBlockClientAsyncNonblockingServerSayHelloParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startAsyncNonblockingServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.nonBlockClientSayHello(port); + } catch (IOException | TException e) { + count.incrementAndGet(); + Assertions.fail( + "nonBlockClientAsyncNonblockingServerSayHelloParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientAsyncServerAsync(port, "sayHello", threadCount); + } + + @Test + public void nonBlockClientAsyncHsHaServerSayHello() throws TException, IOException { + int port = super.getPort(); + this.startAsyncHsHaServer(port); + this.nonBlockClientSayHello(port); + this.waitAndAssertTracesClientAsyncServerAsync(port, "sayHello", 1); + } + + @Test + public void nonBlockClientAsyncHsHaServerSayHelloMuti() throws TException, IOException { + int port = super.getPort(); + this.startAsyncHsHaServer(port); + + for (int i = 0; i < 5; ++i) { + this.nonBlockClientSayHello(port); + } + + this.waitAndAssertTracesClientAsyncServerAsync(port, "sayHello", 5); + } + + @Test + public void nonBlockClientAsyncHsHaServerSayHelloParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startAsyncHsHaServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.nonBlockClientSayHello(port); + } catch (IOException | TException e) { + count.incrementAndGet(); + Assertions.fail( + "nonBlockClientAsyncHsHaServerSayHelloParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientAsyncServerAsync(port, "sayHello", threadCount); + } + + public void syncClientSayHello(int port) throws TException { + TTransport transport = null; + try { + transport = new TSocket("localhost", port); + transport.open(); + TProtocol protocol = new TBinaryProtocol(transport); + ThriftService.Client client = new ThriftService.Client(protocol); + String response = this.testing().runWithSpan("parent", () -> client.sayHello("US", "Bob")); + assertThat(response).isEqualTo("Hello USs' Bob"); + } finally { + if (transport != null) { + transport.close(); + } + } + } + + public void syncClientMultiSayHello(int port) throws TException { + TTransport transport = null; + try { + transport = new TSocket("localhost", port); + transport.open(); + TProtocol protocol = new TBinaryProtocol(transport); + TMultiplexedProtocol multiplexedProtocol = + new TMultiplexedProtocol(protocol, "syncHelloWorld"); + ThriftService.Client client = new ThriftService.Client(multiplexedProtocol); + String response = this.testing().runWithSpan("parent", () -> client.sayHello("US", "Bob")); + assertThat(response).isEqualTo("Hello USs' Bob"); + } finally { + if (transport != null) { + transport.close(); + } + } + } + + public void nonBlockClientSayHello(int port) throws TException, IOException { + TNonblockingTransport transport = new TNonblockingSocket("localhost", port); + TAsyncClientManager clientManager = new TAsyncClientManager(); + TProtocolFactory protocolFactory = new TBinaryProtocol.Factory(); + ThriftService.AsyncClient.Factory factory = + new ThriftService.AsyncClient.Factory(clientManager, protocolFactory); + ThriftService.AsyncClient asyClient = factory.getAsyncClient(transport); + AsyncMethodCallback callback = + new AsyncMethodCallback() { + @Override + public void onComplete(ThriftService.AsyncClient.sayHello_call s) { + try { + String result = s.getResult(); + assertThat(result).isEqualTo("Hello USs' Bob"); + } catch (TException e) { + throw new VerifyException(e); + } + } + + @Override + public void onError(Exception e) { + assertThat(e.getMessage()).isEqualTo("Read call frame size failed"); + } + }; + this.testing().runWithSpan("parent", () -> asyClient.sayHello("US", "Bob", callback)); + } + + public void syncFramedClientSayHello(int port) throws TException { + TTransport transport = null; + try { + transport = new TSocket("localhost", port); + TFramedTransport framedTransport = new TFramedTransport(transport); + framedTransport.open(); + TProtocol protocol = new TBinaryProtocol(framedTransport); + ThriftService.Client client = new ThriftService.Client(protocol); + String response = this.testing().runWithSpan("parent", () -> client.sayHello("US", "Bob")); + assertThat(response).isEqualTo("Hello USs' Bob"); + } finally { + if (transport != null) { + transport.close(); + } + } + } + + public void syncFastFramedClientSayHello(int port) throws TException { + TTransport transport = null; + try { + transport = new TSocket("localhost", port); + TFastFramedTransport framedTransport = new TFastFramedTransport(transport); + framedTransport.open(); + TProtocol protocol = new TBinaryProtocol(framedTransport); + ThriftService.Client client = new ThriftService.Client(protocol); + String response = this.testing().runWithSpan("parent", () -> client.sayHello("US", "Bob")); + assertThat(response).isEqualTo("Hello USs' Bob"); + } finally { + if (transport != null) { + transport.close(); + } + } + } + + public void syncFramedClientMultiSayHello(int port) throws TException { + TTransport transport = null; + try { + transport = new TSocket("localhost", port); + TFramedTransport framedTransport = new TFramedTransport(transport); + framedTransport.open(); + TProtocol protocol = new TBinaryProtocol(framedTransport); + TMultiplexedProtocol multiplexedProtocol = + new TMultiplexedProtocol(protocol, "syncHelloWorld"); + ThriftService.Client client = new ThriftService.Client(multiplexedProtocol); + String response = this.testing().runWithSpan("parent", () -> client.sayHello("US", "Bob")); + assertThat(response).isEqualTo("Hello USs' Bob"); + } finally { + if (transport != null) { + transport.close(); + } + } + } +} diff --git a/instrumentation/thrift/thrift-0.9.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/ThriftBaseTest.java b/instrumentation/thrift/thrift-0.9.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/ThriftBaseTest.java new file mode 100644 index 000000000000..fd4e8fbcf352 --- /dev/null +++ b/instrumentation/thrift/thrift-0.9.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/ThriftBaseTest.java @@ -0,0 +1,902 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1; + +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies; + +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; +import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; +import io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.server.ThriftServiceAsyncImpl; +import io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.server.ThriftServiceImpl; +import io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.thrift.ThriftService; +import io.opentelemetry.sdk.testing.assertj.SpanDataAssert; +import io.opentelemetry.sdk.testing.assertj.TraceAssert; +import io.opentelemetry.sdk.trace.data.StatusData; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.Charset; +import java.util.Random; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.function.Consumer; +import java.util.logging.Logger; +import org.apache.thrift.TMultiplexedProcessor; +import org.apache.thrift.protocol.TBinaryProtocol; +import org.apache.thrift.server.THsHaServer; +import org.apache.thrift.server.TNonblockingServer; +import org.apache.thrift.server.TServer; +import org.apache.thrift.server.TSimpleServer; +import org.apache.thrift.server.TThreadPoolServer; +import org.apache.thrift.server.TThreadedSelectorServer; +import org.apache.thrift.transport.TFastFramedTransport; +import org.apache.thrift.transport.TFramedTransport; +import org.apache.thrift.transport.TNonblockingServerSocket; +import org.apache.thrift.transport.TNonblockingServerTransport; +import org.apache.thrift.transport.TServerSocket; +import org.apache.thrift.transport.TServerTransport; +import org.apache.thrift.transport.TTransportException; +import org.assertj.core.api.AbstractAssert; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.testcontainers.shaded.com.google.common.base.VerifyException; + +public abstract class ThriftBaseTest { + private static final Logger logger = Logger.getLogger(ThriftBaseTest.class.getName()); + public TServer server; + public int port = 13100; + + private static final String ASYNC_CLIENT = + "io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.thrift.ThriftService$AsyncClient"; + private static final String SYNC_CLIENT = + "io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.thrift.ThriftService$Client"; + private static final String ASYNC_SERVER = + "io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.server.ThriftServiceAsyncImpl"; + private static final String SYNC_SERVER = + "io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.server.ThriftServiceImpl"; + private static final String PEER_ADDR = "127.0.0.1"; + + private static final String TRANSPORT_EXCEPTION = + "org.apache.thrift.transport.TTransportException"; + private static final String VERIFY_EXCEPTION = + "org.testcontainers.shaded.com.google.common.base.VerifyException"; + private static final String IO_EXCEPTION = "java.io.IOException"; + + private static final AttributeKey RPC_METHOD = AttributeKey.stringKey("rpc.method"); + private static final AttributeKey RPC_SERVICE = AttributeKey.stringKey("rpc.service"); + private static final AttributeKey RPC_SYSTEM = AttributeKey.stringKey("rpc.system"); + + private static final String EXCEPTION_EVENT_NAME = "exception"; + private static final AttributeKey EXCEPTION_MESSAGE = + AttributeKey.stringKey("exception.message"); + private static final AttributeKey EXCEPTION_TYPE = + AttributeKey.stringKey("exception.type"); + + public static final AttributeKey NETWORK_PEER_ADDRESS = + AttributeKey.stringKey("network.peer.address"); + public static final AttributeKey NETWORK_PEER_PORT = + AttributeKey.longKey("network.peer.port"); + + @RegisterExtension + protected static InstrumentationExtension testing = AgentInstrumentationExtension.create(); + + protected InstrumentationExtension testing() { + return testing; + } + + @BeforeEach + public void before() { + ++this.port; + logger.info( + "before port=" + + this.port + + ", threadName=" + + Thread.currentThread().getName() + + ", threadId=" + + Thread.currentThread().getId()); + this.testing().clearData(); + } + + @AfterEach + public void after() { + this.stopServer(); + } + + public int getPort() { + Random random = new Random(); + int newPort = this.port + random.nextInt(2000); + while (portNotRelease(newPort)) { + newPort = this.port + random.nextInt(2000); + } + return newPort; + } + + public static boolean portNotRelease(int port) { + Process process = null; + String pid = null; + try { + process = Runtime.getRuntime().exec("lsof -ti:" + port); + BufferedReader reader = + new BufferedReader( + new InputStreamReader(process.getInputStream(), Charset.defaultCharset())); + pid = reader.readLine(); + } catch (IOException e) { + throw new VerifyException(e); + } + return pid != null && !pid.isEmpty(); + } + + public void startSyncSimpleServer(int port) throws TTransportException { + ThriftServiceImpl impl = new ThriftServiceImpl(); + ThriftService.Processor processor = + new ThriftService.Processor(impl); + TServerTransport serverTransport = new TServerSocket(port); + this.server = new TSimpleServer(new TServer.Args(serverTransport).processor(processor)); + new Thread( + () -> { + logger.info( + "Starting startSyncSimpleServer threadName=" + + Thread.currentThread().getName() + + ", threadId=" + + Thread.currentThread().getId()); + this.server.serve(); + }) + .start(); + } + + public void startMultiSimpleServer(int port) throws TTransportException { + ThriftServiceImpl syncImpl = new ThriftServiceImpl(); + ThriftService.Processor syncProcessor = + new ThriftService.Processor(syncImpl); + ThriftServiceAsyncImpl asyncImpl = new ThriftServiceAsyncImpl(); + ThriftService.AsyncProcessor asyncProcessor = + new ThriftService.AsyncProcessor(asyncImpl); + TMultiplexedProcessor multiplexedProcessor = new TMultiplexedProcessor(); + multiplexedProcessor.registerProcessor("syncHelloWorld", syncProcessor); + multiplexedProcessor.registerProcessor("asyncHelloWorld", asyncProcessor); + TServerTransport serverTransport = new TServerSocket(port); + this.server = + new TSimpleServer(new TServer.Args(serverTransport).processor(multiplexedProcessor)); + new Thread( + () -> { + logger.info( + "Starting startMultiSimpleServer threadName=" + + Thread.currentThread().getName() + + ", threadId=" + + Thread.currentThread().getId()); + this.server.serve(); + }) + .start(); + } + + public void startMultiThreadedSelectorServer(int port) throws TTransportException { + ThriftServiceImpl syncImpl = new ThriftServiceImpl(); + ThriftService.Processor syncProcessor = + new ThriftService.Processor(syncImpl); + ThriftServiceAsyncImpl asyncImpl = new ThriftServiceAsyncImpl(); + ThriftService.AsyncProcessor asyncProcessor = + new ThriftService.AsyncProcessor(asyncImpl); + TMultiplexedProcessor multiplexedProcessor = new TMultiplexedProcessor(); + multiplexedProcessor.registerProcessor("syncHelloWorld", syncProcessor); + multiplexedProcessor.registerProcessor("asyncHelloWorld", asyncProcessor); + TNonblockingServerTransport transport = new TNonblockingServerSocket(port); + TThreadedSelectorServer.Args serverArgs = + new TThreadedSelectorServer.Args(transport) + .selectorThreads(5) + .workerThreads(10) + .acceptQueueSizePerThread(20) + .processor(multiplexedProcessor); + this.server = new TThreadedSelectorServer(serverArgs); + new Thread( + () -> { + logger.info( + "Starting startMultiThreadedSelectorServer threadName=" + + Thread.currentThread().getName() + + ", threadId=" + + Thread.currentThread().getId()); + this.server.serve(); + }) + .start(); + } + + public void startSyncThreadedSelectorServer(int port) throws TTransportException { + ThriftServiceImpl impl = new ThriftServiceImpl(); + ThriftService.Processor processor = + new ThriftService.Processor(impl); + TNonblockingServerTransport transport = new TNonblockingServerSocket(port); + TThreadedSelectorServer.Args serverArgs = + new TThreadedSelectorServer.Args(transport) + .selectorThreads(5) + .workerThreads(10) + .acceptQueueSizePerThread(20) + .processor(processor); + this.server = new TThreadedSelectorServer(serverArgs); + new Thread( + () -> { + logger.info( + "Starting startAsyncServer threadName=" + + Thread.currentThread().getName() + + ", threadId=" + + Thread.currentThread().getId()); + this.server.serve(); + }) + .start(); + } + + public void startSyncThreadedSelectorFastServer(int port) throws TTransportException { + ThriftServiceImpl impl = new ThriftServiceImpl(); + ThriftService.Processor processor = + new ThriftService.Processor(impl); + TNonblockingServerTransport transport = new TNonblockingServerSocket(port); + TThreadedSelectorServer.Args serverArgs = + new TThreadedSelectorServer.Args(transport) + .selectorThreads(5) + .workerThreads(10) + .acceptQueueSizePerThread(20) + .processor(processor) + .transportFactory(new TFastFramedTransport.Factory()); + this.server = new TThreadedSelectorServer(serverArgs); + new Thread( + () -> { + logger.info( + "Starting startAsyncServer threadName=" + + Thread.currentThread().getName() + + ", threadId=" + + Thread.currentThread().getId()); + this.server.serve(); + }) + .start(); + } + + public void startAsyncThreadedSelectorServer(int port) throws TTransportException { + ThriftServiceAsyncImpl impl = new ThriftServiceAsyncImpl(); + ThriftService.AsyncProcessor processor = + new ThriftService.AsyncProcessor(impl); + TNonblockingServerTransport transport = new TNonblockingServerSocket(port); + TThreadedSelectorServer.Args serverArgs = + new TThreadedSelectorServer.Args(transport) + .selectorThreads(5) + .workerThreads(10) + .acceptQueueSizePerThread(20) + .processor(processor); + this.server = new TThreadedSelectorServer(serverArgs); + new Thread( + () -> { + logger.info( + "Starting startNonBlockingServer threadName=" + + Thread.currentThread().getName() + + ", threadId=" + + Thread.currentThread().getId()); + this.server.serve(); + }) + .start(); + } + + public void startAsyncThreadedSelectorFastServer(int port) throws TTransportException { + ThriftServiceAsyncImpl impl = new ThriftServiceAsyncImpl(); + ThriftService.AsyncProcessor processor = + new ThriftService.AsyncProcessor(impl); + TNonblockingServerTransport transport = new TNonblockingServerSocket(port); + TThreadedSelectorServer.Args serverArgs = + new TThreadedSelectorServer.Args(transport) + .selectorThreads(5) + .workerThreads(10) + .acceptQueueSizePerThread(20) + .processor(processor) + .transportFactory(new TFastFramedTransport.Factory()); + this.server = new TThreadedSelectorServer(serverArgs); + new Thread( + () -> { + logger.info( + "Starting startNonBlockingServer threadName=" + + Thread.currentThread().getName() + + ", threadId=" + + Thread.currentThread().getId()); + this.server.serve(); + }) + .start(); + } + + public void startSyncNonblockingServer(int port) throws TTransportException { + ThriftServiceImpl impl = new ThriftServiceImpl(); + ThriftService.Processor processor = + new ThriftService.Processor(impl); + TNonblockingServerTransport transport = new TNonblockingServerSocket(port); + TNonblockingServer.Args serverArgs = + new TNonblockingServer.Args(transport).processor(processor); + this.server = new TNonblockingServer(serverArgs); + new Thread( + () -> { + logger.info( + "Starting startNonBlockingServer threadName=" + + Thread.currentThread().getName() + + ", threadId=" + + Thread.currentThread().getId()); + this.server.serve(); + }) + .start(); + } + + public void startSyncNonblockingFastServer(int port) throws TTransportException { + ThriftServiceImpl impl = new ThriftServiceImpl(); + ThriftService.Processor processor = + new ThriftService.Processor(impl); + TNonblockingServerTransport transport = new TNonblockingServerSocket(port); + TNonblockingServer.Args serverArgs = + new TNonblockingServer.Args(transport) + .processor(processor) + .transportFactory(new TFastFramedTransport.Factory()) + .protocolFactory(new TBinaryProtocol.Factory()); + this.server = new TNonblockingServer(serverArgs); + new Thread( + () -> { + logger.info( + "Starting startNonBlockingServer threadName=" + + Thread.currentThread().getName() + + ", threadId=" + + Thread.currentThread().getId()); + this.server.serve(); + }) + .start(); + } + + public void startAsyncNonblockingServer(int port) throws TTransportException { + ThriftServiceAsyncImpl impl = new ThriftServiceAsyncImpl(); + ThriftService.AsyncProcessor processor = + new ThriftService.AsyncProcessor(impl); + TNonblockingServerTransport transport = new TNonblockingServerSocket(port); + TNonblockingServer.Args serverArgs = + new TNonblockingServer.Args(transport).processor(processor); + this.server = new TNonblockingServer(serverArgs); + new Thread( + () -> { + logger.info( + "Starting startNonBlockingServer threadName=" + + Thread.currentThread().getName() + + ", threadId=" + + Thread.currentThread().getId()); + this.server.serve(); + }) + .start(); + } + + public void startSyncThreadPoolServer(int port) throws TTransportException { + ThriftServiceImpl impl = new ThriftServiceImpl(); + ThriftService.Processor processor = + new ThriftService.Processor(impl); + TServerSocket transport = new TServerSocket(port); + ExecutorService executor = Executors.newFixedThreadPool(5); + TThreadPoolServer.Args serverArgs = + new TThreadPoolServer.Args(transport).executorService(executor).processor(processor); + TServer server = new TThreadPoolServer(serverArgs); + new Thread( + () -> { + logger.info( + "Starting startSyncThreadPoolServer threadName=" + + Thread.currentThread().getName() + + ", threadId=" + + Thread.currentThread().getId()); + server.serve(); + }) + .start(); + } + + public void startSyncHsHaServer(int port) throws TTransportException { + ThriftServiceImpl impl = new ThriftServiceImpl(); + ThriftService.Processor processor = + new ThriftService.Processor(impl); + TNonblockingServerTransport transport = new TNonblockingServerSocket(port); + TBinaryProtocol.Factory protocolFactory = new TBinaryProtocol.Factory(); + TFramedTransport.Factory transportFactory = new TFramedTransport.Factory(); + THsHaServer.Args serverArgs = + new THsHaServer.Args(transport) + .processor(processor) + .protocolFactory(protocolFactory) + .transportFactory(transportFactory); + this.server = new THsHaServer(serverArgs); + new Thread( + () -> { + logger.info( + "Starting startSyncTHsHaServer threadName=" + + Thread.currentThread().getName() + + ", threadId=" + + Thread.currentThread().getId()); + this.server.serve(); + }) + .start(); + } + + public void startSyncHsHaFastServer(int port) throws TTransportException { + ThriftServiceImpl impl = new ThriftServiceImpl(); + ThriftService.Processor processor = + new ThriftService.Processor(impl); + TNonblockingServerTransport transport = new TNonblockingServerSocket(port); + TBinaryProtocol.Factory protocolFactory = new TBinaryProtocol.Factory(); + TFastFramedTransport.Factory transportFactory = new TFastFramedTransport.Factory(); + THsHaServer.Args serverArgs = + new THsHaServer.Args(transport) + .processor(processor) + .protocolFactory(protocolFactory) + .transportFactory(transportFactory); + this.server = new THsHaServer(serverArgs); + new Thread( + () -> { + logger.info( + "Starting startSyncTHsHaServer threadName=" + + Thread.currentThread().getName() + + ", threadId=" + + Thread.currentThread().getId()); + this.server.serve(); + }) + .start(); + } + + public void startAsyncHsHaServer(int port) throws TTransportException { + ThriftServiceAsyncImpl impl = new ThriftServiceAsyncImpl(); + ThriftService.AsyncProcessor processor = + new ThriftService.AsyncProcessor(impl); + TNonblockingServerTransport transport = new TNonblockingServerSocket(port); + TBinaryProtocol.Factory protocolFactory = new TBinaryProtocol.Factory(); + TFramedTransport.Factory transportFactory = new TFramedTransport.Factory(); + THsHaServer.Args serverArgs = + new THsHaServer.Args(transport) + .processor(processor) + .protocolFactory(protocolFactory) + .transportFactory(transportFactory); + this.server = new THsHaServer(serverArgs); + new Thread( + () -> { + logger.info( + "Starting startAsyncTHsHaServer threadName=" + + Thread.currentThread().getName() + + ", threadId=" + + Thread.currentThread().getId()); + this.server.serve(); + }) + .start(); + } + + public void startAsyncHsHaFastServer(int port) throws TTransportException { + ThriftServiceAsyncImpl impl = new ThriftServiceAsyncImpl(); + ThriftService.AsyncProcessor processor = + new ThriftService.AsyncProcessor(impl); + TNonblockingServerTransport transport = new TNonblockingServerSocket(port); + TBinaryProtocol.Factory protocolFactory = new TBinaryProtocol.Factory(); + TFastFramedTransport.Factory transportFactory = new TFastFramedTransport.Factory(); + THsHaServer.Args serverArgs = + new THsHaServer.Args(transport) + .processor(processor) + .protocolFactory(protocolFactory) + .transportFactory(transportFactory); + this.server = new THsHaServer(serverArgs); + new Thread( + () -> { + logger.info( + "Starting startAsyncTHsHaServer threadName=" + + Thread.currentThread().getName() + + ", threadId=" + + Thread.currentThread().getId()); + this.server.serve(); + }) + .start(); + } + + public void stopServer() { + if (this.server != null) { + this.server.stop(); + } + } + + public void waitAndAssertTracesClientSyncServerSync(int peerPort, String method, int count) { + this.baseWaitAndAssertTraces( + method, + method, + count, + SYNC_CLIENT, + StatusData.unset(), + peerPort, + PEER_ADDR, + null, + null, + SYNC_SERVER, + StatusData.unset(), + null, + null); + } + + public void waitAndAssertTracesClientSyncServerSync( + int peerPort, String clientMethod, String serverMethod, int count) { + this.baseWaitAndAssertTraces( + clientMethod, + serverMethod, + count, + SYNC_CLIENT, + StatusData.unset(), + peerPort, + PEER_ADDR, + null, + null, + SYNC_SERVER, + StatusData.unset(), + null, + null); + } + + public void waitAndAssertTracesClientSyncServerSyncWithError( + int peerPort, String method, int count) { + this.baseWaitAndAssertTraces( + method, + method, + count, + SYNC_CLIENT, + StatusData.error(), + peerPort, + PEER_ADDR, + new Object[] {null, "Internal error processing " + method}, + TRANSPORT_EXCEPTION, + SYNC_SERVER, + StatusData.error(), + new Object[] {"fail"}, + VERIFY_EXCEPTION); + } + + public void waitAndAssertTracesClientSyncServerSyncWithError( + int peerPort, String clientMethod, String serverMethod, int count) { + this.baseWaitAndAssertTraces( + clientMethod, + serverMethod, + count, + SYNC_CLIENT, + StatusData.error(), + peerPort, + PEER_ADDR, + new Object[] {null, "Internal error processing " + clientMethod}, + TRANSPORT_EXCEPTION, + SYNC_SERVER, + StatusData.error(), + new Object[] {"fail"}, + VERIFY_EXCEPTION); + } + + public void waitAndAssertTracesClientSyncServerSyncOnewayError( + int peerPort, String method, int count) { + this.baseWaitAndAssertTraces( + method, + method, + count, + SYNC_CLIENT, + StatusData.unset(), + peerPort, + PEER_ADDR, + null, + null, + SYNC_SERVER, + StatusData.error(), + new Object[] {"fail"}, + VERIFY_EXCEPTION); + } + + public void waitAndAssertTracesClientSyncServerSyncOnewayError( + int peerPort, String clientMethod, String serverMethod, int count) { + this.baseWaitAndAssertTraces( + clientMethod, + serverMethod, + count, + SYNC_CLIENT, + StatusData.unset(), + peerPort, + PEER_ADDR, + null, + null, + SYNC_SERVER, + StatusData.error(), + new Object[] {"fail"}, + VERIFY_EXCEPTION); + } + + public void waitAndAssertTracesClientAsyncServerAsync(int peerPort, String method, int count) { + this.baseWaitAndAssertTraces( + method, + method, + count, + ASYNC_CLIENT, + StatusData.unset(), + peerPort, + PEER_ADDR, + null, + null, + ASYNC_SERVER, + StatusData.unset(), + null, + null); + } + + public void waitAndAssertTracesClientAsyncServerAsyncError( + int peerPort, String method, int count) { + this.baseWaitAndAssertTraces( + method, + method, + count, + ASYNC_CLIENT, + StatusData.unset(), + peerPort, + PEER_ADDR, + null, + null, + ASYNC_SERVER, + StatusData.error(), + new Object[] {"fail"}, + VERIFY_EXCEPTION); + } + + public void waitAndAssertTracesClientAsyncServerAsyncWithError( + int peerPort, String method, int count) { + this.baseWaitAndAssertTraces( + method, + method, + count, + ASYNC_CLIENT, + StatusData.error(), + peerPort, + PEER_ADDR, + new Object[] {"Read call frame size failed", "fail"}, + IO_EXCEPTION, + ASYNC_SERVER, + StatusData.error(), + new Object[] {"Read call frame size failed", "fail"}, + VERIFY_EXCEPTION); + } + + public void waitAndAssertTracesClientAsyncServerSync(int peerPort, String method, int count) { + this.baseWaitAndAssertTraces( + method, + method, + count, + ASYNC_CLIENT, + StatusData.unset(), + peerPort, + PEER_ADDR, + null, + null, + SYNC_SERVER, + StatusData.unset(), + null, + null); + } + + public void waitAndAssertTracesClientAsyncServerSyncWithError( + int peerPort, String method, int count) { + this.baseWaitAndAssertTraces( + method, + method, + count, + ASYNC_CLIENT, + StatusData.error(), + peerPort, + PEER_ADDR, + new Object[] {"Read call frame size failed", "Internal error processing " + method}, + IO_EXCEPTION, + SYNC_SERVER, + StatusData.error(), + new Object[] {"fail"}, + VERIFY_EXCEPTION); + } + + public void waitAndAssertTracesClientAsyncServerSyncOnewayError( + int peerPort, String method, int count) { + this.baseWaitAndAssertTraces( + method, + method, + count, + ASYNC_CLIENT, + StatusData.unset(), + peerPort, + PEER_ADDR, + null, + null, + SYNC_SERVER, + StatusData.error(), + new Object[] {"fail"}, + VERIFY_EXCEPTION); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) // 测试代码 + public void waitAndAssertTracesClientSyncServerAsync(int peerPort, String method, int count) { + this.baseWaitAndAssertTraces( + method, + method, + count, + SYNC_CLIENT, + StatusData.unset(), + peerPort, + PEER_ADDR, + null, + null, + ASYNC_SERVER, + StatusData.unset(), + null, + null); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) // 测试代码 + public void waitAndAssertTracesClientSyncServerAsyncError( + int peerPort, String method, int count) { + this.baseWaitAndAssertTraces( + method, + method, + count, + SYNC_CLIENT, + StatusData.unset(), + peerPort, + PEER_ADDR, + null, + null, + ASYNC_SERVER, + StatusData.error(), + new Object[] {"fail"}, + VERIFY_EXCEPTION); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + public void waitAndAssertTracesClientSyncServerAsyncWithError( + int peerPort, String method, int count) { + this.baseWaitAndAssertTraces( + method, + method, + count, + SYNC_CLIENT, + StatusData.error(), + peerPort, + PEER_ADDR, + new Object[] {null, "fail"}, + TRANSPORT_EXCEPTION, + ASYNC_SERVER, + StatusData.error(), + new Object[] {"fail"}, + VERIFY_EXCEPTION); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + private void baseWaitAndAssertTraces( + String clientMethod, + String serverMethod, + int count, + String clientClass, + StatusData clientStatus, + int peerPort, + String peerAddr, + Object[] clientErrMsg, + String clientErrorType, + String serverClass, + StatusData serverStatus, + Object[] serverErrMsg, + String serverErrorType) { + Consumer[] consumers = new Consumer[count]; + Consumer traceAssertConsumer; + if (serverClass == null) { + traceAssertConsumer = + trace -> + trace.hasSpansSatisfyingExactly( + span -> span.hasName("parent").hasKind(SpanKind.INTERNAL).hasNoParent(), + clientSpanDataAssertConsumer( + clientMethod, + clientClass, + clientStatus, + trace, + peerPort, + peerAddr, + clientErrMsg, + clientErrorType)); + } else { + traceAssertConsumer = + trace -> + trace.hasSpansSatisfyingExactly( + span -> span.hasName("parent").hasKind(SpanKind.INTERNAL).hasNoParent(), + clientSpanDataAssertConsumer( + clientMethod, + clientClass, + clientStatus, + trace, + peerPort, + peerAddr, + clientErrMsg, + clientErrorType), + serverSpanDataAssertConsumer( + serverMethod, + serverClass, + serverStatus, + trace, + serverErrMsg, + serverErrorType)); + } + + for (int i = 0; i < count; ++i) { + consumers[i] = traceAssertConsumer; + } + this.testing().waitAndAssertTraces(consumers); + } + + @SuppressWarnings({"ReturnValueIgnored"}) + private static Consumer clientSpanDataAssertConsumer( + String clientMethod, + String clientClass, + StatusData statusData, + TraceAssert trace, + int peerPort, + String peerAddr, + Object[] errMsg, + String errorType) { + Consumer consumer = + span -> + span.hasName(clientMethod) + .hasKind(SpanKind.CLIENT) + .hasParent(trace.getSpan(0)) + .hasStatus(statusData) + .hasAttributesSatisfying( + equalTo(NETWORK_PEER_PORT, peerPort), + equalTo(NETWORK_PEER_ADDRESS, peerAddr), + equalTo(RPC_SYSTEM, "thrift"), + equalTo(RPC_SERVICE, clientClass), + equalTo(RPC_METHOD, clientMethod)); + if (statusData == StatusData.error()) { + consumer = + consumer.andThen( + span -> + span.hasEventsSatisfyingExactly( + event -> + event + .hasName(EXCEPTION_EVENT_NAME) + .hasAttributesSatisfyingExactly( + satisfies(EXCEPTION_MESSAGE, val -> val.isIn(errMsg)), + satisfies( + AttributeKey.stringKey("exception.stacktrace"), + AbstractAssert::isNotNull), + equalTo(EXCEPTION_TYPE, errorType)))); + } + return consumer; + } + + @SuppressWarnings({"ReturnValueIgnored"}) + private static Consumer serverSpanDataAssertConsumer( + String serverMethod, + String serverClass, + StatusData statusData, + TraceAssert trace, + Object[] errMsg, + String errorType) { + Consumer consumer = + span -> + span.hasName(serverMethod) + .hasKind(SpanKind.SERVER) + .hasParent(trace.getSpan(1)) + .hasStatus(statusData) + .hasAttributesSatisfying( + equalTo(NETWORK_PEER_ADDRESS, "127.0.0.1"), + equalTo(RPC_SYSTEM, "thrift"), + equalTo(RPC_SERVICE, serverClass), + equalTo(RPC_METHOD, serverMethod)); + if (statusData == StatusData.error()) { + consumer = + consumer.andThen( + span -> + span.hasEventsSatisfyingExactly( + event -> + event + .hasName(EXCEPTION_EVENT_NAME) + .hasAttributesSatisfyingExactly( + satisfies(EXCEPTION_MESSAGE, val -> val.isIn(errMsg)), + satisfies( + AttributeKey.stringKey("exception.stacktrace"), + AbstractAssert::isNotNull), + equalTo(EXCEPTION_TYPE, errorType)))); + } + return consumer; + } +} diff --git a/instrumentation/thrift/thrift-0.9.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/WithErrorTest.java b/instrumentation/thrift/thrift-0.9.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/WithErrorTest.java new file mode 100644 index 000000000000..6c70af7a1983 --- /dev/null +++ b/instrumentation/thrift/thrift-0.9.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/WithErrorTest.java @@ -0,0 +1,961 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.thrift.ThriftService; +import java.io.IOException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import org.apache.thrift.TException; +import org.apache.thrift.async.AsyncMethodCallback; +import org.apache.thrift.async.TAsyncClientManager; +import org.apache.thrift.protocol.TBinaryProtocol; +import org.apache.thrift.protocol.TMultiplexedProtocol; +import org.apache.thrift.protocol.TProtocol; +import org.apache.thrift.protocol.TProtocolFactory; +import org.apache.thrift.transport.TFramedTransport; +import org.apache.thrift.transport.TNonblockingSocket; +import org.apache.thrift.transport.TNonblockingTransport; +import org.apache.thrift.transport.TSocket; +import org.apache.thrift.transport.TTransport; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; +import org.testcontainers.shaded.com.google.common.base.VerifyException; + +public class WithErrorTest extends ThriftBaseTest { + + @Test + public void syncClientSyncSimpleServerWithError() throws TException { + int port = super.getPort(); + this.startSyncSimpleServer(port); + this.syncClientWithError(port); + this.waitAndAssertTracesClientSyncServerSyncWithError(port, "withError", 1); + } + + @Test + public void syncClientSyncSimpleServerWithErrorMuti() throws TException { + int port = super.getPort(); + this.startSyncSimpleServer(port); + for (int i = 0; i < 5; ++i) { + this.syncClientWithError(port); + } + this.waitAndAssertTracesClientSyncServerSyncWithError(port, "withError", 5); + } + + @Test + public void syncClientSyncSimpleServerWithErrorParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncSimpleServer(port); + AtomicInteger count = new AtomicInteger(0); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncClientWithError(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncClientSimpleServerWithErrorParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + latch.await(); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerSyncWithError(port, "withError", threadCount); + } + + @Test + public void syncClientSyncThreadPoolServerWithError() throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncThreadPoolServer(port); + this.syncClientWithError(port); + this.waitAndAssertTracesClientSyncServerSyncWithError(port, "withError", 1); + } + + @Test + public void syncClientSyncThreadPoolServerWithErrorMuti() throws TException { + int port = super.getPort(); + this.startSyncThreadPoolServer(port); + for (int i = 0; i < 5; ++i) { + this.syncClientWithError(port); + } + this.waitAndAssertTracesClientSyncServerSyncWithError(port, "withError", 5); + } + + @Test + public void syncClientSyncThreadPoolServerWithErrorParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncThreadPoolServer(port); + AtomicInteger count = new AtomicInteger(0); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncClientWithError(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncClientSimpleServerWithErrorParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + latch.await(); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerSyncWithError(port, "withError", threadCount); + } + + @Test + public void syncClientMutiSyncSimpleServerWithError() throws TException { + int port = super.getPort(); + this.startMultiSimpleServer(port); + this.syncClientMultiWithError(port); + this.waitAndAssertTracesClientSyncServerSyncWithError( + port, "withError", "syncHelloWorld:withError", 1); + } + + @Test + public void syncClientMutiSyncSimpleServerWithErrorMuti() throws TException { + int port = super.getPort(); + this.startMultiSimpleServer(port); + for (int i = 0; i < 5; ++i) { + this.syncClientMultiWithError(port); + } + this.waitAndAssertTracesClientSyncServerSyncWithError( + port, "withError", "syncHelloWorld:withError", 5); + } + + @Test + public void syncClientMutiSyncSimpleServerWithErrorParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startMultiSimpleServer(port); + AtomicInteger count = new AtomicInteger(0); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncClientMultiWithError(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncClientSimpleServerWithErrorParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + latch.await(); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerSyncWithError( + port, "withError", "syncHelloWorld:withError", threadCount); + } + + @Test + public void syncFramedClientAsyncThreadedSelectorServerWithError() throws TException { + int port = super.getPort(); + this.startAsyncThreadedSelectorServer(port); + this.syncFramedClientWithError(port); + this.waitAndAssertTracesClientSyncServerAsyncWithError(port, "withError", 1); + } + + @Test + public void syncFramedClientAsyncThreadedSelectorServerWithErrorMuti() throws TException { + int port = super.getPort(); + this.startAsyncThreadedSelectorServer(port); + + for (int i = 0; i < 5; ++i) { + this.syncFramedClientWithError(port); + } + + this.waitAndAssertTracesClientSyncServerAsyncWithError(port, "withError", 5); + } + + @Test + public void syncFramedClientAsyncThreadedSelectorServerWithErrorParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startAsyncThreadedSelectorServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncFramedClientWithError(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncFramedClientAsyncThreadedSelectorServerWithErrorParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerAsyncWithError(port, "withError", threadCount); + } + + @Test + public void syncFramedClientAsyncMutiThreadedSelectorServerWithError() throws TException { + int port = super.getPort(); + this.startMultiThreadedSelectorServer(port); + this.syncFramedClientMultiWithError(port); + this.waitAndAssertTracesClientSyncServerSyncWithError( + port, "withError", "syncHelloWorld:withError", 1); + } + + @Test + public void syncFramedClientAsyncMutiThreadedSelectorServerWithErrorMuti() throws TException { + int port = super.getPort(); + this.startMultiThreadedSelectorServer(port); + + for (int i = 0; i < 5; ++i) { + this.syncFramedClientMultiWithError(port); + } + + this.waitAndAssertTracesClientSyncServerSyncWithError( + port, "withError", "syncHelloWorld:withError", 5); + } + + @Test + public void syncFramedClientAsyncMutiThreadedSelectorServerWithErrorParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startMultiThreadedSelectorServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncFramedClientMultiWithError(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncFramedClientAsyncThreadedSelectorServerWithErrorParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerSyncWithError( + port, "withError", "syncHelloWorld:withError", threadCount); + } + + @Test + public void syncFramedClientSyncThreadedSelectorServerWithError() throws TException { + int port = super.getPort(); + this.startSyncThreadedSelectorServer(port); + this.syncFramedClientWithError(port); + this.waitAndAssertTracesClientSyncServerSyncWithError(port, "withError", 1); + } + + @Test + public void syncFramedClientSyncThreadedSelectorServerWithErrorMuti() throws TException { + int port = super.getPort(); + this.startSyncThreadedSelectorServer(port); + + for (int i = 0; i < 5; ++i) { + this.syncFramedClientWithError(port); + } + + this.waitAndAssertTracesClientSyncServerSyncWithError(port, "withError", 5); + } + + @Test + public void syncFramedClientSyncThreadedSelectorServerWithErrorParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncThreadedSelectorServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncFramedClientWithError(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncFramedClientSyncThreadedSelectorServerWithErrorParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerSyncWithError(port, "withError", threadCount); + } + + @Test + public void nonBlockClientAsyncThreadedSelectorServerWithError() throws TException, IOException { + int port = super.getPort(); + this.startAsyncThreadedSelectorServer(port); + this.nonBlockClientWithError(port); + this.waitAndAssertTracesClientAsyncServerAsyncWithError(port, "withError", 1); + } + + @Test + public void nonBlockClientAsyncThreadedSelectorServerWithErrorMuti() + throws TException, IOException { + int port = super.getPort(); + this.startAsyncThreadedSelectorServer(port); + + for (int i = 0; i < 5; ++i) { + this.nonBlockClientWithError(port); + } + + this.waitAndAssertTracesClientAsyncServerAsyncWithError(port, "withError", 5); + } + + @Test + public void nonBlockClientAsyncThreadedSelectorServerWithErrorParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startAsyncThreadedSelectorServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.nonBlockClientWithError(port); + } catch (IOException | TException e) { + count.incrementAndGet(); + Assertions.fail( + "nonBlockClientAsyncThreadedSelectorServerWithErrorParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientAsyncServerAsyncWithError(port, "withError", threadCount); + } + + @Test + public void nonBlockClientSyncThreadedSelectorServerWithError() throws TException, IOException { + int port = super.getPort(); + this.startSyncThreadedSelectorServer(port); + this.nonBlockClientWithError(port); + this.waitAndAssertTracesClientAsyncServerSyncWithError(port, "withError", 1); + } + + @Test + public void nonBlockClientSyncThreadedSelectorServerWithErrorMuti() + throws TException, IOException { + int port = super.getPort(); + this.startSyncThreadedSelectorServer(port); + + for (int i = 0; i < 5; ++i) { + this.nonBlockClientWithError(port); + } + + this.waitAndAssertTracesClientAsyncServerSyncWithError(port, "withError", 5); + } + + @Test + public void nonBlockClientSyncThreadedSelectorServerWithErrorParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncThreadedSelectorServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.nonBlockClientWithError(port); + } catch (IOException | TException e) { + count.incrementAndGet(); + Assertions.fail( + "nonBlockClientSyncThreadedSelectorServerWithErrorParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientAsyncServerSyncWithError(port, "withError", threadCount); + } + + @Test + public void syncFramedClientSyncNonblockingServerWithError() throws TException { + int port = super.getPort(); + this.startSyncNonblockingServer(port); + this.syncFramedClientWithError(port); + this.waitAndAssertTracesClientSyncServerSyncWithError(port, "withError", 1); + } + + @Test + public void syncFramedClientSyncNonblockingServerWithErrorMuti() throws TException { + int port = super.getPort(); + this.startSyncNonblockingServer(port); + + for (int i = 0; i < 5; ++i) { + this.syncFramedClientWithError(port); + } + + this.waitAndAssertTracesClientSyncServerSyncWithError(port, "withError", 5); + } + + @Test + public void syncFramedClientSyncNonblockingServerWithErrorParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncNonblockingServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncFramedClientWithError(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncFramedClientSyncNonblockingServerWithErrorParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerSyncWithError(port, "withError", threadCount); + } + + @Test + public void syncFramedClientSyncHsHaServerWithError() throws TException { + int port = super.getPort(); + this.startSyncHsHaServer(port); + this.syncFramedClientWithError(port); + this.waitAndAssertTracesClientSyncServerSyncWithError(port, "withError", 1); + } + + @Test + public void syncFramedClientSyncHsHaServerWithErrorMuti() throws TException { + int port = super.getPort(); + this.startSyncHsHaServer(port); + + for (int i = 0; i < 5; ++i) { + this.syncFramedClientWithError(port); + } + + this.waitAndAssertTracesClientSyncServerSyncWithError(port, "withError", 5); + } + + @Test + public void syncFramedClientSyncHsHaServerWithErrorParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncHsHaServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncFramedClientWithError(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncFramedClientSyncHsHaServerWithErrorParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerSyncWithError(port, "withError", threadCount); + } + + @Test + public void syncFramedClientAsyncNonblockingServerWithError() throws TException { + int port = super.getPort(); + this.startAsyncNonblockingServer(port); + this.syncFramedClientWithError(port); + this.waitAndAssertTracesClientSyncServerAsyncWithError(port, "withError", 1); + } + + @Test + public void syncFramedClientAsyncNonblockingServerWithErrorMuti() throws TException { + int port = super.getPort(); + this.startAsyncNonblockingServer(port); + + for (int i = 0; i < 5; ++i) { + this.syncFramedClientWithError(port); + } + + this.waitAndAssertTracesClientSyncServerAsyncWithError(port, "withError", 5); + } + + @Test + public void syncFramedClientAsyncNonblockingServerWithErrorParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startAsyncNonblockingServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncFramedClientWithError(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncFramedClientAsyncNonblockingServerWithErrorParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerAsyncWithError(port, "withError", threadCount); + } + + @Test + public void syncFramedClientAsyncHsHaServerWithError() throws TException { + int port = super.getPort(); + this.startAsyncHsHaServer(port); + this.syncFramedClientWithError(port); + this.waitAndAssertTracesClientSyncServerAsyncWithError(port, "withError", 1); + } + + @Test + public void syncFramedClientAsyncHsHaServerWithErrorMuti() throws TException { + int port = super.getPort(); + this.startAsyncHsHaServer(port); + + for (int i = 0; i < 5; ++i) { + this.syncFramedClientWithError(port); + } + + this.waitAndAssertTracesClientSyncServerAsyncWithError(port, "withError", 5); + } + + @Test + public void syncFramedClientAsyncHsHaServerWithErrorParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startAsyncHsHaServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.syncFramedClientWithError(port); + } catch (TException e) { + count.incrementAndGet(); + Assertions.fail( + "syncFramedClientAsyncHsHaServerWithErrorParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientSyncServerAsyncWithError(port, "withError", threadCount); + } + + @Test + public void nonBlockClientSyncNonblockingServerWithError() throws TException, IOException { + int port = super.getPort(); + this.startSyncNonblockingServer(port); + this.nonBlockClientWithError(port); + this.waitAndAssertTracesClientAsyncServerSyncWithError(port, "withError", 1); + } + + @Test + public void nonBlockClientSyncNonblockingServerWithErrorMuti() throws TException, IOException { + int port = super.getPort(); + this.startSyncNonblockingServer(port); + + for (int i = 0; i < 5; ++i) { + this.nonBlockClientWithError(port); + } + + this.waitAndAssertTracesClientAsyncServerSyncWithError(port, "withError", 5); + } + + @Test + public void nonBlockClientSyncNonblockingServerWithErrorParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncNonblockingServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.nonBlockClientWithError(port); + } catch (IOException | TException e) { + count.incrementAndGet(); + Assertions.fail( + "nonBlockClientSyncNonblockingServerWithErrorParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientAsyncServerSyncWithError(port, "withError", threadCount); + } + + @Test + public void nonBlockClientSyncHsHaServerWithError() throws TException, IOException { + int port = super.getPort(); + this.startSyncHsHaServer(port); + this.nonBlockClientWithError(port); + this.waitAndAssertTracesClientAsyncServerSyncWithError(port, "withError", 1); + } + + @Test + public void nonBlockClientSyncHsHaServerWithErrorMuti() throws TException, IOException { + int port = super.getPort(); + this.startSyncHsHaServer(port); + + for (int i = 0; i < 5; ++i) { + this.nonBlockClientWithError(port); + } + + this.waitAndAssertTracesClientAsyncServerSyncWithError(port, "withError", 5); + } + + @Test + public void nonBlockClientSyncHsHaServerWithErrorParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startSyncHsHaServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.nonBlockClientWithError(port); + } catch (IOException | TException e) { + count.incrementAndGet(); + Assertions.fail( + "nonBlockClientSyncHsHaServerWithErrorParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientAsyncServerSyncWithError(port, "withError", threadCount); + } + + @Test + public void nonBlockClientAsyncNonblockingServerWithError() throws TException, IOException { + int port = super.getPort(); + this.startAsyncNonblockingServer(port); + this.nonBlockClientWithError(port); + this.waitAndAssertTracesClientAsyncServerAsyncWithError(port, "withError", 1); + } + + @Test + public void nonBlockClientAsyncNonblockingServerWithErrorMuti() throws TException, IOException { + int port = super.getPort(); + this.startAsyncNonblockingServer(port); + + for (int i = 0; i < 5; ++i) { + this.nonBlockClientWithError(port); + } + + this.waitAndAssertTracesClientAsyncServerAsyncWithError(port, "withError", 5); + } + + @Test + public void nonBlockClientAsyncNonblockingServerWithErrorParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startAsyncNonblockingServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.nonBlockClientWithError(port); + } catch (IOException | TException e) { + count.incrementAndGet(); + Assertions.fail( + "nonBlockClientAsyncNonblockingServerWithErrorParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientAsyncServerAsyncWithError(port, "withError", threadCount); + } + + @Test + public void nonBlockClientAsyncHsHaServerWithError() throws TException, IOException { + int port = super.getPort(); + this.startAsyncHsHaServer(port); + this.nonBlockClientWithError(port); + this.waitAndAssertTracesClientAsyncServerAsyncWithError(port, "withError", 1); + } + + @Test + public void nonBlockClientAsyncHsHaServerWithErrorMuti() throws TException, IOException { + int port = super.getPort(); + this.startAsyncHsHaServer(port); + + for (int i = 0; i < 5; ++i) { + this.nonBlockClientWithError(port); + } + + this.waitAndAssertTracesClientAsyncServerAsyncWithError(port, "withError", 5); + } + + @Test + public void nonBlockClientAsyncHsHaServerWithErrorParallel() + throws TException, InterruptedException { + int port = super.getPort(); + this.startAsyncHsHaServer(port); + AtomicInteger count = new AtomicInteger(); + int threadCount = 5; + CountDownLatch latch = new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; ++i) { + new Thread( + () -> { + try { + this.nonBlockClientWithError(port); + } catch (IOException | TException e) { + count.incrementAndGet(); + Assertions.fail( + "nonBlockClientAsyncHsHaServerWithErrorParallel field: " + + e.getCause().getMessage()); + } finally { + latch.countDown(); + } + }) + .start(); + } + + latch.await(10L, TimeUnit.SECONDS); + assertThat(count.get()).isEqualTo(0); + this.waitAndAssertTracesClientAsyncServerAsyncWithError(port, "withError", threadCount); + } + + public void syncClientWithError(int port) throws TException { + TTransport transport = null; + try { + transport = new TSocket("localhost", port); + transport.open(); + TProtocol protocol = new TBinaryProtocol(transport); + ThriftService.Client client = new ThriftService.Client(protocol); + Exception error = null; + try { + this.testing().runWithSpan("parent", () -> client.withError()); + } catch (Exception e) { + error = e; + } + assertThat(error).isNotNull(); + } finally { + if (transport != null) { + transport.close(); + } + } + } + + public void syncClientMultiWithError(int port) throws TException { + TTransport transport = null; + try { + transport = new TSocket("localhost", port); + transport.open(); + TProtocol protocol = new TBinaryProtocol(transport); + TMultiplexedProtocol multiplexedProtocol = + new TMultiplexedProtocol(protocol, "syncHelloWorld"); + ThriftService.Client client = new ThriftService.Client(multiplexedProtocol); + Exception error = null; + try { + this.testing().runWithSpan("parent", () -> client.withError()); + } catch (Exception e) { + error = e; + } + assertThat(error).isNotNull(); + } finally { + if (transport != null) { + transport.close(); + } + } + } + + public void nonBlockClientWithError(int port) throws TException, IOException { + TNonblockingTransport transport = new TNonblockingSocket("localhost", port); + TAsyncClientManager clientManager = new TAsyncClientManager(); + TProtocolFactory protocolFactory = new TBinaryProtocol.Factory(); + ThriftService.AsyncClient.Factory factory = + new ThriftService.AsyncClient.Factory(clientManager, protocolFactory); + ThriftService.AsyncClient asyClient = factory.getAsyncClient(transport); + AsyncMethodCallback callback = + new AsyncMethodCallback() { + @Override + public void onComplete(ThriftService.AsyncClient.withError_call s) { + try { + String result = s.getResult(); + assertThat(result).isEqualTo("Hello USs' Bob"); + } catch (TException e) { + throw new VerifyException(e); + } + } + + @Override + public void onError(Exception e) { + assertThat(e.getMessage()).isEqualTo("Read call frame size failed"); + } + }; + this.testing().runWithSpan("parent", () -> asyClient.withError(callback)); + } + + public void syncFramedClientWithError(int port) throws TException { + TTransport transport = null; + try { + transport = new TSocket("localhost", port); + TFramedTransport framedTransport = new TFramedTransport(transport); + framedTransport.open(); + TProtocol protocol = new TBinaryProtocol(framedTransport); + ThriftService.Client client = new ThriftService.Client(protocol); + Exception error = null; + try { + this.testing().runWithSpan("parent", () -> client.withError()); + } catch (Exception e) { + error = e; + } + assertThat(error).isNotNull(); + } finally { + if (transport != null) { + transport.close(); + } + } + } + + public void syncFramedClientMultiWithError(int port) throws TException { + TTransport transport = null; + try { + transport = new TSocket("localhost", port); + TFramedTransport framedTransport = new TFramedTransport(transport); + framedTransport.open(); + TProtocol protocol = new TBinaryProtocol(framedTransport); + TMultiplexedProtocol multiplexedProtocol = + new TMultiplexedProtocol(protocol, "syncHelloWorld"); + ThriftService.Client client = new ThriftService.Client(multiplexedProtocol); + Exception error = null; + try { + this.testing().runWithSpan("parent", () -> client.withError()); + } catch (Exception e) { + error = e; + } + assertThat(error).isNotNull(); + } finally { + if (transport != null) { + transport.close(); + } + } + } +} diff --git a/instrumentation/thrift/thrift-0.9.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ThriftServiceAsyncImpl.java b/instrumentation/thrift/thrift-0.9.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ThriftServiceAsyncImpl.java new file mode 100644 index 000000000000..0aa95a9ca68e --- /dev/null +++ b/instrumentation/thrift/thrift-0.9.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ThriftServiceAsyncImpl.java @@ -0,0 +1,40 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.server; + +import io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.thrift.ThriftService; +import org.apache.thrift.TException; +import org.apache.thrift.async.AsyncMethodCallback; +import org.testcontainers.shaded.com.google.common.base.VerifyException; + +@SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused", "all"}) +public class ThriftServiceAsyncImpl implements ThriftService.AsyncIface { + public ThriftServiceAsyncImpl() {} + + @Override + public void sayHello(String zone, String name, AsyncMethodCallback resultHandler) + throws TException { + resultHandler.onComplete("Hello " + zone + "s' " + name); + } + + @Override + public void withError(AsyncMethodCallback resultHandler) throws TException { + throw new VerifyException("fail"); + } + + @Override + public void noReturn(int delay, AsyncMethodCallback resultHandler) throws TException { + resultHandler.onComplete(null); + } + + @Override + public void oneWay(AsyncMethodCallback resultHandler) throws TException {} + + @Override + public void oneWayWithError(AsyncMethodCallback resultHandler) throws TException { + throw new VerifyException("fail"); + } +} diff --git a/instrumentation/thrift/thrift-0.9.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ThriftServiceImpl.java b/instrumentation/thrift/thrift-0.9.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ThriftServiceImpl.java new file mode 100644 index 000000000000..3d38fe442eb3 --- /dev/null +++ b/instrumentation/thrift/thrift-0.9.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ThriftServiceImpl.java @@ -0,0 +1,37 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.server; + +import io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.thrift.ThriftService; +import org.apache.thrift.TException; +import org.testcontainers.shaded.com.google.common.base.VerifyException; + +@SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused", "all"}) +public class ThriftServiceImpl implements ThriftService.Iface { + + public ThriftServiceImpl() {} + + @Override + public String sayHello(String zone, String name) { + return "Hello " + zone + "s' " + name; + } + + @Override + public String withError() { + throw new VerifyException("fail"); + } + + @Override + public void noReturn(int delay) throws TException {} + + @Override + public void oneWay() {} + + @Override + public void oneWayWithError() { + throw new VerifyException("fail"); + } +} diff --git a/instrumentation/thrift/thrift-0.9.1/javaagent/src/test/resources/ThriftService.thrift b/instrumentation/thrift/thrift-0.9.1/javaagent/src/test/resources/ThriftService.thrift new file mode 100644 index 000000000000..f4f63bab0ef5 --- /dev/null +++ b/instrumentation/thrift/thrift-0.9.1/javaagent/src/test/resources/ThriftService.thrift @@ -0,0 +1,10 @@ +namespace java io.opentelemetry.javaagent.instrumentation.thrift.v0_9_1.thrift + +service ThriftService { + string sayHello(1:string zone,2:string name); + string withError(); + void noReturn(1:i32 delay); + oneway void oneWay(); + oneway void oneWayWithError(); +} + diff --git a/instrumentation/thrift/thrift-0.9.1/javaagent/src/test/resources/thrift b/instrumentation/thrift/thrift-0.9.1/javaagent/src/test/resources/thrift new file mode 100755 index 000000000000..6d06d49993d6 Binary files /dev/null and b/instrumentation/thrift/thrift-0.9.1/javaagent/src/test/resources/thrift differ diff --git a/instrumentation/thrift/thrift-common/library/build.gradle.kts b/instrumentation/thrift/thrift-common/library/build.gradle.kts new file mode 100644 index 000000000000..44fee0f36f1d --- /dev/null +++ b/instrumentation/thrift/thrift-common/library/build.gradle.kts @@ -0,0 +1,10 @@ +plugins { + id("otel.library-instrumentation") +} + +dependencies { + library("org.apache.thrift:libthrift:0.7.0") + compileOnly("javax.annotation:javax.annotation-api:1.3.2") + compileOnly("com.google.auto.value:auto-value-annotations") + annotationProcessor("com.google.auto.value:auto-value") +} diff --git a/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/RequestScopeContext.java b/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/RequestScopeContext.java new file mode 100644 index 000000000000..e7574c9be8ae --- /dev/null +++ b/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/RequestScopeContext.java @@ -0,0 +1,33 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.thrift.common; + +import com.google.auto.value.AutoValue; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import javax.annotation.Nullable; + +@AutoValue +public abstract class RequestScopeContext { + + public static RequestScopeContext create( + ThriftRequest request, @Nullable Scope scope, Context context) { + return new AutoValue_RequestScopeContext(request, scope, context); + } + + public abstract ThriftRequest getRequest(); + + @Nullable + public abstract Scope getScope(); + + public abstract Context getContext(); + + public void close() { + if (getScope() != null) { + getScope().close(); + } + } +} diff --git a/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/SocketAccessor.java b/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/SocketAccessor.java new file mode 100644 index 000000000000..9858047bdd77 --- /dev/null +++ b/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/SocketAccessor.java @@ -0,0 +1,86 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.thrift.common; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.net.Socket; +import org.apache.thrift.transport.TNonblockingSocket; +import org.apache.thrift.transport.TSaslClientTransport; +import org.apache.thrift.transport.TSocket; +import org.apache.thrift.transport.TTransport; + +public class SocketAccessor { + private static final String TRANSPORT = "transport_"; + private static final String UNDERLYING = "underlying"; + private static final String GET_INNER_TRANSPORT = "getInnerTransport"; + + private static final Class LAYERED_TRANSPORT = + getClass("org.apache.thrift.transport.layered.TLayeredTransport"); + private static final Class FRAMED_TRANSPORT = + getClass("org.apache.thrift.transport.TFramedTransport"); + private static final Class FAST_FRAMED_TRANSPORT = + getClass("org.apache.thrift.transport.TFastFramedTransport"); + + private SocketAccessor() {} + + public static Socket getSocket(TTransport transport) { + if (transport == null) { + return null; + } + try { + if (transport instanceof TSocket) { + return ((TSocket) transport).getSocket(); + } + if (transport instanceof TNonblockingSocket) { + return ((TNonblockingSocket) transport).getSocketChannel().socket(); + } + if (transport instanceof TSaslClientTransport) { + return getSocket(((TSaslClientTransport) transport).getUnderlyingTransport()); + } + Class thisClass = transport.getClass(); + Class superClass = thisClass.getSuperclass(); + Class layeredTransport = LAYERED_TRANSPORT; + if (superClass != null && superClass == layeredTransport) { + Method parentMethod = superClass.getMethod(GET_INNER_TRANSPORT); + Object result = parentMethod.invoke(transport); + if (result != null && result instanceof TTransport) { + return getSocket((TTransport) result); + } + } + + if (thisClass == FRAMED_TRANSPORT) { + return getInnerTransportSocket(thisClass, TRANSPORT, transport); + } + if (thisClass == FAST_FRAMED_TRANSPORT) { + return getInnerTransportSocket(thisClass, UNDERLYING, transport); + } + } catch (Throwable e) { + return null; + } + return null; + } + + public static Class getClass(String className) { + try { + return Class.forName(className); + } catch (Throwable e) { + return null; + } + } + + private static Socket getInnerTransportSocket( + Class thisClass, String targetField, TTransport transport) + throws NoSuchFieldException, IllegalAccessException { + Field field = thisClass.getDeclaredField(targetField); + field.setAccessible(true); + Object fieldTransport = field.get(transport); + if (fieldTransport instanceof TTransport) { + return getSocket((TTransport) fieldTransport); + } + return null; + } +} diff --git a/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/ThriftAttributesExtractor.java b/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/ThriftAttributesExtractor.java new file mode 100644 index 000000000000..a9091798255c --- /dev/null +++ b/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/ThriftAttributesExtractor.java @@ -0,0 +1,27 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.thrift.common; + +import io.opentelemetry.api.common.AttributesBuilder; +import io.opentelemetry.context.Context; +import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; +import javax.annotation.Nullable; + +final class ThriftAttributesExtractor implements AttributesExtractor { + + @Override + public void onStart(AttributesBuilder attributes, Context parentContext, ThriftRequest request) { + // Request attributes captured on request end. + } + + @Override + public void onEnd( + AttributesBuilder attributes, + Context context, + ThriftRequest request, + @Nullable Integer status, + @Nullable Throwable error) {} +} diff --git a/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/ThriftHeaderGetter.java b/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/ThriftHeaderGetter.java new file mode 100644 index 000000000000..89fbc6e2cad2 --- /dev/null +++ b/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/ThriftHeaderGetter.java @@ -0,0 +1,27 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.thrift.common; + +import io.opentelemetry.context.propagation.TextMapGetter; +import javax.annotation.Nullable; + +public enum ThriftHeaderGetter implements TextMapGetter { + INSTANCE; + + @Override + public Iterable keys(ThriftRequest request) { + return request.getHeader().keySet(); + } + + @Override + @Nullable + public String get(@Nullable ThriftRequest request, String key) { + if (request == null) { + return null; + } + return request.getHeader().get(key); + } +} diff --git a/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/ThriftHeaderSetter.java b/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/ThriftHeaderSetter.java new file mode 100644 index 000000000000..ecc6fd90d59b --- /dev/null +++ b/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/ThriftHeaderSetter.java @@ -0,0 +1,23 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.thrift.common; + +import io.opentelemetry.context.propagation.TextMapSetter; +import java.util.Map; +import javax.annotation.Nullable; + +public enum ThriftHeaderSetter implements TextMapSetter { + INSTANCE; + + @Override + public void set(@Nullable ThriftRequest request, String key, String value) { + if (request == null) { + return; + } + Map header = request.getHeader(); + header.put(key, value); + } +} diff --git a/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/ThriftInstrumenterFactory.java b/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/ThriftInstrumenterFactory.java new file mode 100644 index 000000000000..b9f7617299bc --- /dev/null +++ b/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/ThriftInstrumenterFactory.java @@ -0,0 +1,51 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.thrift.common; + +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.instrumentation.api.incubator.semconv.rpc.RpcClientAttributesExtractor; +import io.opentelemetry.instrumentation.api.incubator.semconv.rpc.RpcClientMetrics; +import io.opentelemetry.instrumentation.api.incubator.semconv.rpc.RpcServerAttributesExtractor; +import io.opentelemetry.instrumentation.api.incubator.semconv.rpc.RpcServerMetrics; +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import io.opentelemetry.instrumentation.api.semconv.network.NetworkAttributesExtractor; +import io.opentelemetry.instrumentation.api.semconv.network.ServerAttributesExtractor; +import io.opentelemetry.instrumentation.thrift.common.client.ThriftClientNetworkAttributesGetter; +import io.opentelemetry.instrumentation.thrift.common.server.ThriftServerNetworkAttributesGetter; + +public final class ThriftInstrumenterFactory { + + public static Instrumenter clientInstrumenter( + String instrumentationName) { + ThriftClientNetworkAttributesGetter netClientAttributesGetter = + new ThriftClientNetworkAttributesGetter(); + ThriftRpcAttributesGetter rpcAttributesGetter = ThriftRpcAttributesGetter.INSTANCE; + return Instrumenter.builder( + GlobalOpenTelemetry.get(), instrumentationName, new ThriftSpanNameExtractor()) + .setSpanStatusExtractor(ThriftSpanStatusExtractor.INSTANCE) + .addAttributesExtractor(RpcClientAttributesExtractor.create(rpcAttributesGetter)) + .addAttributesExtractor(ServerAttributesExtractor.create(netClientAttributesGetter)) + .addAttributesExtractor(NetworkAttributesExtractor.create(netClientAttributesGetter)) + .addOperationMetrics(RpcClientMetrics.get()) + .buildClientInstrumenter(ThriftHeaderSetter.INSTANCE); + } + + public static Instrumenter serverInstrumenter( + String instrumentationName) { + ThriftServerNetworkAttributesGetter netServerAttributesGetter = + new ThriftServerNetworkAttributesGetter(); + ThriftRpcAttributesGetter rpcAttributesGetter = ThriftRpcAttributesGetter.INSTANCE; + return Instrumenter.builder( + GlobalOpenTelemetry.get(), instrumentationName, new ThriftSpanNameExtractor()) + .setSpanStatusExtractor(ThriftSpanStatusExtractor.INSTANCE) + .addAttributesExtractor(RpcServerAttributesExtractor.create(rpcAttributesGetter)) + .addAttributesExtractor(NetworkAttributesExtractor.create(netServerAttributesGetter)) + .addOperationMetrics(RpcServerMetrics.get()) + .buildServerInstrumenter(ThriftHeaderGetter.INSTANCE); + } + + private ThriftInstrumenterFactory() {} +} diff --git a/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/ThriftRequest.java b/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/ThriftRequest.java new file mode 100644 index 000000000000..e5d3fffa9379 --- /dev/null +++ b/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/ThriftRequest.java @@ -0,0 +1,33 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.thrift.common; + +import com.google.auto.value.AutoValue; +import java.net.Socket; +import java.util.Map; +import javax.annotation.Nullable; + +@AutoValue +public abstract class ThriftRequest { + + public static ThriftRequest create( + @Nullable String serviceName, + String methodName, + @Nullable Socket socket, + Map header) { + return new AutoValue_ThriftRequest(serviceName, methodName, socket, header); + } + + @Nullable + public abstract String getServiceName(); + + public abstract String getMethodName(); + + @Nullable + public abstract Socket getSocket(); + + public abstract Map getHeader(); +} diff --git a/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/ThriftRpcAttributesGetter.java b/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/ThriftRpcAttributesGetter.java new file mode 100644 index 000000000000..ba021f5ec730 --- /dev/null +++ b/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/ThriftRpcAttributesGetter.java @@ -0,0 +1,30 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.thrift.common; + +import io.opentelemetry.instrumentation.api.incubator.semconv.rpc.RpcAttributesGetter; +import javax.annotation.Nullable; + +public enum ThriftRpcAttributesGetter implements RpcAttributesGetter { + INSTANCE; + + @Override + public String getSystem(ThriftRequest request) { + return "thrift"; + } + + @Override + @Nullable + public String getService(ThriftRequest request) { + return request.getServiceName(); + } + + @Override + @Nullable + public String getMethod(ThriftRequest request) { + return request.getMethodName(); + } +} diff --git a/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/ThriftSpanNameExtractor.java b/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/ThriftSpanNameExtractor.java new file mode 100644 index 000000000000..553f0cc1f1d6 --- /dev/null +++ b/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/ThriftSpanNameExtractor.java @@ -0,0 +1,15 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.thrift.common; + +import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; + +public final class ThriftSpanNameExtractor implements SpanNameExtractor { + @Override + public String extract(ThriftRequest request) { + return request.getMethodName(); + } +} diff --git a/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/ThriftSpanStatusExtractor.java b/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/ThriftSpanStatusExtractor.java new file mode 100644 index 000000000000..4b2972ee5116 --- /dev/null +++ b/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/ThriftSpanStatusExtractor.java @@ -0,0 +1,28 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.thrift.common; + +import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusBuilder; +import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor; +import javax.annotation.Nullable; + +public final class ThriftSpanStatusExtractor + implements SpanStatusExtractor { + + public static final ThriftSpanStatusExtractor INSTANCE = new ThriftSpanStatusExtractor(); + + @Override + public void extract( + SpanStatusBuilder spanStatusBuilder, + ThriftRequest request, + @Nullable Integer status, + @Nullable Throwable error) { + if ((status != null && status > 0) || error != null) { + spanStatusBuilder.setStatus(StatusCode.ERROR); + } + } +} diff --git a/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/client/MethodAccessor.java b/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/client/MethodAccessor.java new file mode 100644 index 000000000000..7c94ae7636fe --- /dev/null +++ b/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/client/MethodAccessor.java @@ -0,0 +1,31 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.thrift.common.client; + +import java.lang.reflect.Method; +import java.util.HashSet; +import java.util.Set; + +public class MethodAccessor { + + private MethodAccessor() {} + + public static Set voidMethodNames(String serviceName) { + Set methodNames = new HashSet<>(); + try { + Class clazz = Class.forName(serviceName); + Method[] declaredMethods = clazz.getDeclaredMethods(); + for (Method declaredMethod : declaredMethods) { + if (declaredMethod.getReturnType() == void.class) { + methodNames.add(declaredMethod.getName()); + } + } + } catch (ClassNotFoundException ignore) { + // ignore + } + return methodNames; + } +} diff --git a/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/client/ThriftClientNetworkAttributesGetter.java b/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/client/ThriftClientNetworkAttributesGetter.java new file mode 100644 index 000000000000..d24d4924f0b3 --- /dev/null +++ b/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/client/ThriftClientNetworkAttributesGetter.java @@ -0,0 +1,34 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.thrift.common.client; + +import io.opentelemetry.instrumentation.api.semconv.network.NetworkAttributesGetter; +import io.opentelemetry.instrumentation.api.semconv.network.ServerAttributesGetter; +import io.opentelemetry.instrumentation.thrift.common.ThriftRequest; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketAddress; +import javax.annotation.Nullable; + +public final class ThriftClientNetworkAttributesGetter + implements ServerAttributesGetter, + NetworkAttributesGetter { + + @Nullable + @Override + public InetSocketAddress getNetworkPeerInetSocketAddress( + ThriftRequest request, @Nullable Integer integer) { + Socket socket = request.getSocket(); + if (socket == null) { + return null; + } + SocketAddress address = socket.getRemoteSocketAddress(); + if (address instanceof InetSocketAddress) { + return (InetSocketAddress) address; + } + return null; + } +} diff --git a/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/server/ThriftServerNetworkAttributesGetter.java b/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/server/ThriftServerNetworkAttributesGetter.java new file mode 100644 index 000000000000..1fe9bb8fe147 --- /dev/null +++ b/instrumentation/thrift/thrift-common/library/src/main/java/io/opentelemetry/instrumentation/thrift/common/server/ThriftServerNetworkAttributesGetter.java @@ -0,0 +1,38 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.thrift.common.server; + +import io.opentelemetry.instrumentation.api.semconv.network.NetworkAttributesGetter; +import io.opentelemetry.instrumentation.api.semconv.network.ServerAttributesGetter; +import io.opentelemetry.instrumentation.thrift.common.ThriftRequest; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketAddress; +import javax.annotation.Nullable; + +/** + * This class is internal and is hence not for public use. Its APIs are unstable and can change at + * any time. + */ +public final class ThriftServerNetworkAttributesGetter + implements ServerAttributesGetter, + NetworkAttributesGetter { + + @Override + @Nullable + public InetSocketAddress getNetworkPeerInetSocketAddress( + ThriftRequest request, @Nullable Integer status) { + Socket socket = request.getSocket(); + if (socket == null) { + return null; + } + SocketAddress address = socket.getRemoteSocketAddress(); + if (address instanceof InetSocketAddress) { + return (InetSocketAddress) address; + } + return null; + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 37b2859bcc6a..fa52828c9c61 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -616,6 +616,8 @@ include(":instrumentation:xxl-job:xxl-job-2.3.0:javaagent") include(":instrumentation:xxl-job:xxl-job-common:javaagent") include(":instrumentation:xxl-job:xxl-job-common:testing") include(":instrumentation:zio:zio-2.0:javaagent") +include(":instrumentation:thrift:thrift-0.9.1:javaagent") +include(":instrumentation:thrift:thrift-common:library") // benchmark include(":benchmark-overhead-jmh")