Skip to content

Add experimental SdkResourceProvider implementation - #8865

Open
jack-berg wants to merge 4 commits into
open-telemetry:mainfrom
jack-berg:sdk-resource-provider
Open

jack-berg wants to merge 4 commits into
open-telemetry:mainfrom
jack-berg:sdk-resource-provider

Conversation

@jack-berg

@jack-berg jack-berg commented Sep 25, 2026 •

Copy link
Copy Markdown
Member

Introduce SdkResourceProvider, representing the ResourceProvider spec concept added in opentelemetry-specification#5057.

Shape:

  • Add new SdkResourceProvider, SdkResourceProviderBuilder.
    • Composed of one or more ResourceDetector (new internal concept). A resource detector is a single source of a resource.
    • The merged resource from the detectors is used to serve the key operation: getResource()
    • SdkResourceProviderBuilder has methods for adding static resources, and in the future can have methods for adding resources who's entity's descriptive attributes are subject to change
  • SdkTracerProviderBuilder, SdkMeterProviderBuilder, SdkLoggerProviderBuilder all have new setResourceProvider(..) methods, which is mutually exclusive with existing setResource(..) / addResource(..) methods
  • SdkTracerProvider, SdkMeterProvider, SdkLoggerProvider all have new getResourceProvider method. This is always available, whether a caller invoked setResourceProvider(..) or setResource(..) / addResource(..). If the later were called, a SdkResourceProvider is derived from the static resource
  • ExtendedOpenTelemetrySdk has a new getSdkResourceProvider() method for accessing the resource provider. The value is derived at construction time by looking at getResourceProvider() of SdkTracerProvider, SdkMeterProvider, SdkLoggerProvider. If they all agree, you get a result. If they disagree, we throw an exception.
  • Inside of SdkLoggerProvider, SdkMeterProvider, SdkTracerProvder are "shared state" objects like LoggerSharedState. These are used to resolve the resource attached to span / metric / logrecord records. These have been updated to attach the result of the resolved SdkResourceProvider.

In followups, we need to:

  • Update autoconfigure / declarative config to attach SdkResourceProviders to SdkMeterProvider, SdkLoggerProvider, SdkTracerProvider instead of a resource
  • Add functionality to be able to re-compute the resource without destroying hot path performance. Currently, getResource() is called on the hotpath for span and log creation. Need to develop a caching / TTL mechanism to occasionally recompute the resource, or shift it off the hot path entirely into some sort of background task.
  • Update autoconfigure to always return an ExtendedOpenTelemetrySdk instance, such that SdkResourceProvider is consistently available whether autoconfigure or declarative config is used

This functionality segues nicely with @jsuereth's #8464: each entity aware resource detector becomes one of these new ResourceDetector instances and are added to SdkResourceProvider. The work josh has done to update the Resource#merge behavior to merge entities is brought over here for free. And we have a natural starting point for refreshing / recomputing resource / entities.

@open-telemetry/java-approvers heads up on this - as well as embodying a new spec concept and helping the entities story, this is the key to unblocking the two additional use cases we identified where consumers of the SDK need to access the resolved resource: opamp and process context sharing.

@jack-berg
jack-berg requested a review from a team as a code owner September 25, 2026 21:47
@opentelemetry-pr-dashboard

opentelemetry-pr-dashboard Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Pull request dashboard status

Waiting on maintainers · refreshed 2026-10-20 20:25 UTC

Merge when ready.

Status above doesn't look right?
  • Just replied or pushed? Anything around or after the refresh time above may not be picked up yet — give it a few minutes.
  • Anything look wrong? Report it with what you expected; it helps us improve the dashboard.

* iteration - all detectors are cached at construction. TTL-based cache invalidation using this
* flag is planned for a future iteration.
*/
boolean shouldReinvoke();

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Since we're not doing anything with this today, we could punt on this. But the whole idea is sort of contrived and pointless without it. There's no need for a dedicated ResourceDetector / ResourceProvider framework when Resource / ResourceBuilder already allow you to iteratively construct a resource.

But Resource/ResourceBuilder break down with entity requirements. The design in this PR tries to accomplish the core goal of making SDK resource information accessible to things like opamp, process context sharing, etc with a forward looking api.

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.

Seems like a bit of future-proofing, which I think is usually discouraged in public APIs since it's so easily added later when it's needed. I'd leave it out, but don't feel strongly about it.

@codecov

codecov Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.78014% with 13 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.41%. Comparing base (63150e0) to head (537723e).
⚠️ Report is 8 commits behind head on main.

Files with missing lines Patch % Lines
...metry/sdk/logs/internal/SdkLoggerProviderUtil.java 69.23% 4 Missing ⚠️
...try/sdk/metrics/internal/SdkMeterProviderUtil.java 69.23% 4 Missing ⚠️
...etry/sdk/trace/internal/SdkTracerProviderUtil.java 69.23% 4 Missing ⚠️
...lemetry/sdk/internal/ExtendedOpenTelemetrySdk.java 94.11% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main    #8865      +/-   ##
============================================
- Coverage     90.61%   90.41%   -0.21%     
- Complexity    10882    10946      +64     
============================================
  Files          1015     1018       +3     
  Lines         29731    29976     +245     
  Branches       3876     3908      +32     
============================================
+ Hits          26942    27104     +162     
- Misses         1872     1921      +49     
- Partials        917      951      +34     

☔ View full report in Codecov by Harness.
📢 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.

import io.opentelemetry.sdk.resources.Resource;
import javax.annotation.Nullable;

final class ConstantResourceDetector implements ResourceDetector {

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.

oooh - interesting. Do you think this needs to be one of the 'out of the box' specified detectors?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Not sure. I did this because I had to. I think it makes sense to build SdkResourceProvider around the idea that resource attributes may change at runtime via entity descriptive attributes, but in practice all resources today (and most in the future) are statically evaluated at config time. So having syntactic sugar to reflect the common case is a must.

BTW I decided (b82c1bd) that the whole notion of a ResourceDetector should be hidden from users. Given that we already have ResourceProvider and ComponentProvider (i.e the declarative config version), having yet another interface for providing resources is too confusing a UX.

Instead, we can just have methods in SdkResourceProviderBuilder which reflect the different styles of resources that might need to be associated with a provider:

public final class SdkResourceProviderBuilder {                                                                                                                                                                                                                                                                                                                                                                                                           
 public SdkResourceProviderBuilder addConstantResource(Resource resource);                                                                                                                                                                                                                                                                                                                                                                               
 public SdkResourceProviderBuilder addConstantResource(Resource resource, @Nullable String name);                                                                                                                                                                                                                                                                                                                                                        
                                                                                                                                                                                                                                                                                                                                                                                                                                                         
 public SdkResourceProvider build();                                                                                                                                                                                                                                                                                                                                                                                                                     
                                                                                                                                                                                                                                                                                                                                                                                                                                                         
 // Proposed future expansion                                                                                                                                                                                                                                                                                                                                                                                                                            
 public SdkResourceProviderBuilder addDetector(Supplier<Resource> resourceSupplier, Duration refreshInterval);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
 public SdkResourceProviderBuilder addDetector(Supplier<Resource> resourceSupplier, Duration refreshInterval, @Nullable String name);                                                                                                                                                                                                                                                                                                                                           
}   

@jsuereth jsuereth left a comment

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.

Awesome! This looks a lot like an earlier prototype of Entities I had, but a good bit cleaner.

Comment thread sdk/all/src/main/java/io/opentelemetry/sdk/internal/ExtendedOpenTelemetrySdk.java Outdated

SdkResourceProvider(List<ResourceDetector> detectors) {
this.detectors = Collections.unmodifiableList(new ArrayList<>(detectors));
this.cachedResource = merge(this.detectors);

@breedx-splk breedx-splk Oct 15, 2026 •

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.

Because the detectors might be doing actual, real work (like going out and discovering or finding stuff)....I don't love the idea of escaping the constructor doing work in the constructor like this, as I think it can lead to a weird class of problem that's hard to troubleshoot, and object construction having side effects is usually unexpected behavior.

Prefer a factory method and passing in the true dependency: Resource.

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.

Ok maybe escaping the constructor usually means leaking this outside the class...so that's not really happening here, but it still makes me twitchy because object construction could have side effects.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Not sure what you mean by escaping the constructor.

This looks odd right now because all detectors are static. But in the future, we want to add detectors that needs to be periodically refreshed.

Comment thread sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProviderBuilder.java Outdated
Comment thread sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProviderBuilder.java Outdated

@breedx-splk breedx-splk left a comment

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.

Looking good here. There's already some approvals, so I'm just holding off to see if any of my suggestions merit follow-ups, but this is mostly solid to me!

Comment thread sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProviderBuilder.java Outdated

This branch has not been deployed

No deployments
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.

5 participants