Skip to content

Fix Groovy OpenTelemetrySdk builder loading#8407

Open
ADITYA-CODE-SOURCE wants to merge 7 commits into
open-telemetry:mainfrom
ADITYA-CODE-SOURCE:issue-8198-groovy-builder
Open

Fix Groovy OpenTelemetrySdk builder loading#8407
ADITYA-CODE-SOURCE wants to merge 7 commits into
open-telemetry:mainfrom
ADITYA-CODE-SOURCE:issue-8198-groovy-builder

Conversation

@ADITYA-CODE-SOURCE
Copy link
Copy Markdown
Contributor

Fixes #8198

This avoids eager Groovy linkage of incubator-dependent SDK code by resolving IncubatingUtil.createExtendedOpenTelemetrySdk(...) reflectively in OpenTelemetrySdkBuilder instead of calling it directly.

Also adds a Groovy regression test covering OpenTelemetrySdk.builder().build() without incubator classes on the runtime classpath.

}

@Test
void builder_fromGroovyWithoutIncubator() throws Exception {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Could rename the test to buildFromGroovyWithoutIncubator

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in — the test is now named .

Comment on lines +177 to +182
if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
}
if (cause instanceof Error) {
throw (Error) cause;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add some comments justifying the reasons for this handling?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a comment in commit d5ffc54 explaining that reflection wraps the underlying incubator-path failure in InvocationTargetException, and that we rethrow RuntimeException and Error directly to preserve the original behavior.

try {
return (OpenTelemetrySdk)
requireNonNull(CREATE_EXTENDED_OPEN_TELEMETRY_SDK_METHOD)
.invoke(null, openTelemetrySdk, configProvider);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Looking at the javadoc for invoke, it throws 3 checked exceptions:

  • IllegalAccessException
  • IllegalArgumentException
  • InvocationTargetException

Might be good to add handling for IllegalArgumentException (although it is less likely since arguments are controlled).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. I added explicit IllegalArgumentException handling in commit d5ffc54 as well.

* io.opentelemetry.sdk.internal.SdkConfigProvider)}.
*/
OpenTelemetrySdkBuilder setConfigProvider(SdkConfigProvider configProvider) {
OpenTelemetrySdkBuilder setConfigProvider(Object configProvider) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: Why was this changed to Object?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed it to Object so the reflective path in OpenTelemetrySdkBuilder no longer depends on a narrower incubator-linked method signature while Groovy is eagerly inspecting the builder. The actual object passed is still the same internal config provider; this just keeps the optional incubator path behind reflection.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 15, 2026

Codecov Report

❌ Patch coverage is 83.33333% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.88%. Comparing base (7b72998) to head (6479a05).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
.../io/opentelemetry/sdk/OpenTelemetrySdkBuilder.java 82.60% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff            @@
##               main    #8407   +/-   ##
=========================================
  Coverage     90.88%   90.88%           
- Complexity     7985     7989    +4     
=========================================
  Files           898      898           
  Lines         24107    24129   +22     
  Branches       2406     2408    +2     
=========================================
+ Hits          21909    21930   +21     
- Misses         1455     1458    +3     
+ Partials        743      741    -2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@ADITYA-CODE-SOURCE
Copy link
Copy Markdown
Contributor Author

Follow-up: I added focused coverage for the reflective error-handling branches in OpenTelemetrySdkBuilder (runtime exception, error, checked exception, illegal argument, and illegal access paths) and pushed that in commit aa2fdc1. This should address the remaining patch coverage gap from Codecov.

@ADITYA-CODE-SOURCE
Copy link
Copy Markdown
Contributor Author

Follow-up: the broad CI failures were coming from an Error Prone overload-order warning on the new helper in OpenTelemetrySdkBuilder, which was then treated as an error under the normal build settings. I aligned the overload parameter order and updated the new branch-coverage tests accordingly in commit e0d4b87.

@psx95
Copy link
Copy Markdown
Contributor

psx95 commented May 15, 2026

You need to run spotlessApply to fix some of the failures.

@jack-berg
Copy link
Copy Markdown
Member

Hey I want to take a step back on this. This PR represents a precedent that we're going to jump through additional hoops to support groovy.

We don't say anything about groovy or other JVM based languages in our versioning policy. And its not that a don't want to support these. But I don't understand what supporting entails. Groovy for example, has different class loading semantics that has runs into issues with the patterns we use to activate different capabilities based on whether or not certain dependencies are present. For example, the metrics, logs, and trace SDKs all behave differently based on whether opentelemetry-api-incubator is present, using techniques like this to detect if the module is present, and helps like this that interact with the standard java classloader in such a way that the incubating classes are only loaded after we verify they are present.

I know the techniques we need to use to make these patterns work with the java class loader. I don't the ways in which groovy class loading is different. I do know that there are differences that are impactful though.

Before establishing a precedent about groovy, I want more analysis to be done about those differences and what it means for the patterns we employ.

I know that its a bigger scope than just solving an issue that appears to be self contained. But some seemingly simple issues have a big can of worms hiding under the surface and this is one of them.

Groovy users can always get around these issues by including the compile only dependencies on their classpath.

@ADITYA-CODE-SOURCE
Copy link
Copy Markdown
Contributor Author

Hey I want to take a step back on this. This PR represents a precedent that we're going to jump through additional hoops to support groovy.

We don't say anything about groovy or other JVM based languages in our versioning policy. And its not that a don't want to support these. But I don't understand what supporting entails. Groovy for example, has different class loading semantics that has runs into issues with the patterns we use to activate different capabilities based on whether or not certain dependencies are present. For example, the metrics, logs, and trace SDKs all behave differently based on whether opentelemetry-api-incubator is present, using techniques like this to detect if the module is present, and helps like this that interact with the standard java classloader in such a way that the incubating classes are only loaded after we verify they are present.

I know the techniques we need to use to make these patterns work with the java class loader. I don't the ways in which groovy class loading is different. I do know that there are differences that are impactful though.

Before establishing a precedent about groovy, I want more analysis to be done about those differences and what it means for the patterns we employ.

I know that its a bigger scope than just solving an issue that appears to be self contained. But some seemingly simple issues have a big can of worms hiding under the surface and this is one of them.

Groovy users can always get around these issues by including the compile only dependencies on their classpath.

@jack-berg That’s a fair point. I’m happy to close this PR if you think the compile-only dependency workaround is sufficient for now, and that any broader JVM-language compatibility discussion should happen separately.

@laurit
Copy link
Copy Markdown
Contributor

laurit commented May 19, 2026

Did you try using @CompileStatic? As far as I understand the only relevant change is in the signature of setConfigProvider. Is calling IncubatingUtil via reflection necessary?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Can't build OpenTelemetrySdk in groovy

4 participants