Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

otel: conceal unwrapping for global async instrument registration #5881

Open
wants to merge 13 commits into
base: main
Choose a base branch
from

Conversation

jmacd
Copy link
Contributor

@jmacd jmacd commented Oct 10, 2024

Two defects are fixed here. However, note that async instrument delegation appears to have been broken a long time.

Internalizes and tests the behavior of the Global MeterProvider. This moves the call to Unwrap() out of the SDK, fully concealing it within the internal/global package (using an un-exported method).

This adds a test for the new functionality. While this test is not comprehensive, because it doesn't test every instrument variation, it explicitly tests that both the NewCallback function and the Observe functions receive objects constructed by the alternate SDK.

Fixes #5827

Copy link

codecov bot commented Oct 10, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 84.6%. Comparing base (cd754a6) to head (2a906fb).

Additional details and impacted files

Impacted file tree graph

@@          Coverage Diff          @@
##            main   #5881   +/-   ##
=====================================
  Coverage   84.5%   84.6%           
=====================================
  Files        272     272           
  Lines      22840   22829   -11     
=====================================
+ Hits       19313   19314    +1     
+ Misses      3178    3170    -8     
+ Partials     349     345    -4     

see 3 files with indirect coverage changes

@dashpole
Copy link
Contributor

dashpole commented Oct 10, 2024

Is this broken for our SDK as well?

if u, ok := inst.(interface {
Unwrap() metric.Observable
}); ok {
inst = u.Unwrap()
}

@dashpole dashpole added this to the v1.31.0 milestone Oct 10, 2024
@jmacd
Copy link
Contributor Author

jmacd commented Oct 10, 2024

I'm mildly confused by this. My expectation was that the internal/global package would hide details about the delgation and that SDKs would not need to unwrap themselves. Investigating!

@jmacd
Copy link
Contributor Author

jmacd commented Oct 10, 2024

@dashpole PTAL

You pointed me to more tests w/ more nuance. The TestGlobalInstRegisterCallback test in sdk/metric exercises a case with mixed use of pre-registration and post-registration instruments. I've corrected this PR to pass all tests.

The unwrap() method is non-exported again. SDKs should not need to call such a method.

@jmacd
Copy link
Contributor Author

jmacd commented Oct 10, 2024

For what it's worth, I ran the tests in otel-launcher-go that had broken and they are fixed by this PR.

Copy link
Contributor

@dashpole dashpole left a comment

Choose a reason for hiding this comment

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

I tried to figure out why the unwrapping was done in the SDK in #3584, but can't figure it out. This LGTM, but I would really like @MrAlias to review if he remembers why this was done

@jmacd jmacd changed the title (internal/global/meter.go): Fix unwrapping for global async instrument registration (internal/global/meter.go): Unwrapping for global async instrument registration Oct 10, 2024
@jmacd
Copy link
Contributor Author

jmacd commented Oct 10, 2024

@dashpole As we discussed, I'll leave this open.
I think it is safe to release this repo as-is. The fact that unwrap() is called, doing nothing, appears harmless for OTel-Go SDK users. For the alternate SDK user, I can work around this by calling Unwrap(). I would be glad to see this PR applied after the release, but I'll accept if you decide to keep calling Unwrap() the SDK's responsibility. If so, I'd propose to add a public Unwrap interface and documentation. I'll leave it up to you and @MrAlias. Thanks!

@jmacd jmacd changed the title (internal/global/meter.go): Unwrapping for global async instrument registration (internal/global/meter.go): Conceal unwrapping for global async instrument registration Oct 10, 2024
Copy link
Contributor

@dashpole dashpole left a comment

Choose a reason for hiding this comment

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

I would like to wait to merge this until after the release.

@pellared
Copy link
Member

Do we want to make a patch release after this is merged?

@dashpole
Copy link
Contributor

Do we want to make a patch release after this is merged?

I don't think so. This fixes a bug for alternative SDKs. Based on #5881 (comment), @jmacd is going to work around the issue in the meantime.

@MrAlias MrAlias modified the milestones: v1.31.0, v1.32.0 Oct 14, 2024
jmacd added a commit to lightstep/otel-launcher-go that referenced this pull request Oct 15, 2024
**Description:** Updates to OTel-Go 1.31 require minor LS Metric SDK
fixes (see Unwrap()), discussed and fixed in the upstream PR
open-telemetry/opentelemetry-go#5881. The
Unwrap() calls here are to work around the problem until fully fixed
upstream.

**Link to tracking Issue:**
open-telemetry/opentelemetry-go#5827 explains
how we got here.

Part of #794.

**Testing:** Incomplete. Existing tests were logging messages about
foreign instruments in the asynchronous call path, but nothing failed as
a result.
@jmacd
Copy link
Contributor Author

jmacd commented Oct 16, 2024

I worked around the problem as stated above, so I consider this a nice-to-have low priority fix. The workaround, in case anyone else cares, is

	if unwrapped, ok := inst.(interface {
		Unwrap() metric.Observable
	}); ok {
		inst = unwrapped.Unwrap()
	}

I needed to do this in two places related to asynchronous instrument handling. The global package hides this detail as far as synchronous instruments are concerned. Link.

@pellared pellared changed the title (internal/global/meter.go): Conceal unwrapping for global async instrument registration otel: conceal unwrapping for global async instrument registration Oct 16, 2024
@pellared pellared added the pkg:API Related to an API package label Oct 16, 2024

func (uo *unwrapObs) ObserveFloat64(inst metric.Float64Observable, value float64, opts ...metric.ObserveOption) {
if un, ok := inst.(unwrapper); ok {
inst = un.unwrap().(metric.Float64Observable)
Copy link
Contributor

Choose a reason for hiding this comment

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

This will panic if this is an invalid type conversion, whereas before it would be logged as an error.

Can we log this as an error? Or, better yet, include a specific unwrappableFloat64Observable type?

type unwrapFloat64Observabler interface {
	unwrapFloat64Observable() metric.Float64Observable
}

and similar for Int64Observable?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pkg:API Related to an API package
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Regression: Delegation broken for global meterproviders
5 participants