Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
16 changes: 16 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ endif()
option(WITH_ABI_VERSION_1 "ABI version 1" ON)
option(WITH_ABI_VERSION_2 "EXPERIMENTAL: ABI version 2 preview" OFF)

# Experimental: bound synchronous metric instruments (Counter, Histogram).
# Requires WITH_ABI_VERSION_2. Context-bearing bound operations, exemplar
# parity, Gauge, and UpDownCounter bound support are follow-ups.
option(WITH_METRICS_BOUND_INSTRUMENTS_PREVIEW
"EXPERIMENTAL: bound synchronous metric instruments preview" OFF)

option(WITH_CONFIGURATION "EXPERIMENTAL: YAML configuration file" OFF)

#
Expand Down Expand Up @@ -94,6 +100,12 @@ else()
set(OPENTELEMETRY_ABI_VERSION_NO "${OPENTELEMETRY_ABI_VERSION_DEFAULT}")
endif()

if(WITH_METRICS_BOUND_INSTRUMENTS_PREVIEW AND NOT WITH_ABI_VERSION_2)
message(
FATAL_ERROR
"WITH_METRICS_BOUND_INSTRUMENTS_PREVIEW requires WITH_ABI_VERSION_2")
endif()

option(WITH_NO_DEPRECATED_CODE "Do not include deprecated code" OFF)

set(WITH_STL
Expand Down Expand Up @@ -487,6 +499,10 @@ message(STATUS "WITH_API_ONLY: ${WITH_API_ONLY}")
message(STATUS "WITH_NO_DEPRECATED_CODE: ${WITH_NO_DEPRECATED_CODE}")
message(STATUS "WITH_ABI_VERSION_1: ${WITH_ABI_VERSION_1}")
message(STATUS "WITH_ABI_VERSION_2: ${WITH_ABI_VERSION_2}")
message(
STATUS
"WITH_METRICS_BOUND_INSTRUMENTS_PREVIEW: ${WITH_METRICS_BOUND_INSTRUMENTS_PREVIEW}"
)
message(STATUS "OTELCPP_VERSIONED_LIBS: ${OTELCPP_VERSIONED_LIBS}")
message(STATUS "OTELCPP_MAINTAINER_MODE: ${OTELCPP_MAINTAINER_MODE}")
message(STATUS "WITH_STL: ${WITH_STL}")
Expand Down
20 changes: 20 additions & 0 deletions api/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ cc_library(
}) + select({
":abi_version_no_1": ["OPENTELEMETRY_ABI_VERSION_NO=1"],
":abi_version_no_2": ["OPENTELEMETRY_ABI_VERSION_NO=2"],
}) + select({
# Experimental: bound synchronous metric instruments preview.
# NOTE: this define only takes effect when ABI v2 is also enabled
# (`--//api:abi_version_no=2`); see api/include/opentelemetry/version.h
# which gates OPENTELEMETRY_HAVE_METRICS_BOUND_INSTRUMENTS_PREVIEW on
# both ABI v2 and ENABLE_METRICS_BOUND_INSTRUMENTS_PREVIEW.
":metrics_bound_instruments_preview_enabled": ["ENABLE_METRICS_BOUND_INSTRUMENTS_PREVIEW"],
"//conditions:default": [],
}),
strip_include_prefix = "include",
tags = ["api"],
Expand Down Expand Up @@ -80,3 +88,15 @@ config_setting(
name = "abi_version_no_2",
flag_values = {":abi_version_no": "2"},
)

# Experimental: bound synchronous metric instruments preview.
# Only effective with `--//api:abi_version_no=2`.
bool_flag(
name = "with_metrics_bound_instruments_preview",
build_setting_default = False,
)

config_setting(
name = "metrics_bound_instruments_preview_enabled",
flag_values = {":with_metrics_bound_instruments_preview": "true"},
)
5 changes: 5 additions & 0 deletions api/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ target_compile_definitions(
opentelemetry_api
INTERFACE OPENTELEMETRY_ABI_VERSION_NO=${OPENTELEMETRY_ABI_VERSION_NO})

if(WITH_METRICS_BOUND_INSTRUMENTS_PREVIEW)
target_compile_definitions(opentelemetry_api
INTERFACE ENABLE_METRICS_BOUND_INSTRUMENTS_PREVIEW)
endif()

if(WITH_OTLP_RETRY_PREVIEW)
target_compile_definitions(opentelemetry_api
INTERFACE ENABLE_OTLP_RETRY_PREVIEW)
Expand Down
33 changes: 33 additions & 0 deletions api/include/opentelemetry/metrics/noop.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,24 @@ OPENTELEMETRY_BEGIN_NAMESPACE
namespace metrics
{

#ifdef OPENTELEMETRY_HAVE_METRICS_BOUND_INSTRUMENTS_PREVIEW
template <class T>
class NoopBoundCounter : public BoundCounter<T>
{
public:
NoopBoundCounter() noexcept = default;
void Add(T /* value */) noexcept override {}
};

template <class T>
class NoopBoundHistogram : public BoundHistogram<T>
{
public:
NoopBoundHistogram() noexcept = default;
void Record(T /* value */) noexcept override {}
};
#endif

template <class T>
class NoopCounter : public Counter<T>
{
Expand All @@ -29,6 +47,13 @@ class NoopCounter : public Counter<T>
const common::KeyValueIterable & /* attributes */,
const context::Context & /* context */) noexcept override
{}
#ifdef OPENTELEMETRY_HAVE_METRICS_BOUND_INSTRUMENTS_PREVIEW
nostd::unique_ptr<BoundCounter<T>> Bind(
const common::KeyValueIterable & /* attributes */) noexcept override
{
return nostd::unique_ptr<BoundCounter<T>>{new NoopBoundCounter<T>()};
}
#endif
};

template <class T>
Expand All @@ -51,6 +76,14 @@ class NoopHistogram : public Histogram<T>

void Record(T /*value*/) noexcept override {}
#endif

#ifdef OPENTELEMETRY_HAVE_METRICS_BOUND_INSTRUMENTS_PREVIEW
nostd::unique_ptr<BoundHistogram<T>> Bind(
const common::KeyValueIterable & /* attributes */) noexcept override
{
return nostd::unique_ptr<BoundHistogram<T>>{new NoopBoundHistogram<T>()};
}
#endif
};

template <class T>
Expand Down
113 changes: 113 additions & 0 deletions api/include/opentelemetry/metrics/sync_instruments.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
#include "opentelemetry/nostd/type_traits.h"
#include "opentelemetry/version.h"

#ifdef OPENTELEMETRY_HAVE_METRICS_BOUND_INSTRUMENTS_PREVIEW
# include "opentelemetry/nostd/unique_ptr.h"
#endif

OPENTELEMETRY_BEGIN_NAMESPACE
namespace metrics
{
Expand All @@ -26,6 +30,62 @@ class SynchronousInstrument
virtual ~SynchronousInstrument() = default;
};

#ifdef OPENTELEMETRY_HAVE_METRICS_BOUND_INSTRUMENTS_PREVIEW
// Bound synchronous instrument support intentionally covers Counter and
// Histogram only. UpDownCounter, Gauge, exemplar parity, and context-bearing
// bound operations are follow-ups. This API is experimental and is gated
// behind both ABI v2 and ENABLE_METRICS_BOUND_INSTRUMENTS_PREVIEW
// (see OPENTELEMETRY_HAVE_METRICS_BOUND_INSTRUMENTS_PREVIEW in version.h).
/**
* @since ABI_VERSION 2
* A bound counter handle obtained via Counter<T>::Bind(...). The associated
* attribute set is captured at Bind time so the hot path avoids per-call
* attribute processing and hashmap lookup. The handle must not outlive the
* Counter instrument from which it was obtained.
*/
template <class T>
class BoundCounter
{
public:
BoundCounter() = default;
BoundCounter(const BoundCounter &) = delete;
BoundCounter(BoundCounter &&) noexcept = delete;
BoundCounter &operator=(const BoundCounter &) = delete;
BoundCounter &operator=(BoundCounter &&) noexcept = delete;
virtual ~BoundCounter() = default;

/**
* Record a value against the bound attribute set.
*
* @param value The increment amount. MUST be non-negative.
*/
virtual void Add(T value) noexcept = 0;
};

/**
* @since ABI_VERSION 2
* A bound histogram handle obtained via Histogram<T>::Bind(...).
*/
template <class T>
class BoundHistogram
{
public:
BoundHistogram() = default;
BoundHistogram(const BoundHistogram &) = delete;
BoundHistogram(BoundHistogram &&) noexcept = delete;
BoundHistogram &operator=(const BoundHistogram &) = delete;
BoundHistogram &operator=(BoundHistogram &&) noexcept = delete;
virtual ~BoundHistogram() = default;

/**
* Record a value against the bound attribute set.
*
* @param value The measurement value. MUST be non-negative.
*/
virtual void Record(T value) noexcept = 0;
};
#endif

/* A Counter instrument that adds values. */
template <class T>
class Counter : public SynchronousInstrument
Expand Down Expand Up @@ -98,6 +158,32 @@ class Counter : public SynchronousInstrument
attributes.begin(), attributes.end()},
context);
}

#ifdef OPENTELEMETRY_HAVE_METRICS_BOUND_INSTRUMENTS_PREVIEW
/**
* @since ABI_VERSION 2
* Returns a bound counter handle for the given attribute set. Repeated calls
* to BoundCounter<T>::Add(value) avoid per-call attribute processing and
* hashmap lookup. The bound handle MUST NOT outlive this Counter instrument.
*/
virtual nostd::unique_ptr<BoundCounter<T>> Bind(
const common::KeyValueIterable &attributes) noexcept = 0;

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

nostd::unique_ptr<BoundCounter<T>> Bind(
std::initializer_list<std::pair<nostd::string_view, common::AttributeValue>>
attributes) noexcept
{
return this->Bind(nostd::span<const std::pair<nostd::string_view, common::AttributeValue>>{
attributes.begin(), attributes.end()});
}
#endif
};

/** A histogram instrument that records values. */
Expand Down Expand Up @@ -140,6 +226,33 @@ class Histogram : public SynchronousInstrument
}
#endif

#ifdef OPENTELEMETRY_HAVE_METRICS_BOUND_INSTRUMENTS_PREVIEW
/**
* @since ABI_VERSION 2
* Returns a bound histogram handle for the given attribute set. Repeated
* calls to BoundHistogram<T>::Record(value) avoid per-call attribute
* processing and hashmap lookup. The bound handle MUST NOT outlive this
* Histogram instrument.
*/
virtual nostd::unique_ptr<BoundHistogram<T>> Bind(
const common::KeyValueIterable &attributes) noexcept = 0;

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

nostd::unique_ptr<BoundHistogram<T>> Bind(
std::initializer_list<std::pair<nostd::string_view, common::AttributeValue>>
attributes) noexcept
{
return this->Bind(nostd::span<const std::pair<nostd::string_view, common::AttributeValue>>{
attributes.begin(), attributes.end()});
}
#endif

/**
* Records a value.
*
Expand Down
7 changes: 7 additions & 0 deletions api/include/opentelemetry/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,10 @@
#define OPENTELEMETRY_NAMESPACE opentelemetry :: OPENTELEMETRY_CONCAT(v, OPENTELEMETRY_ABI_VERSION_NO)

// clang-format on

// Experimental: bound synchronous metric instruments (Counter, Histogram).
// This public API is available only in ABI v2 preview builds. Guard bound
// instrument code with OPENTELEMETRY_HAVE_METRICS_BOUND_INSTRUMENTS_PREVIEW.
#if OPENTELEMETRY_ABI_VERSION_NO >= 2 && defined(ENABLE_METRICS_BOUND_INSTRUMENTS_PREVIEW)
# define OPENTELEMETRY_HAVE_METRICS_BOUND_INSTRUMENTS_PREVIEW 1
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I kept this derived preview macro in version.h so API and SDK headers use one consistent guard for the ABI-v2 + preview-flag combination. This is temporary while bound instruments are experimental; once the API is stabilized, we can remove the preview flag and keep the surface under the normal ABI rules.

#endif
35 changes: 35 additions & 0 deletions sdk/include/opentelemetry/sdk/metrics/state/metric_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,28 @@ namespace metrics
/* Represent the storage from which to collect the metrics */
class CollectorHandle;

#ifdef OPENTELEMETRY_HAVE_METRICS_BOUND_INSTRUMENTS_PREVIEW
/**
* @since ABI_VERSION 2
* Storage-side interface for a bound sync metric handle. Created by
* SyncWritableMetricStorage::Bind(...). The hot path RecordLong/RecordDouble
* skips per-call attribute filtering and hashmap lookup.
*/
class BoundSyncWritableMetricStorage
{
public:
BoundSyncWritableMetricStorage() = default;
BoundSyncWritableMetricStorage(const BoundSyncWritableMetricStorage &) = delete;
BoundSyncWritableMetricStorage(BoundSyncWritableMetricStorage &&) = delete;
BoundSyncWritableMetricStorage &operator=(const BoundSyncWritableMetricStorage &) = delete;
BoundSyncWritableMetricStorage &operator=(BoundSyncWritableMetricStorage &&) = delete;
virtual ~BoundSyncWritableMetricStorage() = default;

virtual void RecordLong(int64_t value) noexcept = 0;
virtual void RecordDouble(double value) noexcept = 0;
};
#endif

class MetricStorage
{
public:
Expand Down Expand Up @@ -75,6 +97,19 @@ class SyncWritableMetricStorage
virtual void RecordDouble(double value,
const opentelemetry::common::KeyValueIterable &attributes,
const opentelemetry::context::Context &context) noexcept = 0;

#ifdef OPENTELEMETRY_HAVE_METRICS_BOUND_INSTRUMENTS_PREVIEW
/**
* @since ABI_VERSION 2
* Returns a bound storage handle for the given attribute set, or nullptr if
* the storage does not support binding. Default returns nullptr.
*/
virtual std::shared_ptr<BoundSyncWritableMetricStorage> Bind(
const opentelemetry::common::KeyValueIterable & /* attributes */) noexcept
{
return nullptr;
}
#endif
};

/* Represents the async metric stroage */
Expand Down
Loading
Loading