feat: Add support for Thrift 0.9.1 and later versions#13784
feat: Add support for Thrift 0.9.1 and later versions#13784YaoYingLong wants to merge 20 commits into
Conversation
|
In order to minimize the amount of code, do you think it would be possible to re-generate the generated code on build instead of adding it to git ? The likely challenge here would be being able to maintain those over time, in particular it would really be useful to be able to re-generate and update those every time the thrift version changes, or even generating and testing multiple versions. |
…be regenerated during the build process.
| pass { | ||
| group.set("org.apache.thrift") | ||
| module.set("libthrift") | ||
| versions.set("[0.9.1,)") |
There was a problem hiding this comment.
usually we also add assertInverse.set(true) to verify that instrumentation does not apply on earlier versions
| var generateThrift = tasks.register<Exec>("generateThrift") { | ||
| group = "build" | ||
| description = "Generate Java code from Thrift IDL files" | ||
| commandLine(thriftExecutable, "--gen", "java", "-out", thriftOutputDir, thriftInputFile) |
There was a problem hiding this comment.
Binaries shouldn't be really added to the source code repository, there is even a scorecard check for that https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#binary-artifacts Also since the project needs to build on at least windows, linux and mac just having one binary wouldn't work. Currently code generation seems to fail https://scans.gradle.com/s/73advrdsyn2fk/console-log/task/:instrumentation:thrift:thrift-0.9.1:javaagent:generateThrift?anchor=1&page=1 I would have hoped that the compiler binaries would be available for download like for the gRPC but that doesn't seem to be the case.
I think it would be best to go back to adding the generated java files to the repo for now. We can work on automating the generation later when other issues have been sorted. One way we could do the generation would be to have the thrift compiler in a docker image and run that image during the build similarly to how semconv repo runs weaver https://github.com/open-telemetry/semantic-conventions-java/blob/36743b068e1d3bbff129b528a340a63fb544e390/build.gradle.kts#L86 An example of such image can be found from https://github.com/reddit/thrift-compiler/pkgs/container/thrift-compiler If we can't find an existing image for the version we need we can build it ourself. @open-telemetry/java-instrumentation-approvers do you have any suggestions? Would having the thrift compiler in docker image be worth the effort?
There was a problem hiding this comment.
Then I will temporarily add the generated Java files to the repository, or temporarily remove the test code.
| * 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 { |
There was a problem hiding this comment.
this code seems to originate from skywalking https://github.com/apache/skywalking-java/blob/9e80a4c85ba895083e892f2024611a27846c3c5f/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/wrapper/AbstractProtocolWrapper.java#L22 you should point to the origin of the code like in
| import org.apache.thrift.protocol.TType; | ||
| import org.apache.thrift.transport.TTransport; | ||
|
|
||
| @SuppressWarnings("all") |
There was a problem hiding this comment.
instead of suppressing warnings we prefer to fix the code so that it wouldn't have the warnings
| // TMultiplexedProcessor compatible | ||
| Field field = null; | ||
| try { | ||
| field = TProtocolDecorator.class.getDeclaredField("concreteProtocol"); |
There was a problem hiding this comment.
when we use reflection we always fetch the field/method only once and the reuse it
| @@ -0,0 +1,10 @@ | |||
| plugins { | |||
| id("otel.library-instrumentation") | |||
There was a problem hiding this comment.
By library instrumentation we mean instrumentation that can be applied without the agent. This module does not seem to contain a library instrumentation in that sense. Consider merging it into the javaagent module or if you intend to add instrumentations for more versions that could benefit from shared code you could rename this module from library to javaagent too.
There was a problem hiding this comment.
This is the shared code for adding instrumentation for more versions, so I have renamed the module to javaagent.
| import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; | ||
| import javax.annotation.Nullable; | ||
|
|
||
| final class ThriftAttributesExtractor implements AttributesExtractor<ThriftRequest, Integer> { |
|
|
||
| import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; | ||
|
|
||
| public final class ThriftSpanNameExtractor implements SpanNameExtractor<ThriftRequest> { |
There was a problem hiding this comment.
there are semantic conventions that define the name for a RPC span, you should follow them. See RpcSpanNameExtractor.
|
|
||
| @Override | ||
| public String getSystem(ThriftRequest request) { | ||
| return "thrift"; |
There was a problem hiding this comment.
You should also create a pr to add thrift to rpc.system values in https://github.com/open-telemetry/semantic-conventions/blob/main/docs/rpc/rpc-spans.md. See open-telemetry/semantic-conventions@7c1aa90 for inspiration. It is possible that the value should be apache_thrift instead of thrift but I'll leave this for the semantic conventions folks to decide.
|
@YaoYingLong 兄弟你还在维护这个pull req吗 |
在的 只是最近没有时间顾的上来修改提的修改建议 |
|
Any updates? |
|
This PR has been labeled as stale due to lack of activity and needing author feedback. It will be automatically closed if there is no further activity over the next 7 days. |
Optimized according to Laurit's suggestions. |
…butesGetter parameters.
…ate and populate the .fossa.yml file.
|
@beztebya666 @laurit Hello, both of you, Thank you for your previous suggestions! I have made the necessary changes based on your feedback and have also fixed all the failing test cases. Could you please help review it again? Thank you so much! |
|
Any updates on this? |
@laurit need to see this |
There was a problem hiding this comment.
Pull request overview
Adds OpenTelemetry Javaagent instrumentation for Apache Thrift (targeting Thrift 0.9.1+) by introducing a shared thrift-common library-instrumentation module and a thrift-0.9.1 javaagent module, and wiring these new projects into the build and FOSSA scanning configuration.
Changes:
- Introduces
instrumentation/thrift/thrift-commonhelpers (request model, header propagation helpers, RPC + network attribute getters, instrumenter factory). - Adds
instrumentation/thrift/thrift-0.9.1ByteBuddy instrumentations and protocol wrappers for client/server span creation, context propagation, and async handling. - Registers the new Gradle modules in
settings.gradle.ktsand adds new FOSSA Gradle targets.
Reviewed changes
Copilot reviewed 36 out of 36 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
| settings.gradle.kts | Adds Thrift modules to the Gradle build (but currently drops zio-http-3.0 include). |
| .fossa.yml | Adds FOSSA targets for the new Thrift modules (but currently drops zio-http-3.0 target). |
| instrumentation/thrift/thrift-common/javaagent/build.gradle.kts | Declares dependencies for the shared Thrift instrumentation helpers. |
| instrumentation/thrift/thrift-common/javaagent/src/main/java/io/opentelemetry/instrumentation/thrift/common/ThriftRequest.java | Defines a request carrier for span naming/attributes and context propagation. |
| instrumentation/thrift/thrift-common/javaagent/src/main/java/io/opentelemetry/instrumentation/thrift/common/ThriftInstrumenterFactory.java | Centralizes client/server Instrumenter construction (RPC + network attrs, metrics, propagators). |
| instrumentation/thrift/thrift-common/javaagent/src/main/java/io/opentelemetry/instrumentation/thrift/common/ThriftSpanNameExtractor.java | Derives span names from service + method. |
| instrumentation/thrift/thrift-common/javaagent/src/main/java/io/opentelemetry/instrumentation/thrift/common/ThriftSpanStatusExtractor.java | Maps Thrift status/error to span status. |
| instrumentation/thrift/thrift-common/javaagent/src/main/java/io/opentelemetry/instrumentation/thrift/common/ThriftRpcAttributesGetter.java | Supplies RPC semantic convention attributes (rpc.system/service/method). |
| instrumentation/thrift/thrift-common/javaagent/src/main/java/io/opentelemetry/instrumentation/thrift/common/ThriftHeaderGetter.java | Extracts propagation headers from the Thrift request carrier. |
| instrumentation/thrift/thrift-common/javaagent/src/main/java/io/opentelemetry/instrumentation/thrift/common/ThriftHeaderSetter.java | Injects propagation headers into the Thrift request carrier. |
| instrumentation/thrift/thrift-common/javaagent/src/main/java/io/opentelemetry/instrumentation/thrift/common/SocketAccessor.java | Extracts underlying Socket from various Thrift TTransport implementations. |
| instrumentation/thrift/thrift-common/javaagent/src/main/java/io/opentelemetry/instrumentation/thrift/common/RequestScopeContext.java | Stores request + context + optional scope for lifecycle management. |
| instrumentation/thrift/thrift-common/javaagent/src/main/java/io/opentelemetry/instrumentation/thrift/common/client/MethodAccessor.java | Reflection-based helpers for method return-type discovery and protocol field access. |
| instrumentation/thrift/thrift-common/javaagent/src/main/java/io/opentelemetry/instrumentation/thrift/common/client/VirtualFields.java | Stores async callback associations via VirtualField. |
| instrumentation/thrift/thrift-common/javaagent/src/main/java/io/opentelemetry/instrumentation/thrift/common/client/ThriftClientNetworkAttributesGetter.java | Supplies network peer attributes for client spans. |
| instrumentation/thrift/thrift-common/javaagent/src/main/java/io/opentelemetry/instrumentation/thrift/common/server/ThriftServerNetworkAttributesGetter.java | Supplies network peer attributes for server spans. |
| instrumentation/thrift/thrift-0.9.1/javaagent/build.gradle.kts | Declares javaagent plugin usage and muzzle range for Thrift 0.9.1+. |
| instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/ThriftSingletons.java | Provides singleton instrumenters for client/server. |
| instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/AbstractProtocolWrapper.java | Base protocol decorator and reserved field constants for trace header transport. |
| instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/AsyncMethodCallbackWrapper.java | Ends spans on async completion/error. |
| instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/client/ThriftClientCommonInstrumentationModule.java | Registers client-side type instrumentations. |
| instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/client/ThriftClientInstrumentation.java | Instruments sync clients: wraps protocols and ends spans on send/receive. |
| instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/client/ThriftAsyncClientInstrumentation.java | Instruments async clients: wraps protocol factory to inject tracing. |
| instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/client/ClientProtocolFactoryWrapper.java | Wraps TProtocolFactory to return tracing protocol decorators. |
| instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/client/ClientOutProtocolWrapper.java | Client protocol wrapper that starts spans and injects trace headers via reserved field. |
| instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/client/ThriftAsyncMethodCallInstrumentation.java | Captures async callbacks and associates them with method calls via VirtualField. |
| instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/client/ThriftAsyncWriteArgsInstrumentation.java | Adjusts async oneway behavior and wires request scope to callbacks. |
| instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ThriftServerInstrumentationModule.java | Registers server-side type instrumentations. |
| instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ThriftServerInstrumentation.java | Wraps server protocol factory on server construction. |
| instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ServerProtocolFactoryWrapper.java | Produces server-side tracing protocol wrapper instances. |
| instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ServerInProtocolWrapper.java | Server protocol wrapper that extracts headers and starts server spans. |
| instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ThriftFrameBufferInstrumentation.java | Captures transport on non-blocking servers to support socket extraction. |
| instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ThriftAsyncProcessInstrumentation.java | Wraps async result handlers to end spans on callback completion. |
| instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ThriftBaseProcessorInstrumentation.java | Ends server spans around sync processor process() execution. |
| instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ThriftBaseAsyncProcessorInstrumentation.java | Ends server spans for async processor execution paths. |
| instrumentation/thrift/thrift-0.9.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_9_1/server/ThriftMutiplexedProcessorInstrumentation.java | Handles TMultiplexedProcessor end-of-request behavior. |
| 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:zio:zio-http-3.0:javaagent") | ||
| include(":instrumentation:thrift:thrift-0.9.1:javaagent") | ||
| include(":instrumentation:thrift:thrift-common:javaagent") |
There was a problem hiding this comment.
settings.gradle.kts no longer includes the :instrumentation:zio:zio-http-3.0:javaagent project, but that module still exists in the repo (e.g., instrumentation/zio/zio-http-3.0/...) and is referenced from docs/instrumentation-list.yaml. This will stop it from being built/published and may break expectations; please re-add the include (and keep the Thrift includes as well).
| path: ./ | ||
| target: ':instrumentation:zio:zio-http-3.0:javaagent' | ||
| - type: gradle | ||
| path: ./ |
There was a problem hiding this comment.
.fossa.yml removed the Gradle target for :instrumentation:zio:zio-http-3.0:javaagent, but the module still exists and is listed in docs/instrumentation-list.yaml. Please restore the removed FOSSA target entry so license scanning continues to cover this instrumentation.
| path: ./ | |
| path: ./ | |
| target: ':instrumentation:zio:zio-http-3.0:javaagent' | |
| - type: gradle | |
| path: ./ |
| return field; | ||
| } | ||
| Context context = serverInstrumenter().start(parentContext, request); | ||
| this.requestScopeContext = RequestScopeContext.create(request, null, context); |
There was a problem hiding this comment.
When the trace header is found in readFieldBegin(), the server span is started but the returned Context is never made current (scope is stored as null). This means downstream work during request processing won't see the server context. Consider calling context.makeCurrent() here too and storing the resulting Scope in RequestScopeContext (mirroring the readMessageEnd() path).
| this.requestScopeContext = RequestScopeContext.create(request, null, context); | |
| Scope scope = context.makeCurrent(); | |
| this.requestScopeContext = RequestScopeContext.create(request, scope, context); |
There was a problem hiding this comment.
In an asynchronous non-blocking scenario, the related logic will be executed in a separate thread. During thread switching, context.makeCurrent() will be executed once. If context.makeCurrent() is executed again at this point, it will result in duplicate executions of context.makeCurrent(), which may lead to issues.
| public static Set<String> voidMethodNames(String serviceName) { | ||
| Set<String> methodNames = SERVICE_NAME_METHOD_NAMES.getOrDefault(serviceName, new HashSet<>()); | ||
| if (!methodNames.isEmpty()) { | ||
| return methodNames; | ||
| } |
There was a problem hiding this comment.
voidMethodNames() re-runs reflection every time for services that have no void-returning methods because it treats an empty cached set as “not cached” (if (!methodNames.isEmpty())). This can add unnecessary overhead on hot paths. Consider caching based on containsKey(serviceName) (or using computeIfAbsent) so an empty result is still memoized; also consider using a concurrent map since this cache is accessed from multiple threads in the agent.
| 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); | ||
| } |
There was a problem hiding this comment.
getProtocol(TTransport transport) ignores its transport parameter and instead calls updateTransport(this.transport). If the factory is ever reused with a different transport, the wrapper will retain the wrong transport/socket info. Please update the wrapper using the method parameter (and/or drop the stored transport field if it’s not needed).
There was a problem hiding this comment.
The passed-in TTransport might be wrapped multiple times, and only the TTransport provided in the constructor is the original one that contains the socket.
| public final class ThriftMutiplexedProcessorInstrumentation implements TypeInstrumentation { | ||
|
|
||
| @Override | ||
| public ElementMatcher<TypeDescription> typeMatcher() { | ||
| return named("org.apache.thrift.TMultiplexedProcessor"); | ||
| } |
There was a problem hiding this comment.
Class name ThriftMutiplexedProcessorInstrumentation has a typo (“Mutiplexed” vs “Multiplexed”), while it instruments org.apache.thrift.TMultiplexedProcessor. Renaming to ThriftMultiplexedProcessorInstrumentation would improve discoverability and consistency (and update the module’s typeInstrumentations() list accordingly).
| public final class ThriftClientNetworkAttributesGetter | ||
| implements ServerAttributesGetter<ThriftRequest>, | ||
| NetworkAttributesGetter<ThriftRequest, Integer> { | ||
|
|
||
| @Nullable | ||
| @Override | ||
| public InetSocketAddress getNetworkPeerInetSocketAddress( | ||
| ThriftRequest request, @Nullable Integer integer) { |
There was a problem hiding this comment.
ThriftClientNetworkAttributesGetter implements ServerAttributesGetter, but does not override getServerAddress() / getServerPort(). As a result, ServerAttributesExtractor.create(netClientAttributesGetter) in ThriftInstrumenterFactory.clientInstrumenter() is effectively a no-op. Either implement server address/port extraction (e.g., from the socket) or remove the ServerAttributesExtractor registration to avoid confusion and extra work.
| import javax.annotation.Nullable; | ||
|
|
||
| public enum ThriftHeaderGetter implements TextMapGetter<ThriftRequest> { | ||
| INSTANCE; | ||
|
|
||
| @Override | ||
| public Iterable<String> keys(ThriftRequest request) { |
There was a problem hiding this comment.
TextMapGetter.keys() does not handle a null carrier, while get() does. Many TextMapGetter implementations in this repo accept @Nullable and return an empty list when the carrier is null to avoid NPEs during propagation. Consider aligning keys() with that pattern.
| import javax.annotation.Nullable; | |
| public enum ThriftHeaderGetter implements TextMapGetter<ThriftRequest> { | |
| INSTANCE; | |
| @Override | |
| public Iterable<String> keys(ThriftRequest request) { | |
| import java.util.Collections; | |
| import javax.annotation.Nullable; | |
| public enum ThriftHeaderGetter implements TextMapGetter<ThriftRequest> { | |
| INSTANCE; | |
| @Override | |
| public Iterable<String> keys(@Nullable ThriftRequest request) { | |
| if (request == null) { | |
| return Collections.emptyList(); | |
| } |
| public final class ThriftSpanNameExtractor implements SpanNameExtractor<ThriftRequest> { | ||
| @Override | ||
| public String extract(ThriftRequest request) { | ||
| if (request.getServiceName() == null || request.getMethodName() == null) { |
There was a problem hiding this comment.
ThriftRequest.getMethodName() is declared non-null, but ThriftSpanNameExtractor.extract() still checks request.getMethodName() == null. This is inconsistent and can hide actual contract violations (AutoValue will throw if methodName is null). Either make methodName nullable end-to-end or remove the null check and rely on the non-null contract.
| if (request.getServiceName() == null || request.getMethodName() == null) { | |
| if (request.getServiceName() == null) { |
| transformer.applyAdviceToMethod( | ||
| isConstructor().and(takesArguments(2)), | ||
| ThriftClientInstrumentation.class.getName() + "$ConstructorTowAdvice"); | ||
|
|
There was a problem hiding this comment.
Typo in advice class name: ConstructorTowAdvice should be ConstructorTwoAdvice (or similar). Since these names are used in stack traces and debugging, correcting the typo will make troubleshooting easier.
|
One issue with this PR is that it doesn't include tests. There original PR did include them but it also included a ton of generated code. Ideally code generation would happen during the build. I'm not familiar with thrift toolchain so I don't know whether it is easy (e.g. for protobuf there is a gradle plugin that runs protoc). If tools need to be installed manually one option we could try would be to test for the presence of the tools and skip the build or tests when the necessary tools are not present and the |
|
this is all turning into a very complex PR... we just wanted thrift support for this java agent.. is there an easier way? @laurit @YaoYingLong I'll be honest, in 24 days this PR will be exactly a year old |
Regarding the implementation mentioned in https://github.com/opentracing-contrib/java-thrift, I took a closer look. Since Thrift is based on a layer 4 protocol, it inherently supports synchronous blocking, synchronous non-blocking, and asynchronous non-blocking modes. The SpanProcessor used on the server side is an implementation of Thrift's TProcessor, which indicates that it can only support synchronous blocking and synchronous non-blocking scenarios, but not asynchronous non-blocking scenarios (whether on the client or server side). The asynchronous non-blocking mode uses TAsyncProcessor + TNonblockingServer or TThreadedSelectorServer. The fields exported in https://github.com/opentracing-contrib/java-thrift are actually quite limited and only support Thrift versions 0.13 and above. In this PR, network-related fields have been added for compatibility, supporting versions 0.9.1 and above, including differences in the oneway mechanism between versions 0.9.1, 0.9.2, and 0.9.3. Additionally, to ensure compatibility with asynchronous scenarios, the logic appears relatively complex. If only synchronous scenarios are considered and the interception for asynchronous scenarios is removed, the code would become much simpler. The implementation approach is actually the same as in java-thrift. Regarding the tests, there are no available Docker images for version 0.9.x, so for now, only version 0.12 images can be used. Additionally, the previously removed test cases have been added back, with some simplifications and optimizations made. |
|
@YaoYingLong thanks for the explanation. Just wondering if testing older versions is going to be a pain then perhaps we shouldn't bother with them at all? Would that simplify the instrumentation? |
Because some of our applications use version 0.9.x, we have implemented compatibility for this version. However, if you think it’s unnecessary, I can remove this part of the compatibility logic and only support relatively higher versions. This would simplify the compatibility logic for ONEWAY messages, but it won’t significantly simplify the code or reduce its complexity because the asynchronous logic is the same in higher versions and version 0.9.1. The primary cause of complexity lies in the asynchronous logic, which is used quite frequently. If you want me to simplify the compatibility logic for ONEWAY messages, please let me know, and I will make the adjustments. |
Lets try to keep the support for old versions then. |
|
Thanks @YaoYingLong! Closing in favor of #18405 |
Add support for Thrift 0.9.1 and later versions
#1573
Special Note:Although 51 files were added with a total of 16,937 lines of code, 12 of them are test-related files containing 14,960 lines of code, while the actual instrumentation adaptation code is only around 1,900 lines. Among the test-related code, approximately 9,000 lines were generated using the Thrift client based on IDL files for testing purposes. Due to the limitations of Thrift client code generation, these generated codes were pre-generated and placed in the project's test directory.