Repository navigation
Conversation
Pull request dashboard statusWaiting on the author · refreshed 2026-11-03 16:15 UTC Respond to 1 review item (e.g. link a commit, explain why not, ask a follow-up):
Status above doesn't look right?
|
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #8979 +/- ##
============================================
- Coverage 90.39% 90.37% -0.02%
- Complexity 10997 11018 +21
============================================
Files 1020 1020
Lines 30096 30170 +74
Branches 3929 3939 +10
============================================
+ Hits 27204 27267 +63
- Misses 1937 1942 +5
- Partials 955 961 +6 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
psx95
left a comment
There was a problem hiding this comment.
When registering the associated storage for metrics in SdkMeter, if a view has drop aggregation, then the storage for that is skipped. This could probably cause an issue in the intended functionality because opentelemetry-java evaluates each matching RegisteredView independently in SdkMeter and simply skips (continue) any view whose aggregation is Aggregation.drop(), registering both:
- InstrumentSelector("*") →
enabled = true - InstrumentSelector("my.unwanted.instrument") →
enabled = falseand this will not disable "my.unwanted.instrument" since the second view turns intoAggregation.drop()and is skipped by SdkMeter, while the first view (*) still registers a live MetricStorage for "my.unwanted.instrument".
IIUC, this is a key use-case of the spec, right?
| UnaryOperator<Attributes> attributesFilter, | ||
| int cardinalityLimit, | ||
| SourceInfo viewSourceInfo, | ||
| @Nullable Boolean enabled) { |
There was a problem hiding this comment.
Why is this Nullable? We already have a constructor which can be used when the user does not wish to explicitly provide enabled.
There was a problem hiding this comment.
SdkMeterProviderBuilder#registerView and ViewRegistry pass view.getEnabled() / registeredView.getEnabled() (which is @Nullable Boolean—null when unset, true, or false) directly into this 6-argument create method, so @Nullable avoids requiring a null check at each call site. The 5-argument overload is just a convenience for internal default views (DEFAULT_REGISTERED_VIEW, DROP_REGISTERED_VIEW) and tests that don't have a View with enabled.
| assertThat(counter2.isEnabled()).isFalse(); | ||
|
|
||
| counter1.add(1); | ||
| counter2.add(1); |
There was a problem hiding this comment.
nit: Perhaps adding an assertion to reflect the expected behavior of updating a disabled counter might be good.
There was a problem hiding this comment.
addressed in e5409e0 (satisfiesExactly asserts that collectAllMetrics() only contains counter1 and that counter2's measurement was dropped; added a comment above the assertion to make that explicit).
|
|
||
| private static RegisteredView applyAdviceToDefaultView( | ||
| RegisteredView instrumentDefaultView, Advice advice) { | ||
| RegisteredView registeredView, Advice advice) { |
There was a problem hiding this comment.
Just curious: Why the name change?
There was a problem hiding this comment.
Previously applyAdviceToDefaultView was only called on instrumentDefaultView when no view matched. Since it is now also called at line 128 on a matched RegisteredView (entry) when enabled=true and the view did not specify an attribute filter, I generalized the parameter name to registeredView.
| if (matchesSelector(entry.getInstrumentSelector(), descriptor, meterScope)) { | ||
| if (Boolean.FALSE.equals(entry.getEnabled())) { | ||
| result.add(applyDropAggregation(entry)); | ||
| continue; |
There was a problem hiding this comment.
This would force the next iteration without checking isCompatibleWithInstrument verification.
| if (descriptor.getAdvice().isOptIn() && !Boolean.TRUE.equals(entry.getEnabled())) { | ||
| result.add(applyDropAggregation(entry)); | ||
| } else if (Boolean.TRUE.equals(entry.getEnabled()) | ||
| && descriptor.getAdvice().hasAttributes() | ||
| && entry.getView().getAttributeFilter().equals(StringPredicates.ALL)) { | ||
| result.add(applyAdviceToDefaultView(entry, descriptor.getAdvice())); | ||
| } else { | ||
| result.add(entry); |
There was a problem hiding this comment.
Can we add minor comments on these if-else conditions to clarify the intent here?
Currently, it seems like on a standard instrument (OptIn = false) with AttributesAdvice would be treated differently depending on enabled being unset or true.
Setting enabled = true on a standard instrument would cause the advice to be applied, but leaving enabled unset would not. But it looks like this is a side effect of the current implementation rather than intention.
There was a problem hiding this comment.
addressed in e942aa3. And yes, on OptIn=false instruments when enabled is unset, matching views without an attribute filter currently ignore Attributes advice due to #7134 (pre-dating open-telemetry/opentelemetry-specification#4389), whereas for enabled=true we preserve Attributes advice so enabling an OptIn instrument via a view respects its other advisory parameters per open-telemetry/opentelemetry-specification#4809.
7bbc2e1 to
e942aa3
Compare
dashpole
left a comment
There was a problem hiding this comment.
When registering the associated storage for metrics in
SdkMeter, if a view has drop aggregation, then the storage for that is skipped... IIUC, this is a key use-case of the spec, right?
In the Metrics SDK specification (Measurement processing), that difference comes down to view_matching_mode:
- In
view_matching_mode: independent(the default, and whatopentelemetry-javacurrently implements), each matchingViewis evaluated independently without merging across views—so just as registeringInstrumentSelector("*")(withDefaultAggregation) alongsideInstrumentSelector("my.unwanted.instrument")withAggregation.drop()still exports"my.unwanted.instrument"from the first wildcard view today,enabledonly controls the stream produced by that view. (Inindependentmode, you can disable all instruments by default withInstrumentSelector("*")->enabled = falseand selectively enableInstrumentSelector("my.wanted.instrument")->enabled = true.) - Overriding
InstrumentSelector("*")->enabled = truewith a subsequentInstrumentSelector("my.unwanted.instrument")->enabled = falseis supported underview_matching_mode: composable(open-telemetry/opentelemetry-specification#5173), which merges matching views with the same stream name in registration order using last-wins precedence forenabled,aggregation,description, andaggregation_cardinality_limit.
| UnaryOperator<Attributes> attributesFilter, | ||
| int cardinalityLimit, | ||
| SourceInfo viewSourceInfo, | ||
| @Nullable Boolean enabled) { |
There was a problem hiding this comment.
SdkMeterProviderBuilder#registerView and ViewRegistry pass view.getEnabled() / registeredView.getEnabled() (which is @Nullable Boolean—null when unset, true, or false) directly into this 6-argument create method, so @Nullable avoids requiring a null check at each call site. The 5-argument overload is just a convenience for internal default views (DEFAULT_REGISTERED_VIEW, DROP_REGISTERED_VIEW) and tests that don't have a View with enabled.
| assertThat(counter2.isEnabled()).isFalse(); | ||
|
|
||
| counter1.add(1); | ||
| counter2.add(1); |
There was a problem hiding this comment.
addressed in e5409e0 (satisfiesExactly asserts that collectAllMetrics() only contains counter1 and that counter2's measurement was dropped; added a comment above the assertion to make that explicit).
|
|
||
| private static RegisteredView applyAdviceToDefaultView( | ||
| RegisteredView instrumentDefaultView, Advice advice) { | ||
| RegisteredView registeredView, Advice advice) { |
There was a problem hiding this comment.
Previously applyAdviceToDefaultView was only called on instrumentDefaultView when no view matched. Since it is now also called at line 128 on a matched RegisteredView (entry) when enabled=true and the view did not specify an attribute filter, I generalized the parameter name to registeredView.
| if (matchesSelector(entry.getInstrumentSelector(), descriptor, meterScope)) { | ||
| if (Boolean.FALSE.equals(entry.getEnabled())) { | ||
| result.add(applyDropAggregation(entry)); | ||
| continue; |
| if (descriptor.getAdvice().isOptIn() && !Boolean.TRUE.equals(entry.getEnabled())) { | ||
| result.add(applyDropAggregation(entry)); | ||
| } else if (Boolean.TRUE.equals(entry.getEnabled()) | ||
| && descriptor.getAdvice().hasAttributes() | ||
| && entry.getView().getAttributeFilter().equals(StringPredicates.ALL)) { | ||
| result.add(applyAdviceToDefaultView(entry, descriptor.getAdvice())); | ||
| } else { | ||
| result.add(entry); |
There was a problem hiding this comment.
addressed in e942aa3. And yes, on OptIn=false instruments when enabled is unset, matching views without an attribute filter currently ignore Attributes advice due to #7134 (pre-dating open-telemetry/opentelemetry-specification#4389), whereas for enabled=true we preserve Attributes advice so enabling an OptIn instrument via a view respects its other advisory parameters per open-telemetry/opentelemetry-specification#4809.
…dMetricsApiUsageTest
…g View enabled=false
e942aa3 to
1eb12d5
Compare
Summary
Implements the experimental
OptIninstrument advisory parameter andViewenabledstream configuration defined in open-telemetry/opentelemetry-specification#4809:opentelemetry-api-incubator):setOptInAdvice(boolean)(default no-op) to all 8Extended*Builderinterfaces (ExtendedDoubleCounterBuilder,ExtendedDoubleGaugeBuilder,ExtendedDoubleHistogramBuilder,ExtendedDoubleUpDownCounterBuilder,ExtendedLongCounterBuilder,ExtendedLongGaugeBuilder,ExtendedLongHistogramBuilder,ExtendedLongUpDownCounterBuilder).opentelemetry-sdk-metrics):isOptIn()/setOptIn(boolean)to internalAdvice/AdviceBuilderand wiressetOptInAdvice(boolean)across allExtendedSdk*Builderimplementations (preservingoptInacross.ofDoubles()/.ofLongs()builder swaps).ViewBuilder#setEnabled(boolean)andView#getEnabled(), exposed experimentally viaSdkMeterProviderUtil#setEnabled(ViewBuilder, boolean).ViewRegistry#findViewsso that:OptIn=trueuseAggregation.drop()by default when no view matches or when a matching view does not setenabled=true.enabled=falseuseAggregation.drop()regardless of the view's configured aggregation.enabled=trueenableOptIn=trueinstruments while still respecting other instrument advisory parameters (AttributesandExplicitBucketBoundaries) unless overridden by the view.