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

[API] Add synchronous gauge #3029

Merged
merged 10 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions api/include/opentelemetry/metrics/meter.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ class Histogram;
template <typename T>
class UpDownCounter;

template <typename T>
class Gauge;

class ObservableInstrument;

/**
Expand Down Expand Up @@ -91,6 +94,25 @@ class Meter
nostd::string_view description = "",
nostd::string_view unit = "") noexcept = 0;

/**
* Creates a Gauge with the passed characteristics and returns a unique_ptr to that Counter.
marcalff marked this conversation as resolved.
Show resolved Hide resolved
*
* @param name the name of the new Gauge.
* @param description a brief description of what the Gauge is used for.
* @param unit the unit of metric values following https://unitsofmeasure.org/ucum.html.
* @return a unique pointer to the created Gauge.
*/

virtual nostd::unique_ptr<Gauge<int64_t>> CreateInt64Gauge(
nostd::string_view name,
nostd::string_view description = "",
nostd::string_view unit = "") noexcept = 0;

virtual nostd::unique_ptr<Gauge<double>> CreateDoubleGauge(
nostd::string_view name,
nostd::string_view description = "",
nostd::string_view unit = "") noexcept = 0;
marcalff marked this conversation as resolved.
Show resolved Hide resolved

/**
* Creates a Asynchronous (Observable) Gauge with the passed characteristics and returns a
* shared_ptr to that Observable Gauge
Expand Down
34 changes: 34 additions & 0 deletions api/include/opentelemetry/metrics/noop.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,24 @@ class NoopUpDownCounter : public UpDownCounter<T>
{}
};

template <class T>
class NoopGauge : public Gauge<T>
{
public:
NoopGauge(nostd::string_view /* name */,
nostd::string_view /* description */,
nostd::string_view /* unit */) noexcept
{}
~NoopGauge() override = default;
void Record(T /* value */) noexcept override {}
void Record(T /* value */, const context::Context & /* context */) noexcept override {}
void Record(T /* value */, const common::KeyValueIterable & /* attributes */) noexcept override {}
void Record(T /* value */,
const common::KeyValueIterable & /* attributes */,
const context::Context & /* context */) noexcept override
{}
};

class NoopObservableInstrument : public ObservableInstrument
{
public:
Expand Down Expand Up @@ -140,6 +158,22 @@ class NoopMeter final : public Meter
return nostd::unique_ptr<Histogram<double>>{new NoopHistogram<double>(name, description, unit)};
}

nostd::unique_ptr<Gauge<int64_t>> CreateInt64Gauge(
nostd::string_view name,
nostd::string_view description = "",
nostd::string_view unit = "") noexcept override
{
return nostd::unique_ptr<Gauge<int64_t>>{new NoopGauge<int64_t>(name, description, unit)};
}

nostd::unique_ptr<Gauge<double>> CreateDoubleGauge(
nostd::string_view name,
nostd::string_view description = "",
nostd::string_view unit = "") noexcept override
{
return nostd::unique_ptr<Gauge<double>>{new NoopGauge<double>(name, description, unit)};
}

nostd::shared_ptr<ObservableInstrument> CreateInt64ObservableGauge(
nostd::string_view name,
nostd::string_view description = "",
Expand Down
75 changes: 75 additions & 0 deletions api/include/opentelemetry/metrics/sync_instruments.h
Original file line number Diff line number Diff line change
Expand Up @@ -247,5 +247,80 @@ class UpDownCounter : public SynchronousInstrument
}
};

/* A Gauge instrument that records values. */
template <class T>
class Gauge : public SynchronousInstrument
{

public:
/**
* Record a value
*
* @param value The measurement value. May be positive, negative or zero.
Copy link
Contributor

Choose a reason for hiding this comment

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

not blocking the merge. Seems T should be integer or float types? If so, could it be asserted explicitly like below?

static_assert(std::is_same_v<T, int64_t> || std::is_same_v<T, double>, "Gauge<T> can only be instantiated with int64_t or double");

*/
virtual void Record(T value) noexcept = 0;

/**
* Record a value
*
* @param value The measurement value. May be positive, negative or zero.
* @param context The explicit context to associate with this measurement.
*/
virtual void Record(T value, const context::Context &context) noexcept = 0;

/**
* Record a value with a set of attributes.
*
* @param value The measurement value. May be positive, negative or zero.
* @param attributes A set of attributes to associate with the value.
*/

virtual void Record(T value, const common::KeyValueIterable &attributes) noexcept = 0;

/**
* Record a value with a set of attributes.
*
* @param value The measurement value. May be positive, negative or zero.
* @param attributes A set of attributes to associate with the value.
* @param context The explicit context to associate with this measurement.
*/
virtual void Record(T value,
const common::KeyValueIterable &attributes,
const context::Context &context) noexcept = 0;

template <class U,
nostd::enable_if_t<common::detail::is_key_value_iterable<U>::value> * = nullptr>
void Record(T value, const U &attributes) noexcept
{
this->Record(value, common::KeyValueIterableView<U>{attributes});
}

template <class U,
nostd::enable_if_t<common::detail::is_key_value_iterable<U>::value> * = nullptr>
void Record(T value, const U &attributes, const context::Context &context) noexcept
{
this->Record(value, common::KeyValueIterableView<U>{attributes}, context);
}

void Record(T value,
std::initializer_list<std::pair<nostd::string_view, common::AttributeValue>>
attributes) noexcept
{
this->Record(value, nostd::span<const std::pair<nostd::string_view, common::AttributeValue>>{
attributes.begin(), attributes.end()});
}

void Record(T value,
std::initializer_list<std::pair<nostd::string_view, common::AttributeValue>> attributes,
const context::Context &context) noexcept
{
this->Record(value,
nostd::span<const std::pair<nostd::string_view, common::AttributeValue>>{
attributes.begin(), attributes.end()},
context);
}
};


} // namespace metrics
OPENTELEMETRY_END_NAMESPACE
19 changes: 19 additions & 0 deletions examples/common/metrics_foo_library/foo_library.cc
Original file line number Diff line number Diff line change
Expand Up @@ -106,4 +106,23 @@ void foo_library::histogram_example(const std::string &name)
histogram_counter->Record(val, labelkv, context);
std::this_thread::sleep_for(std::chrono::milliseconds(250));
}


}

void foo_library::gauge_example(const std::string &name)
{
std::string gauge_name = name + "_gauge";
auto provider = metrics_api::Provider::GetMeterProvider();
opentelemetry::nostd::shared_ptr<metrics_api::Meter> meter = provider->GetMeter(name, "1.2.0");
auto gauge = meter->CreateInt64Gauge(gauge_name, "des", "unit");
auto context = opentelemetry::context::Context{};
for (uint32_t i = 0; i < 20; ++i)
{
int64_t val = (rand() % 100) + 100;
std::map<std::string, std::string> labels = get_random_attr();
auto labelkv = opentelemetry::common::KeyValueIterableView<decltype(labels)>{labels};
gauge->Record(val, labelkv, context);
std::this_thread::sleep_for(std::chrono::milliseconds(250));
}
}
1 change: 1 addition & 0 deletions examples/common/metrics_foo_library/foo_library.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ class foo_library
static void counter_example(const std::string &name);
static void histogram_example(const std::string &name);
static void observable_counter_example(const std::string &name);
static void gauge_example(const std::string &name);
};
6 changes: 6 additions & 0 deletions examples/metrics_simple/metrics_ostream.cc
Original file line number Diff line number Diff line change
Expand Up @@ -148,15 +148,21 @@ int main(int argc, char **argv)
{
foo_library::histogram_example(name);
}
else if (example_type == "gauge")
{
foo_library::gauge_example(name);
}
else
{
std::thread counter_example{&foo_library::counter_example, name};
std::thread observable_counter_example{&foo_library::observable_counter_example, name};
std::thread histogram_example{&foo_library::histogram_example, name};
std::thread gauge_example{&foo_library::gauge_example, name};

counter_example.join();
observable_counter_example.join();
histogram_example.join();
gauge_example.join();
}

CleanupMetrics();
Expand Down
6 changes: 6 additions & 0 deletions examples/otlp/file_metric_main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -98,15 +98,21 @@ int main(int argc, char *argv[])
{
foo_library::histogram_example(name);
}
else if (example_type == "gauge")
{
foo_library::gauge_example(name);
}
else
{
std::thread counter_example{&foo_library::counter_example, name};
std::thread observable_counter_example{&foo_library::observable_counter_example, name};
std::thread histogram_example{&foo_library::histogram_example, name};
std::thread gauge_example{&foo_library::gauge_example, name};

counter_example.join();
observable_counter_example.join();
histogram_example.join();
gauge_example.join();
}

CleanupMetrics();
Expand Down
6 changes: 6 additions & 0 deletions examples/otlp/grpc_metric_main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -93,15 +93,21 @@ int main(int argc, char *argv[])
{
foo_library::histogram_example(name);
}
else if (example_type == "gauge")
{
foo_library::gauge_example(name);
}
else
{
std::thread counter_example{&foo_library::counter_example, name};
std::thread observable_counter_example{&foo_library::observable_counter_example, name};
std::thread histogram_example{&foo_library::histogram_example, name};
std::thread gauge_example{&foo_library::gauge_example, name};

counter_example.join();
observable_counter_example.join();
histogram_example.join();
gauge_example.join();
}

CleanupMetrics();
Expand Down
6 changes: 6 additions & 0 deletions examples/otlp/http_metric_main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -133,15 +133,21 @@ int main(int argc, char *argv[])
{
foo_library::histogram_example(name);
}
else if (example_type == "gauge")
{
foo_library::gauge_example(name);
}
else
{
std::thread counter_example{&foo_library::counter_example, name};
std::thread observable_counter_example{&foo_library::observable_counter_example, name};
std::thread histogram_example{&foo_library::histogram_example, name};
std::thread gauge_example{&foo_library::gauge_example, name};

counter_example.join();
observable_counter_example.join();
histogram_example.join();
gauge_example.join();
}

CleanupMetrics();
Expand Down
2 changes: 2 additions & 0 deletions exporters/otlp/src/otlp_metric_utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ sdk::metrics::AggregationTemporality OtlpMetricUtils::DeltaTemporalitySelector(
case sdk::metrics::InstrumentType::kObservableCounter:
case sdk::metrics::InstrumentType::kHistogram:
case sdk::metrics::InstrumentType::kObservableGauge:
case sdk::metrics::InstrumentType::kGauge:
return sdk::metrics::AggregationTemporality::kDelta;
case sdk::metrics::InstrumentType::kUpDownCounter:
case sdk::metrics::InstrumentType::kObservableUpDownCounter:
Expand All @@ -320,6 +321,7 @@ sdk::metrics::AggregationTemporality OtlpMetricUtils::LowMemoryTemporalitySelect
case sdk::metrics::InstrumentType::kHistogram:
return sdk::metrics::AggregationTemporality::kDelta;
case sdk::metrics::InstrumentType::kObservableCounter:
case sdk::metrics::InstrumentType::kGauge:
case sdk::metrics::InstrumentType::kObservableGauge:
case sdk::metrics::InstrumentType::kUpDownCounter:
case sdk::metrics::InstrumentType::kObservableUpDownCounter:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ class DefaultAggregation
return AggregationType::kSum;
case InstrumentType::kHistogram:
return AggregationType::kHistogram;
case InstrumentType::kGauge:
case InstrumentType::kObservableGauge:
return AggregationType::kLastValue;
default:
Expand Down
1 change: 1 addition & 0 deletions sdk/include/opentelemetry/sdk/metrics/instruments.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ enum class InstrumentType
kCounter,
kHistogram,
kUpDownCounter,
kGauge,
Copy link
Contributor

Choose a reason for hiding this comment

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

Is inserting a new InstrumentType of kGauge a SDK breaking change and also break the ABI? Should it be included only for OPENTELEMETRY_ABI_VERSION_NO >= 2?

Copy link
Member

@lalitb lalitb Oct 30, 2024

Choose a reason for hiding this comment

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

It won't be ABI breaking for API, as InstrumentType is not part of API surface. And we don't guarantee SDK ABI compatibility. It could be breaking change for custom exporters which use the switch on this enum without handling default case, but this can be added in the changelog.

Copy link
Member

Choose a reason for hiding this comment

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

This has been discussed before:

#3029 (comment)

The code as written is fine:

  • no change in the API, this kGauge is part of the SDK
  • the SDK ABI is changed, and we do not guarantee SDK ABI compatibility

I don't think we should document that in the changelog for the SDK, by definition every SDK change can (and most of the time does) break the SDK ABI.

@ThomsonTan Please remove the change requested then, as this blocks the merge.

marcalff marked this conversation as resolved.
Show resolved Hide resolved
kObservableCounter,
kObservableGauge,
kObservableUpDownCounter
marcalff marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
10 changes: 10 additions & 0 deletions sdk/include/opentelemetry/sdk/metrics/meter.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,16 @@ class Meter final : public opentelemetry::metrics::Meter
nostd::string_view description = "",
nostd::string_view unit = "") noexcept override;

nostd::unique_ptr<opentelemetry::metrics::Gauge<int64_t>> CreateInt64Gauge(
nostd::string_view name,
nostd::string_view description = "",
nostd::string_view unit = "") noexcept override;

nostd::unique_ptr<opentelemetry::metrics::Gauge<double>> CreateDoubleGauge(
nostd::string_view name,
nostd::string_view description = "",
nostd::string_view unit = "") noexcept override;

nostd::shared_ptr<opentelemetry::metrics::ObservableInstrument> CreateInt64ObservableGauge(
nostd::string_view name,
nostd::string_view description = "",
Expand Down
32 changes: 32 additions & 0 deletions sdk/include/opentelemetry/sdk/metrics/sync_instruments.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,38 @@ class DoubleUpDownCounter : public Synchronous, public opentelemetry::metrics::U
void Add(double value, const opentelemetry::context::Context &context) noexcept override;
};

class LongGauge : public Synchronous, public opentelemetry::metrics::Gauge<int64_t>
{
public:
LongGauge(const InstrumentDescriptor &instrument_descriptor,
std::unique_ptr<SyncWritableMetricStorage> storage);

void Record(int64_t value,
const opentelemetry::common::KeyValueIterable &attributes) noexcept override;
void Record(int64_t value,
const opentelemetry::common::KeyValueIterable &attributes,
const opentelemetry::context::Context &context) noexcept override;

void Record(int64_t value) noexcept override;
void Record(int64_t value, const opentelemetry::context::Context &context) noexcept override;
};

class DoubleGauge : public Synchronous, public opentelemetry::metrics::Gauge<double>
{
public:
DoubleGauge(const InstrumentDescriptor &instrument_descriptor,
std::unique_ptr<SyncWritableMetricStorage> storage);

void Record(double value,
const opentelemetry::common::KeyValueIterable &attributes) noexcept override;
void Record(double value,
const opentelemetry::common::KeyValueIterable &attributes,
const opentelemetry::context::Context &context) noexcept override;

void Record(double value) noexcept override;
void Record(double value, const opentelemetry::context::Context &context) noexcept override;
};

class LongHistogram : public Synchronous, public opentelemetry::metrics::Histogram<uint64_t>
{
public:
Expand Down
Loading
Loading