-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Asynchronous Instrument API non-compliant with OTel Specification: creation does not accept callbacks #3451
Comments
This will break the symmetry with the sync instrument options, but it looks like the solution will be to add some |
The way I read the specification, the current asynchronous API is compliant. You wrote "Our current metric API does not accept That is true, however, I had parsed the "or" in that statement as allowing instrument creation with ONLY zero callback functions, to allow the current form of |
That's how I read it as well, but I seemed to be alone and I could see the other interpretation (must accept list of callbacks, even if its length is zero) as valid as well. v0v |
I think it could be better specified if "or" is non-exclusive similar to the rest of the document, or it is meant to be exclusive. But I believe the intent is the common non-exclusive use. Meaning a users should be allowed to pass callback but they can also choose to not pass callbacks if they want. Given the purpose of the specification is to maintain compatibility across implementations, and all the other stable releases I have looked at offer this, I think we need to as well. |
This is going to be important to address at this point in time as the symmetry breaking between sync and async instrument options is one we need to fix now or forever live with. If we went stable without adjusting this we would not be able to support a callback option or would have to ignore it for sync instrument creations. |
😁 I think I wrote this sentence, and I wrote it after the current Go async instrument API was adopted thinking it would allow it to pass. To me, it's in the spirit of Go to reduce the number of optional ways of configuring something. I also see how Considering this alongside #3452 I would suggest that |
Agreed. It was pointed in the SIG meeting that the specification also says these should be "permanently registered" which motivated a consensus to agree with this there. |
The approach in #3507 works well to ensure that the instrument the callback is registered for is the only instrument allowed to be updated:
However, this also means the user needs to make a type conversion before they can observe. E.g. _, err := meter.AsyncInt64().Gauge(
"MemoryUsage",
WithUnit(unit.Bytes),
WithCallback(func(ctx context.Context, instrument Asynchronous) error {
// Do Work to get the real memoryUsage.
// mem := GatherMemory(ctx)
mem := 75000
instrument.(asyncint64.Gauge).Observe(ctx, int64(mem))
return nil
}),
) This is not ideal. It requires users to understand this is needed and opens up the possibility of a panic if a bug is introduced. It would be great if we could design a callback that will ensure that only the instrument it is registered for is updated, but also avoid having the user do this type conversion. AlternatesTyped callback return valuestype CallbackInt64 func(context.Context) (int64, error)
type CallbackFloat64 func(context.Context) (float64, error) Which would mean that the async options would further have to be split by type. E.g. func WithCallbackInt64(CallbackInt64) AsynchronousInt64Option
func WithCallbackFloat64(CallbackFloat64) AsynchronousFloat64Option Using generics here would be helpful, but we are trying to not include them in the API. This will have overhead in the SDK where these callback types will need to be stored separately. Typed callback parameterstype AsynchronousInt64 interface {
Asynchronous
Observe(context.Context, int64, ...attribute.KeyValue)
}
type AsynchronousFloat64 interface {
Asynchronous
Observe(context.Context, float64, ...attribute.KeyValue)
}
type CallbackInt64 func(context.Context, AsynchronousInt64) error
type CallbackFloat64 func(context.Context, AsynchronousFloat64) error
func WithCallbackInt64(CallbackInt64) AsynchronousInt64Option
func WithCallbackFloat64(CallbackFloat64) AsynchronousFloat64Option This will as well have overhead in the SDK where these callback types will need to be stored separately. |
The "Typed callback return values" proposal would allow for the callbacks to be inlined and avoid a GC ref count on the passed instrument. |
Splitting options and callbacks into the already existing async/sync packages allows this duplication to be a bit more reasonable. I'm going to update #3057 to use the "Typed callback return values" proposal and split the options this way. |
The return value will need to be a slice of attribute to value pairs. Updating in the update. |
Description
The OpenTelemetry specification states:
Our current metric API does not accept "zero or more
callback
functions" for new async instruments.The text was updated successfully, but these errors were encountered: