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

Metrics API : Provider , MeterProvider, Meter, SynchronousInstrument #1033

Merged
merged 20 commits into from
Nov 11, 2021
Merged
Show file tree
Hide file tree
Changes from 4 commits
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
21 changes: 21 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ option(WITH_NO_GETENV "Whether the platform supports environment variables" OFF)

option(BUILD_TESTING "Whether to enable tests" ON)

option(BUILD_PACKAGE "Whether to build rpm/deb package" OFF)

if(WITH_NO_GENENV)
add_definitions(-DNO_GETENV)
endif()
Expand Down Expand Up @@ -412,3 +414,22 @@ install(
EXPORT "${PROJECT_NAME}-target"
NAMESPACE "${PROJECT_NAME}::"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")

if(BUILD_PACKAGE AND UNIX)
execute_process(
COMMAND lsb_release -si
OUTPUT_VARIABLE distribution
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(distribution STREQUAL "Debian" OR distribution STREQUAL "Ubuntu")
set(INSTALL_LIB_DIR
${CMAKE_INSTALL_PREFIX}/lib/${CPACK_DEBIAN_ARCHITECTURE}-linux-gnu)
include(cmake/MakeDeb.cmake)
elseif(
distribution MATCHES "RedHat.*"
OR distribution MATCHES "openSUSE.*"
OR distribution STREQUAL "Fedora")
set(INSTALL_LIB_DIR
${CMAKE_INSTALL_PREFIX}/lib/${CMAKE_SYSTEM_PROCESSOR}-linux-gnu)
include(cmake/MakeRpm.cmake)
endif()
endif()
30 changes: 30 additions & 0 deletions api/include/opentelemetry/metrics_new/async_instruments.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

#pragma once
#ifdef ENABLE_METRICS_PREVIEW

# include "instrument.h"
# include "observer_result.h"

OPENTELEMETRY_BEGIN_NAMESPACE
namespace metrics_new
{
class AsynchronousInstrument
{};

template <class T>
class ObservableCounter : public AsynchronousInstrument
{};

template <class T>
class ObservableGauge : public AsynchronousInstrument
{};

template <class T>
class ObservableUpDownCounter : public AsynchronousInstrument
{};

} // namespace metrics_new
OPENTELEMETRY_END_NAMESPACE
#endif
252 changes: 252 additions & 0 deletions api/include/opentelemetry/metrics_new/meter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

#pragma once
#ifdef ENABLE_METRICS_PREVIEW

# include "opentelemetry/metrics_new/async_instruments.h"
# include "opentelemetry/metrics_new/instrument.h"
# include "opentelemetry/metrics_new/sync_instruments.h"
# include "opentelemetry/nostd/shared_ptr.h"
# include "opentelemetry/nostd/span.h"
# include "opentelemetry/nostd/string_view.h"
# include "opentelemetry/version.h"

OPENTELEMETRY_BEGIN_NAMESPACE
namespace metrics_new
{
/**
* Handles instrument creation and provides a facility for batch recording.
*
* This class provides methods to create new metric instruments, record a
* batch of values to a specified set of instruments, and collect
* measurements from all instruments.
*
*/
class Meter
{
public:
virtual ~Meter() = default;

/**
* Creates a Counter with the passed characteristics and returns a shared_ptr to that Counter.
*
* @param name the name of the new Counter.
* @param description a brief description of what the Counter is used for.
* @param unit the unit of metric values following https://unitsofmeasure.org/ucum.html.
* @param enabled a boolean value that turns on or off the metric instrument.
jsuereth marked this conversation as resolved.
Show resolved Hide resolved
* @return a shared pointer to the created Counter.
* @throws NullPointerException if {@code name} is null
* @throws IllegalArgumentException if a different metric by the same name exists in this meter.
* @throws IllegalArgumentException if the {@code name} does not match spec requirements.
*/
virtual nostd::shared_ptr<Counter<short>> CreateShortCounter(
lalitb marked this conversation as resolved.
Show resolved Hide resolved
jsuereth marked this conversation as resolved.
Show resolved Hide resolved
nostd::string_view name,
nostd::string_view description = "",
nostd::string_view unit = "",
const bool enabled = true) noexcept = 0;

virtual nostd::shared_ptr<Counter<int>> CreateIntCounter(nostd::string_view name,
nostd::string_view description = "",
nostd::string_view unit = "",
const bool enabled = true) noexcept = 0;

virtual nostd::shared_ptr<Counter<float>> CreateFloatCounter(
nostd::string_view name,
nostd::string_view description = "",
nostd::string_view unit = "",
const bool enabled = true) noexcept = 0;

virtual nostd::shared_ptr<Counter<double>> CreateDoubleCounter(
nostd::string_view name,
nostd::string_view description = "",
nostd::string_view unit = "",
const bool enabled = true) noexcept = 0;

/**
* Creates a Asynchronouse (Observable) counter with the passed characteristics and returns a
* shared_ptr to that Observable Counter
*
* @param name the name of the new Observable Counter.
* @param description a brief description of what the Observable Counter is used for.
* @param unit the unit of metric values following https://unitsofmeasure.org/ucum.html.
* @param enabled a boolean value that turns on or off the metric instrument.
* @param callback the function to be observed by the instrument.
* @return a shared pointer to the created Observable Counter.
*/
virtual nostd::shared_ptr<ObservableCounter<short>> CreateShortObservableCounter(
nostd::string_view name,
void (*callback)(ObserverResult<short>),
nostd::string_view description = "",
nostd::string_view unit = "",
const bool enabled = true) noexcept = 0;

virtual nostd::shared_ptr<ObservableCounter<int>> CreateIntObservableCounter(
nostd::string_view name,
void (*callback)(ObserverResult<int>),
nostd::string_view description = "",
nostd::string_view unit = "",
const bool enabled = true, ) noexcept = 0;

virtual nostd::shared_ptr<ObservableCounter<float>> CreateFloatObservableCounter(
nostd::string_view name,
nostd::string_view description = "",
nostd::string_view unit = "",
const bool enabled = true,
void (*callback)(ObserverResult<float>)) noexcept = 0;
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: You may want to have a variant of this that takes a void* state parameter and passes that to the callback (or hide that with templates).

I understand you need this API to be bin-compat so likely std::function is out. However, it's entirely likely these observables need to track their own internal state.

Copy link
Member Author

Choose a reason for hiding this comment

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

Does it mean having these two variants:
CreateFloatObservableCounter( .., .., .., callback ) // existing
and
CreateFloatObservableCounter(.., .., .., callback, void *)

Passing state through lambda/std::function would be the best way, but you are correct on issues with ABI-compat. I initially thought this was in the scope of SDK implementation ( as ObserverResult implementation is provided by SDK , and state can be passed through its constructor) but let me give it a thought. Probably we can add it separately from this PR if needed?

Copy link
Member Author

@lalitb lalitb Oct 28, 2021

Choose a reason for hiding this comment

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

Have modified the callback to contain the state. Passing void * or va_args has potential danger of run-time crash, so used KeyValueIterable for it as below:
void (*callback)(ObserverResult<double> &result, const common::KeyValueIterable &state)

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure this is what I meant.

Specifically, what you really want is to pass an instance of a class and its state, vs. a key-value iterable (which is immutable and you cannot change its state).

Maybe try an implementation of one of these methods against some kind of stateful backend where you pull values and see what works best.

I agree void* is unsafe, I'm not sure of a bin-compat alternative....

Copy link
Contributor

Choose a reason for hiding this comment

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

I did some of my own research and likely my understanding of best-practices around callbacks is off in C++. Stateful callbacks apparently commonly use a lambda to capture a local variable that contains state, and likely works here.

Specifically, just want to make sure you can do something like the following:

const MyCustomMetrics& LatestMetrics() {
   static std::unique_ptr<Storage> lastMetricPull;
   static long lastMetricPullTime = 0;
   if (lastMetricPullTime < someThreasholdAgainstCurrentTime) {
      delete lastMetricPull;
      lastMetricPull = expensiveCallForMetrics();
   }
}


void someNormalMethod() {
   meterProivder->CreateFloatObservable(..., ..., ..., [&](ObservableMeasuremnet m) {
      m.observe( LatestMetrics().someValue);
  });
}

I.e. as long as we have a mechanism to store long-running state in "raw" form, we're fine. I forgot lambdas do all sorts of things for you know, so I think your original signature was fine, sorry for the noise!


virtual nostd::shared_ptr<ObservableCounter<double>> CreateDoubleObservableCounter(
nostd::string_view name,
nostd::string_view description = "",
nostd::string_view unit = "",
const bool enabled = true,
void (*callback)(ObserverResult<double>)) noexcept = 0;

/**
* Creates a Histogram with the passed characteristics and returns a shared_ptr to that Histogram.
*
* @param name the name of the new Histogram.
* @param description a brief description of what the Histogram is used for.
* @param unit the unit of metric values following https://unitsofmeasure.org/ucum.html.
* @param enabled a boolean value that turns on or off the metric instrument.
* @return a shared pointer to the created Histogram.
*/
virtual nostd::shared_ptr<Histogram<short>> CreateShortHistogram(
nostd::string_view name,
nostd::string_view description = "",
nostd::string_view unit = "",
const bool enabled = true) noexcept = 0;

virtual nostd::shared_ptr<Histogram<int>> CreateIntHistogram(
nostd::string_view name,
nostd::string_view description = "",
nostd::string_view unit = "",
const bool enabled = true) noexcept = 0;

virtual nostd::shared_ptr<Histogram<float>> CreateFloatHistogram(
nostd::string_view name,
nostd::string_view description = "",
nostd::string_view unit = "",
const bool enabled = true) noexcept = 0;

virtual nostd::shared_ptr<Histogram<double>> CreateDoubleHistogram(
nostd::string_view name,
nostd::string_view description = "",
nostd::string_view unit = "",
const bool enabled = true) noexcept = 0;

/**
* Creates a Asynchronouse (Observable) Gauge with the passed characteristics and returns a
* shared_ptr to that Observable Counter
*
* @param name the name of the new Observable Gauge.
* @param description a brief description of what the Observable Gauge is used for.
* @param unit the unit of metric values following https://unitsofmeasure.org/ucum.html.
* @param enabled a boolean value that turns on or off the metric instrument.
* @param callback the function to be observed by the instrument.
* @return a shared pointer to the created Observable Gauge.
*/
virtual nostd::shared_ptr<ObservableGauge<short>> CreateShortObservableGauge(
nostd::string_view name,
void (*callback)(ObserverResult<short>),
nostd::string_view description = "",
nostd::string_view unit = "",
const bool enabled = true) noexcept = 0;

virtual nostd::shared_ptr<ObservableGauge<int>> CreateIntObservableGauge(
nostd::string_view name,
void (*callback)(ObserverResult<int>),
nostd::string_view description = "",
nostd::string_view unit = "",
const bool enabled = true, ) noexcept = 0;

virtual nostd::shared_ptr<ObservableGauge<float>> CreateFloatObservableGauge(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(ObserverResult<float>)) noexcept = 0;

virtual nostd::shared_ptr<ObservableGauge<double>> CreateDoubleObservableGauge(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(ObserverResult<double>)) noexcept = 0;

/**
* Creates an UpDownCounter with the passed characteristics and returns a shared_ptr to that
* UpDownCounter.
*
* @param name the name of the new UpDownCounter.
* @param description a brief description of what the UpDownCounter is used for.
* @param unit the unit of metric values following https://unitsofmeasure.org/ucum.html.
* @param enabled a boolean value that turns on or off the metric instrument.
* @return a shared pointer to the created UpDownCounter.
*/
virtual nostd::shared_ptr<UpDownCounter<short>> CreateShortUpDownCounter(
nostd::string_view name,
nostd::string_view description = "",
nostd::string_view unit = "",
const bool enabled = true) noexcept = 0;

virtual nostd::shared_ptr<UpDownCounter<int>> CreateIntUpDownCounter(
nostd::string_view name,
nostd::string_view description = "",
nostd::string_view unit = "",
const bool enabled = true) = 0;

virtual nostd::shared_ptr<UpDownCounter<float>> CreateFloatUpDownCounter(
nostd::string_view name,
nostd::string_view description = "",
nostd::string_view unit = "",
const bool enabled = true) noexcept = 0;

virtual nostd::shared_ptr<UpDownCounter<double>> CreateDoubleUpDownCounter(
nostd::string_view name,
nostd::string_view description = "",
nostd::string_view unit = "",
const bool enabled = true) noexcept = 0;

/**
* Creates a Asynchronouse (Observable) UpDownCounter with the passed characteristics and returns
* a shared_ptr to that Observable UpDownCounter
*
* @param name the name of the new Observable UpDownCounter.
* @param description a brief description of what the Observable UpDownCounter is used for.
* @param unit the unit of metric values following https://unitsofmeasure.org/ucum.html.
* @param enabled a boolean value that turns on or off the metric instrument.
* @param callback the function to be observed by the instrument.
* @return a shared pointer to the created Observable UpDownCounter.
*/
virtual nostd::shared_ptr<ObservableUpDownCounter<short>> CreateShortObservableUpDownCounter(
nostd::string_view name,
void (*callback)(ObserverResult<short>),
nostd::string_view description = "",
nostd::string_view unit = "",
const bool enabled = true) noexcept = 0;

virtual nostd::shared_ptr<ObservableUpDownCounter<int>> CreateIntObservableUpDownCounter(
nostd::string_view name,
void (*callback)(ObserverResult<int>),
nostd::string_view description = "",
nostd::string_view unit = "",
const bool enabled = true, ) noexcept = 0;

virtual nostd::shared_ptr<ObservableUpDownCounter<float>> CreateFloatObservableUpDownCounter(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(ObserverResult<float>)) noexcept = 0;

virtual nostd::shared_ptr<ObservableUpDownCounter<double>> CreateDoubleObservableUpDownCounter(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(ObserverResult<double>)) noexcept = 0;
};
} // namespace metrics_new
OPENTELEMETRY_END_NAMESPACE
#endif
32 changes: 32 additions & 0 deletions api/include/opentelemetry/metrics_new/meter_provider.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

#pragma once
#ifdef ENABLE_METRICS_PREVIEW

# include "opentelemetry/metrics/meter.h"
# include "opentelemetry/nostd/shared_ptr.h"
# include "opentelemetry/nostd/string_view.h"

OPENTELEMETRY_BEGIN_NAMESPACE
namespace metrics_new
{
/**
* Creates new Meter instances.
*/
class MeterProvider
{
public:
virtual ~MeterProvider() = default;
/**
* Gets or creates a named Meter instance.
*
* Optionally a version can be passed to create a named and versioned Meter
* instance.
*/
virtual nostd::shared_ptr<Meter> GetMeter(nostd::string_view library_name,
nostd::string_view library_version = "",
nostd::string_view schema_url = "") noexcept = 0;
} // namespace metrics
OPENTELEMETRY_END_NAMESPACE
#endif
29 changes: 29 additions & 0 deletions api/include/opentelemetry/metrics_new/observer_result.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

#pragma once
#ifdef ENABLE_METRICS_PREVIEW
# include "c

OPENTELEMETRY_BEGIN_NAMESPACE
namespace metrics_new
{

/**
* ObserverResult class is necessary for the callback recording asynchronous
* instrument use.
*/

template <class T>
class ObserverResult
{

public:
virtual void observe(T value) noexcept = 0;

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

} // namespace metrics_new
OPENTELEMETRY_END_NAMESPACE
#endif
Loading