-
Notifications
You must be signed in to change notification settings - Fork 501
[Metrics] Allow registering one callback for multiple instruments #3667
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
base: main
Are you sure you want to change the base?
[Metrics] Allow registering one callback for multiple instruments #3667
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3667 +/- ##
==========================================
- Coverage 90.14% 89.93% -0.20%
==========================================
Files 222 224 +2
Lines 7154 7255 +101
==========================================
+ Hits 6448 6524 +76
- Misses 706 731 +25
🚀 New features to boost your workflow:
|
67d32ef
to
af792aa
Compare
Is it possiable to drop |
af792aa
to
c182ada
Compare
Is the ask here to essentially do...
i.e. to re-implement the existing single-observable callback functionality in terms of the multi-observable callback functionality? Yes, I can do this - let me know if I understood correctly
This I didn't fully understand, because ObservableCallbackRecord and MultiObservableCallbackRecord are implementation details of the SDK ObservableRegistry; users shouldn't be touching these classes, I thought? (In fact: the definition of |
d75abed
to
f76d7db
Compare
Oh, one more thought; if ObservableRegistry can be thought of as a part of the internal API/ABI of the SDK, I could probably dispense with the ABI version guards in it (since symbols from ObservableRegistry would only be used inside the SDK library itself). this would allow unconditionally reimplementing the existing single-observable callback in terms of the multi-observable implementation. Reckon I should do this? |
Yes, it should be safe to do ABI breaking changes with ObservableRegistry. |
Yes, that's what I want.
We maintain cache of registered callbacks in our project, which allow us to do lazy registration, reload , cleanup and some others things, another group of types will make us to double the cache and APIs to maintain them. BTW: It's OK to break ABI or API in v2 now. |
45c9861
to
0abaaf5
Compare
OK, awesome - I think I've done that, hope this looks right to you 🙏 |
5e5199f
to
6256773
Compare
This commit adds a pair of methods `Meter::RegisterCallback` and `Meter::DeregisterCallback` which allow you to set up one callback which can record observations for multiple observable instruments. The callback will be passed an object of type MultiObserverResult, which can be used to get an ObserverResultT for an instrument. This allows a single expensive operation to yield multiple different observable metrics without the need to call said expensive operation multiple times.
6256773
to
3c168b2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR adds support for registering a single callback function to observe multiple observable instruments, addressing the need to avoid redundant expensive operations when generating multiple related metrics. This implements the multi-instrument callback pattern described in the OpenTelemetry specification.
Key changes include:
- Implementation of
Meter::RegisterCallback()
andMeter::DeregisterCallback()
methods that work with multiple instruments - New
MultiObserverResult
API that allows callbacks to record observations for different instruments - Backward-compatible changes that preserve existing single-instrument callback functionality
Reviewed Changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.
Show a summary per file
File | Description |
---|---|
api/include/opentelemetry/metrics/meter.h | Adds RegisterCallback/DeregisterCallback method signatures for multi-instrument callbacks |
api/include/opentelemetry/metrics/multi_observer_result.h | New API class defining the interface for recording observations across multiple instruments |
api/include/opentelemetry/metrics/noop.h | No-op implementation of the new RegisterCallback/DeregisterCallback methods |
sdk/include/opentelemetry/sdk/metrics/meter.h | SDK implementation declarations for the new callback methods |
sdk/include/opentelemetry/sdk/metrics/multi_observer_result.h | SDK concrete implementation of MultiObserverResult |
sdk/include/opentelemetry/sdk/metrics/state/observable_registry.h | Updated registry interface to support multi-instrument callbacks |
sdk/src/metrics/meter.cc | Implementation of RegisterCallback/DeregisterCallback in the SDK meter |
sdk/src/metrics/multi_observer_result.cc | Implementation of the MultiObserverResult functionality |
sdk/src/metrics/state/observable_registry.cc | Refactored registry to handle both single and multi-instrument callback patterns |
sdk/src/metrics/CMakeLists.txt | Added multi_observer_result.cc to the build |
sdk/test/metrics/multi_observer_test.cc | Comprehensive tests for the new multi-instrument callback functionality |
sdk/test/metrics/CMakeLists.txt | Added multi_observer_test to the test suite |
CHANGELOG.md | Documents the new feature |
Comments suppressed due to low confidence (1)
api/include/opentelemetry/metrics/multi_observer_result.h:1
- Corrected spelling of 'unnescessary' to 'unnecessary'.
// Copyright The OpenTelemetry Authors
namespace | ||
{ | ||
|
||
struct CallbackDeregisterdWhenDestroyedState |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Corrected spelling of 'CallbackDeregisterdWhenDestroyedState' to 'CallbackDeregisteredWhenDestroyedState'.
Copilot uses AI. Check for mistakes.
void callback_deregistered_when_destroyed_callback(metrics::MultiObserverResult &result, | ||
void *vstate) | ||
{ | ||
auto state = reinterpret_cast<CallbackDeregisterdWhenDestroyedState *>(vstate); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The struct name should be corrected to match the fixed spelling: 'CallbackDeregisteredWhenDestroyedState'.
Copilot uses AI. Check for mistakes.
MetricReader *metric_reader_ptr = nullptr; | ||
auto meter = InitMeter(&metric_reader_ptr, "callback_deregistered_when_destroyed_test"); | ||
|
||
CallbackDeregisterdWhenDestroyedState state{}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The struct name should be corrected to match the fixed spelling: 'CallbackDeregisteredWhenDestroyedState'.
Copilot uses AI. Check for mistakes.
Fixes #3653
Changes
This commit adds a pair of methods
Meter::RegisterCallback
andMeter::DeregisterCallback
which allow you to set up one callback which can record observations for multiple observable instruments.The callback will be passed an object of type MultiObserverResult, which can be used to get an ObserverResultT for an instrument.
This allows a single expensive operation to yield multiple different observable metrics without the need to call said expensive operation multiple times.
There's a test demonstrating the usage, but the short version is
Design notes
RegisterCallback
based on the Go SDK, which exposes a RegsiterCallback method on the Meter for this purpose. Is this the right name? Is Meter scope the right place to put this?opentelemetry::metrics::ObservableInstrument
pointer somehow throughstate
in order to record a measurement. This is in line with the interface sketched out in the spec - https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#multiple-instrument-callbacksObserverResultDirect = std::variant<ObserverResultT<double>, ObserverResultT<int64_t>>
when we already haveObserverResult = std::variant<shared_ptr<ObserverResultT<double>>, shared_ptr<ObserverResultT<int64_t>>
but it does get rid of a needless extra heap allocation in the multi instrument case so it's probably for the best?MultiObserverResult
has protectedForInstrumentDouble
andForInstrumentInt64
; this is needed because you can't have a virtual template method, and I wanted the recording interface to look likeres.ForInstrument<int64_t>(instrument).Observe(value)
. We could makeForInstrument
return a variant, but that would require a) exposingObserverResultDirect
as part of the API, and b) requiring the calling code tostd::get
orstd::visit
that.ForInstrument
. However this seems to be what the spec describes, so I've stuck to the spec.Very keen to hear what you think!
CHANGELOG.md
updated for non-trivial changes