Add instrumentation for thrift#18405
Conversation
| public ElementMatcher.Junction<ClassLoader> classLoaderMatcher() { | ||
| // limit support to 0.13.0 since we don't test with earlier versions | ||
| // added in 0.13.0 | ||
| return hasClassesNamed("org.apache.thrift.protocol.ShortStack"); |
There was a problem hiding this comment.
While the library instrumentation requires 0.13.0 the agent instrumentation could work with older versions. We are limiting the version here because we don't test on older versions.
trask
left a comment
There was a problem hiding this comment.
Automated CI review from #17889 incoming...
Review of the new Apache Thrift instrumentation. Main findings:
SocketAccessorhas a copy/paste bug:FRAMED_TRANSPORTandFAST_FRAMED_TRANSPORTboth resolve toTFastFramedTransport, soTFramedTransport-wrapped transports never reach the framed-transport branch and their socket is not unwrapped.ContextPropagationUtil.readHeaderscorrupts the protocol stream when the entry count exceedsMAX_CONTEXT_ENTRIES— it returns without skipping the unread map entries, while the size-limit branch correctly skips remaining entries.library/README.mdlooks copy-pasted from gRPC: wrong title, wrongcentral.sonatype.comartifact link, undefinedtelemetryvariable in the snippets, wrong return type onwrapClientProtocolFactory.- Minor style:
this.getClass().getName()intransform()should begetClass().getName()(perjavaagent-module-patterns.md); duplicateAutoCleanupExtensionfield in the libraryThriftTest(the abstract base already declares one).
|
I sent a few optional suggestions in laurit#410 |
# Conflicts: # .github/config/latest-dep-versions.json
There was a problem hiding this comment.
Pull request overview
This PR introduces Apache Thrift 0.13+ instrumentation to the OpenTelemetry Java Instrumentation project, providing both a standalone library wrapper (ThriftTelemetry) and Javaagent auto-instrumentation, along with a dedicated testing module and documentation/metadata updates.
Changes:
- Added new Thrift 0.13 modules:
library,javaagent, andtesting, including client/server span + metric coverage and context propagation. - Implemented Thrift client/server wrappers for library users and ByteBuddy instrumentations for javaagent users.
- Added Thrift test coverage (sync, async, transports), plus repo metadata/docs updates and latest-deps tracking.
Reviewed changes
Copilot reviewed 38 out of 38 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
settings.gradle.kts |
Registers the new Thrift 0.13 modules in the Gradle build. |
instrumentation/thrift-0.13/testing/src/main/thrift/custom.thrift |
Defines the Thrift IDL used to generate test client/server artifacts. |
instrumentation/thrift-0.13/testing/src/main/java/io/opentelemetry/instrumentation/thrift/v0_13/CustomHandler.java |
Implements the Thrift service used by tests. |
instrumentation/thrift-0.13/testing/src/main/java/io/opentelemetry/instrumentation/thrift/v0_13/AbstractThriftTest.java |
Shared test suite validating spans/metrics and behavior across server/client modes. |
instrumentation/thrift-0.13/testing/build.gradle.kts |
Adds the testing module dependencies and Thrift source generation step. |
instrumentation/thrift-0.13/metadata.yaml |
Declares instrumentation metadata (semantic conventions, description, link). |
instrumentation/thrift-0.13/library/src/test/java/io/opentelemetry/instrumentation/thrift/v0_13/ThriftTest.java |
Library-instrumentation test coverage using ThriftTelemetry wrappers. |
instrumentation/thrift-0.13/library/src/main/java/io/opentelemetry/instrumentation/thrift/v0_13/ThriftTelemetryBuilder.java |
Builder API to customize extractors and span naming for Thrift telemetry. |
instrumentation/thrift-0.13/library/src/main/java/io/opentelemetry/instrumentation/thrift/v0_13/ThriftTelemetry.java |
Public entrypoint providing wrappers for Thrift processors/protocols/clients. |
instrumentation/thrift-0.13/library/src/main/java/io/opentelemetry/instrumentation/thrift/v0_13/ThriftResponse.java |
Response type used for instrumenter end/status decisions. |
instrumentation/thrift-0.13/library/src/main/java/io/opentelemetry/instrumentation/thrift/v0_13/ThriftRequest.java |
Request carrier for RPC + network attributes and propagation headers. |
instrumentation/thrift-0.13/library/src/main/java/io/opentelemetry/instrumentation/thrift/v0_13/internal/ThriftServerNetworkAttributesGetter.java |
Extracts server-side network/server attributes from ThriftRequest. |
instrumentation/thrift-0.13/library/src/main/java/io/opentelemetry/instrumentation/thrift/v0_13/internal/ThriftRpcAttributesGetter.java |
Provides RPC semantic convention attributes (system/service/method/error). |
instrumentation/thrift-0.13/library/src/main/java/io/opentelemetry/instrumentation/thrift/v0_13/internal/ThriftRequestGetter.java |
TextMapGetter for extracting propagation headers from ThriftRequest. |
instrumentation/thrift-0.13/library/src/main/java/io/opentelemetry/instrumentation/thrift/v0_13/internal/ThriftInstrumenterFactory.java |
Builds client/server instrumenters and wires RPC/network extractors + metrics. |
instrumentation/thrift-0.13/library/src/main/java/io/opentelemetry/instrumentation/thrift/v0_13/internal/ThriftClientNetworkAttributesGetter.java |
Extracts client-side server/network attributes from ThriftRequest. |
instrumentation/thrift-0.13/library/src/main/java/io/opentelemetry/instrumentation/thrift/v0_13/internal/SocketAccessor.java |
Retrieves socket/socket address details across Thrift transport variants. |
instrumentation/thrift-0.13/library/src/main/java/io/opentelemetry/instrumentation/thrift/v0_13/internal/ServerProcessorDecorator.java |
Wraps server processor to apply protocol decorators and end spans correctly. |
instrumentation/thrift-0.13/library/src/main/java/io/opentelemetry/instrumentation/thrift/v0_13/internal/ServerOutProtocolDecorator.java |
Detects server-side exception responses when writing messages. |
instrumentation/thrift-0.13/library/src/main/java/io/opentelemetry/instrumentation/thrift/v0_13/internal/ServerInProtocolDecorator.java |
Reads propagation field, starts server span, and scopes context for handlers. |
instrumentation/thrift-0.13/library/src/main/java/io/opentelemetry/instrumentation/thrift/v0_13/internal/ServerCallContext.java |
ThreadLocal context to expose transport for nonblocking server socket discovery. |
instrumentation/thrift-0.13/library/src/main/java/io/opentelemetry/instrumentation/thrift/v0_13/internal/ContextPropagationUtil.java |
Writes/reads propagation payload in Thrift maps with safety limits. |
instrumentation/thrift-0.13/library/src/main/java/io/opentelemetry/instrumentation/thrift/v0_13/internal/ClientProtocolDecorator.java |
Injects propagation headers into outbound Thrift message fields. |
instrumentation/thrift-0.13/library/src/main/java/io/opentelemetry/instrumentation/thrift/v0_13/internal/ClientCallContext.java |
ThreadLocal call context to coordinate injection and client span lifecycle. |
instrumentation/thrift-0.13/library/src/main/java/io/opentelemetry/instrumentation/thrift/v0_13/internal/AsyncMethodCallbackUtil.java |
Wraps async callbacks to end spans and restore parent context for callback code. |
instrumentation/thrift-0.13/library/README.md |
Documents how to use the standalone Thrift library instrumentation. |
instrumentation/thrift-0.13/library/build.gradle.kts |
Declares library instrumentation build/test tasks (including semconv variants). |
instrumentation/thrift-0.13/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_13/ThriftTest.java |
Javaagent test coverage via AbstractThriftTest. |
instrumentation/thrift-0.13/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_13/ThriftTBaseProcessorInstrumentation.java |
Instruments server processing entrypoint for blocking servers. |
instrumentation/thrift-0.13/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_13/ThriftSingletons.java |
Provides global client/server instrumenters and propagators for the agent. |
instrumentation/thrift-0.13/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_13/ThriftServiceClientInstrumentation.java |
Instruments generated Thrift sync clients and wraps protocols for propagation. |
instrumentation/thrift-0.13/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_13/ThriftInstrumentationModule.java |
Registers the Thrift agent instrumentation module and its type instrumentations. |
instrumentation/thrift-0.13/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_13/ThriftFrameBufferInstrumentation.java |
Adds transport exposure for nonblocking server processing via ThreadLocal context. |
instrumentation/thrift-0.13/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/thrift/v0_13/ThriftAsyncClientInstrumentation.java |
Instruments generated Thrift async clients, wrapping callbacks for span end. |
instrumentation/thrift-0.13/javaagent/build.gradle.kts |
Configures agent module dependencies, muzzle, and semconv-variant test tasks. |
docs/supported-libraries.md |
Adds Thrift to the supported libraries list. |
.github/config/latest-dep-versions.json |
Adds org.apache.thrift:libthrift latest version for dependency update tooling. |
.fossa.yml |
Adds new Thrift gradle targets for license scanning. |
| transformer.applyAdviceToMethod( | ||
| isConstructor().and(takesArgument(0, named("org.apache.thrift.protocol.TProtocolFactory"))), | ||
| getClass().getName() + "$ConstructorAdvice"); | ||
|
|
||
| transformer.applyAdviceToMethod( | ||
| isMethod() | ||
| .and( | ||
| target -> { | ||
| ParameterList<?> parameterList = target.getParameters(); | ||
| if (!parameterList.isEmpty()) { | ||
| String lastParameter = | ||
| parameterList.get(parameterList.size() - 1).getType().asErasure().getName(); | ||
| return "org.apache.thrift.async.AsyncMethodCallback".equals(lastParameter); | ||
| } | ||
| return false; | ||
| }), | ||
| getClass().getName() + "$MethodAdvice"); | ||
| } | ||
|
|
||
| @SuppressWarnings("unused") | ||
| public static class ConstructorAdvice { | ||
| @Advice.AssignReturned.ToArguments(@ToArgument(0)) | ||
| @Advice.OnMethodEnter(suppress = Throwable.class, inline = false) | ||
| public static TProtocolFactory onEnter( | ||
| @Advice.Argument(0) TProtocolFactory protocolFactory, | ||
| @Advice.Argument(2) TNonblockingTransport transport) { | ||
| return new ClientProtocolDecorator.Factory(protocolFactory, getPropagators()); |
There was a problem hiding this comment.
Fixed in fa3f3bc — tightened the matcher with takesArguments(3) and takesArgument(2, TNonblockingTransport), and dropped the unused transport advice binding.
There was a problem hiding this comment.
Update: amended in 951e709 — kept just the original takesArgument(0, TProtocolFactory) matcher and only removed the unused @Advice.Argument(2) TNonblockingTransport binding. takesArguments(3) would have over-tightened (Thrift's generator emits both 3-arg and 4-arg subclass ctors via super(...), so both should be instrumented to wrap the protocol factory).
|
@copilot apply changes based on the comments in this thread |
| private UnaryOperator<SpanNameExtractor<ThriftRequest>> clientSpanNameExtractorCustomizer = | ||
| UnaryOperator.identity(); | ||
| private UnaryOperator<SpanNameExtractor<ThriftRequest>> serverSpanNameExtractorCustomizer = | ||
| UnaryOperator.identity(); | ||
| private final List<AttributesExtractor<ThriftRequest, ThriftResponse>> additionalExtractors = | ||
| new ArrayList<>(); | ||
| private final List<AttributesExtractor<ThriftRequest, ThriftResponse>> | ||
| additionalClientExtractors = new ArrayList<>(); | ||
| private final List<AttributesExtractor<ThriftRequest, ThriftResponse>> | ||
| additionalServerExtractors = new ArrayList<>(); |
There was a problem hiding this comment.
We removed the complex generics from http instrumentations, should we also do it elsewhere for 3.0?
Resolves #1573
While reviewing #13784 noticed that it is significantly more complicated than https://github.com/opentracing-contrib/java-thrift Here is my attempt at building a simpler instrumentation.
It is possible that some of the complexity in #13784 is because of supporting
0.9.1vs0.13.0in the opentracing. Could also be that it handles some cases better. I didn't get around to trying the tests from #13784 with my instrumentation. The tests in this PR are based on the opentracing tests.cc @YaoYingLong