Skip to content

Commit 32dec75

Browse files
committed
Merged from upstream
2 parents 8d4dab7 + 767ef30 commit 32dec75

File tree

13 files changed

+756
-64
lines changed

13 files changed

+756
-64
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ Increment the:
1717

1818
* [TEST] Remove workaround for metrics cardinality limit test
1919
[#3663](https://github.com/open-telemetry/opentelemetry-cpp/pull/3663)
20+
* [METRICS] Allow registering one callback for multiple instruments
21+
[#3667](https://github.com/open-telemetry/opentelemetry-cpp/pull/3667)
2022

2123
* [SDK] Fix typo in hashmap method GetEnteries
2224
[#3680](https://github.com/open-telemetry/opentelemetry-cpp/pull/3680)

api/include/opentelemetry/metrics/meter.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33

44
#pragma once
55

6+
#include <cstdint>
7+
68
#include "opentelemetry/version.h"
79
#include "opentelemetry/nostd/shared_ptr.h"
10+
#include "opentelemetry/nostd/span.h"
811
#include "opentelemetry/nostd/string_view.h"
912
#include "opentelemetry/nostd/unique_ptr.h"
1013

@@ -25,6 +28,8 @@ template <typename T>
2528
class Gauge;
2629

2730
class ObservableInstrument;
31+
class MultiObserverResult;
32+
using MultiObservableCallbackPtr = void (*)(MultiObserverResult &, void *);
2833

2934
/**
3035
* Handles instrument creation and provides a facility for batch recording.
@@ -169,6 +174,32 @@ class Meter
169174
nostd::string_view name,
170175
nostd::string_view description = "",
171176
nostd::string_view unit = "") noexcept = 0;
177+
178+
#if OPENTELEMETRY_ABI_VERSION_NO >= 2
179+
180+
/**
181+
* Registers a callback to be invoked when metrics are collected by this meter. The callback will
182+
* be passed a MultiObserverResult which it can use to make observations for any or all of the
183+
* instruments provided in this registration. Any measurements recorded for instruments _not_ in
184+
* the initial RegisterCallback call will be discarded.
185+
*
186+
* @param callback the callback to be invoked.
187+
* @param state the state to be passed to the callback.
188+
* @param instruments the instruments to be observed.
189+
* @return a unique identifier for the registered callback, which can be used to unregister the
190+
* callback in DeregisterCallback.
191+
*/
192+
virtual uintptr_t RegisterCallback(MultiObservableCallbackPtr callback,
193+
void *state,
194+
nostd::span<ObservableInstrument *> instruments) noexcept = 0;
195+
196+
/**
197+
* Unregisters a callback previously registered with RegisterCallback.
198+
*
199+
* @param callback_id the unique identifier returned by RegisterCallback.
200+
*/
201+
virtual void DeregisterCallback(uintptr_t callback_id) noexcept = 0;
202+
#endif
172203
};
173204
} // namespace metrics
174205
OPENTELEMETRY_END_NAMESPACE
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
#pragma once
5+
6+
#include <cstdint>
7+
8+
#include "opentelemetry/metrics/async_instruments.h"
9+
#include "opentelemetry/metrics/observer_result.h"
10+
#include "opentelemetry/version.h"
11+
12+
OPENTELEMETRY_BEGIN_NAMESPACE
13+
namespace metrics
14+
{
15+
16+
class MultiObserverResult
17+
{
18+
19+
public:
20+
virtual ~MultiObserverResult() = default;
21+
22+
/**
23+
* Obtain an ObserverResultT<T> for the given instrument, that can be used to record
24+
* a measurement on said instrument from a multi-observer callback registered with
25+
* Meter::RegisterCallback. The instrument _must_ have been included in the original
26+
* call to Meter::RegisterCallback; any data points set on other instruments will be
27+
* discarded.
28+
*
29+
* @param instrument The instrument for which to obtain an ObserverResult.
30+
* @return An ObserverResultT<T> for the given instrument.
31+
*/
32+
template <typename T>
33+
ObserverResultT<T> &ForInstrument(const ObservableInstrument *instrument) = delete;
34+
35+
protected:
36+
// You can't have a virtual template, and you can't overload on return type, so we need to
37+
// enumerate the options for the observer result type as separate methods to override.
38+
virtual ObserverResultT<double> &ForInstrumentDouble(const ObservableInstrument *instrument) = 0;
39+
virtual ObserverResultT<int64_t> &ForInstrumentInt64(const ObservableInstrument *instrument) = 0;
40+
};
41+
42+
template <>
43+
inline ObserverResultT<double> &MultiObserverResult::ForInstrument<double>(
44+
const ObservableInstrument *instrument)
45+
{
46+
return ForInstrumentDouble(instrument);
47+
}
48+
49+
template <>
50+
inline ObserverResultT<int64_t> &MultiObserverResult::ForInstrument<int64_t>(
51+
const ObservableInstrument *instrument)
52+
{
53+
return ForInstrumentInt64(instrument);
54+
}
55+
56+
} // namespace metrics
57+
OPENTELEMETRY_END_NAMESPACE

api/include/opentelemetry/metrics/noop.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,18 @@ class NoopMeter final : public Meter
229229
return nostd::shared_ptr<ObservableInstrument>(
230230
new NoopObservableInstrument(name, description, unit));
231231
}
232+
233+
#if OPENTELEMETRY_ABI_VERSION_NO >= 2
234+
uintptr_t RegisterCallback(
235+
MultiObservableCallbackPtr /* callback */,
236+
void * /* state */,
237+
nostd::span<ObservableInstrument *> /* instruments */) noexcept override
238+
{
239+
return 0;
240+
}
241+
242+
void DeregisterCallback(uintptr_t /* callback_id */) noexcept override {}
243+
#endif
232244
};
233245

234246
/**

sdk/include/opentelemetry/sdk/metrics/meter.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,14 @@ class OPENTELEMETRY_EXPORT_TYPE Meter final : public opentelemetry::metrics::Met
131131
std::vector<MetricData> Collect(CollectorHandle *collector,
132132
opentelemetry::common::SystemTimestamp collect_ts) noexcept;
133133

134+
#if OPENTELEMETRY_ABI_VERSION_NO >= 2
135+
uintptr_t RegisterCallback(
136+
opentelemetry::metrics::MultiObservableCallbackPtr callback,
137+
void *state,
138+
nostd::span<opentelemetry::metrics::ObservableInstrument *> instruments) noexcept override;
139+
140+
void DeregisterCallback(uintptr_t callback_id) noexcept override;
141+
#endif
134142
private:
135143
// order of declaration is important here - instrumentation scope should destroy after
136144
// meter-context.
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
#pragma once
5+
6+
#include <unordered_map>
7+
8+
#include "opentelemetry/metrics/async_instruments.h"
9+
#include "opentelemetry/metrics/multi_observer_result.h"
10+
#include "opentelemetry/metrics/observer_result.h"
11+
#include "opentelemetry/nostd/function_ref.h"
12+
#include "opentelemetry/nostd/variant.h"
13+
#include "opentelemetry/sdk/metrics/observer_result.h"
14+
#include "opentelemetry/version.h"
15+
16+
OPENTELEMETRY_BEGIN_NAMESPACE
17+
namespace sdk
18+
{
19+
namespace metrics
20+
{
21+
class OPENTELEMETRY_EXPORT MultiObserverResult final
22+
: public opentelemetry::metrics::MultiObserverResult
23+
{
24+
public:
25+
void RegisterInstrument(opentelemetry::metrics::ObservableInstrument *instrument);
26+
void DeregisterInstrument(opentelemetry::metrics::ObservableInstrument *instrument);
27+
size_t InstrumentCount() const;
28+
bool HasInstrument(const opentelemetry::metrics::ObservableInstrument *instrument) const;
29+
void GetInstruments(
30+
nostd::function_ref<void(opentelemetry::metrics::ObservableInstrument *)> callback);
31+
void Reset();
32+
void StoreResults(opentelemetry::common::SystemTimestamp collection_ts);
33+
34+
protected:
35+
opentelemetry::metrics::ObserverResultT<double> &ForInstrumentDouble(
36+
const opentelemetry::metrics::ObservableInstrument *instrument) override;
37+
opentelemetry::metrics::ObserverResultT<int64_t> &ForInstrumentInt64(
38+
const opentelemetry::metrics::ObservableInstrument *instrument) override;
39+
40+
private:
41+
// This is _different_ to opentelemetry::metrics::ObserverResult because this variant is
42+
// a variant directly of ObserverResultT, not of _pointers_ to ObserverResultT.
43+
// This allows us to avoid an unnescessary layer of inderection and a bunch of allocations.
44+
using ObserverResultDirect =
45+
nostd::variant<nostd::monostate, ObserverResultT<double>, ObserverResultT<int64_t>>;
46+
std::unordered_map<opentelemetry::metrics::ObservableInstrument *, ObserverResultDirect>
47+
observer_results_;
48+
};
49+
} // namespace metrics
50+
} // namespace sdk
51+
52+
OPENTELEMETRY_END_NAMESPACE

sdk/include/opentelemetry/sdk/metrics/state/observable_registry.h

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,53 @@
33

44
#pragma once
55

6+
#include <cstdint>
67
#include <memory>
78
#include <mutex>
89
#include <vector>
910

1011
#include "opentelemetry/version.h"
1112
#include "opentelemetry/common/timestamp.h"
1213
#include "opentelemetry/metrics/async_instruments.h"
14+
#include "opentelemetry/metrics/meter.h"
15+
#include "opentelemetry/sdk/metrics/multi_observer_result.h"
16+
#include "opentelemetry/version.h"
17+
18+
#if OPENTELEMETRY_ABI_VERSION_NO >= 2
19+
# include <unordered_map>
20+
# include "opentelemetry/nostd/span.h"
21+
#endif
1322

1423
OPENTELEMETRY_BEGIN_NAMESPACE
1524
namespace sdk
1625
{
1726
namespace metrics
1827
{
1928

20-
struct ObservableCallbackRecord
21-
{
22-
opentelemetry::metrics::ObservableCallbackPtr callback;
23-
void *state;
24-
opentelemetry::metrics::ObservableInstrument *instrument;
25-
};
29+
struct ObservableCallbackRecord;
2630

2731
class OPENTELEMETRY_EXPORT_TYPE ObservableRegistry
2832
{
2933
public:
34+
// Constructor & destructor need to be defined in the observable_registry.cc TU, rather
35+
// than implicitly defaulted here, so that we can have a unique_ptr to an incomplete
36+
// class as a member.
37+
ObservableRegistry();
38+
~ObservableRegistry();
39+
40+
// Add a callback of the single-instrument form
3041
void AddCallback(opentelemetry::metrics::ObservableCallbackPtr callback,
3142
void *state,
3243
opentelemetry::metrics::ObservableInstrument *instrument);
33-
44+
// Add a callback with the multi-instrument signature
45+
uintptr_t AddCallback(opentelemetry::metrics::MultiObservableCallbackPtr callback,
46+
void *state,
47+
nostd::span<opentelemetry::metrics::ObservableInstrument *> instruments);
48+
// Callbacks added with Meter::RegisterCallback have can be removed by passing back the handle
49+
// returned
50+
void RemoveCallback(uintptr_t id);
51+
// Callbacks added with ObservableInstrument::AddCallback can be removed by passing back the
52+
// original (callback function, state, instrument).
3453
void RemoveCallback(opentelemetry::metrics::ObservableCallbackPtr callback,
3554
void *state,
3655
opentelemetry::metrics::ObservableInstrument *instrument);
@@ -40,7 +59,7 @@ class OPENTELEMETRY_EXPORT_TYPE ObservableRegistry
4059
void Observe(opentelemetry::common::SystemTimestamp collection_ts);
4160

4261
private:
43-
std::vector<std::unique_ptr<ObservableCallbackRecord>> callbacks_;
62+
std::unordered_map<uintptr_t, std::unique_ptr<ObservableCallbackRecord>> callbacks_;
4463
std::mutex callbacks_m_;
4564
};
4665

sdk/src/metrics/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ add_library(
1212
meter_context.cc
1313
meter_context_factory.cc
1414
metric_reader.cc
15+
multi_observer_result.cc
1516
instrument_metadata_validator.cc
1617
export/periodic_exporting_metric_reader.cc
1718
export/periodic_exporting_metric_reader_factory.cc

sdk/src/metrics/meter.cc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@
4444
# include "opentelemetry/sdk/metrics/exemplar/reservoir_utils.h"
4545
#endif
4646

47+
#if OPENTELEMETRY_ABI_VERSION_NO >= 2
48+
# include "opentelemetry/metrics/meter.h"
49+
#endif
50+
4751
namespace
4852
{
4953

@@ -663,6 +667,21 @@ std::vector<MetricData> Meter::Collect(CollectorHandle *collector,
663667
return metric_data_list;
664668
}
665669

670+
#if OPENTELEMETRY_ABI_VERSION_NO >= 2
671+
uintptr_t Meter::RegisterCallback(
672+
opentelemetry::metrics::MultiObservableCallbackPtr callback,
673+
void *state,
674+
nostd::span<opentelemetry::metrics::ObservableInstrument *> instruments) noexcept
675+
{
676+
return observable_registry_->AddCallback(callback, state, instruments);
677+
}
678+
679+
void Meter::DeregisterCallback(uintptr_t callback_id) noexcept
680+
{
681+
observable_registry_->RemoveCallback(callback_id);
682+
}
683+
#endif
684+
666685
// Implementation of the log message recommended by the SDK specification for duplicate instruments.
667686
// See
668687
// https://github.com/open-telemetry/opentelemetry-specification/blob/9c8c30631b0e288de93df7452f91ed47f6fba330/specification/metrics/sdk.md?plain=1#L882

0 commit comments

Comments
 (0)