Skip to content

LazyStorage initializer uses default ServiceLoader context classloader #7427

@indigophox

Description

@indigophox

Describe the bug
LazyStorage's static initializer block calls ServiceLoader.load(), which in turn uses the Thread context classloader.

This easily becomes inconsistent in multi-classloader applications, where the Class reference passed to the method is from LazyStorage's context but the Thread context classloader (not easily controlled by the application due to how class initializers are invoked in separate, anonymous threads) may be inconsistent and

Steps to reproduce
Most of the work here is creating an application with its own application classpath and modules therein.

With that in place (any arbitrary application will do), set a breakpoint at the start of the LazyStorage static block, and call the following prior to resuming the app:

Thread.currentThread.setContextClassLoader(new URLClassLoader(LazyStorage.class.getClassLoader().getURLs(), LazyStorage.class.getClassLoader().getParent()))

The call to ServiceLoader.load() should then throw a ServiceConfigurationError stating java.util.serviceConfigurationError: io.opentelemetry.context.ContextStorageProvider: io.opentelementry.sdk.testing.context.SettableContextStorageProvider is not a subtype.

What did you expect to see?
LazyStorage initializes without throwing.

What did you see instead?
java.util.serviceConfigurationError as above.

What version and what artifacts are you using?
Orthgonal to bug.

Environment
Orthogonal to bug.

Additional context
Affected application is using a separate URLClassLoader around a 3P dependency that then depends on OpenTelemetry. As above the Thread context classloader when LazyStorage it initialized is not controlled by the application and uses the application default classloader, which is incompatible with the classloader visible to/inherited by LazyStorage.

This bug can also be inelegantly mitigated by setting the system property io.opentelemetry.context.contextStorageProvider to default, however this is in no way guaranteed to continue to bypass the call to ServiceLoader.load() in future LazyStorage code.

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions