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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ Increment the:

## [Unreleased]

* [METRICS SDK] Implement configurable cardinality limit at three priority levels
[#3292](https://github.com/open-telemetry/opentelemetry-cpp/issues/3292)

* [SDK] Add `TracerProvider::UpdateTracerConfigurator()` and example
[#4065](https://github.com/open-telemetry/opentelemetry-cpp/issues/4065)

Expand Down
10 changes: 10 additions & 0 deletions sdk/include/opentelemetry/sdk/metrics/meter_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include <atomic>
#include <chrono>
#include <cstddef>
#include <memory>
#include <vector>

Expand Down Expand Up @@ -108,6 +109,15 @@ class MeterContext : public std::enable_shared_from_this<MeterContext>
*/
nostd::span<std::shared_ptr<CollectorHandle>> GetCollectors() noexcept;

/**
* Get the cardinality limit for a given instrument type from configured readers.
* Returns the maximum limit across all readers, or 0 if no reader specifies a limit.
*
* @param instrument_type The instrument type to get the limit for
* @return The maximum cardinality limit, or 0 if not configured
*/
size_t GetReaderCardinalityLimit(InstrumentType instrument_type) noexcept;

/**
* GET SDK Start time
*
Expand Down
34 changes: 34 additions & 0 deletions sdk/include/opentelemetry/sdk/metrics/metric_reader.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include <atomic>
#include <chrono>
#include <cstddef>

#include "opentelemetry/nostd/function_ref.h"
#include "opentelemetry/sdk/metrics/export/metric_producer.h"
Expand All @@ -16,6 +17,22 @@ namespace sdk
{
namespace metrics
{
/**
* Configuration options for cardinality limits per instrument type.
* A value of 0 means use the SDK default (2000).
*/
struct CardinalityLimitOptions
{
size_t default_limit = 0; // 0 means use SDK default (2000)
size_t counter = 0;
size_t gauge = 0;
size_t histogram = 0;
size_t observable_counter = 0;
size_t observable_gauge = 0;
size_t observable_up_down_counter = 0;
size_t up_down_counter = 0;
};

/**
* MetricReader defines the interface to collect metrics from SDK
*/
Expand Down Expand Up @@ -45,6 +62,22 @@ class MetricReader
virtual AggregationTemporality GetAggregationTemporality(
InstrumentType instrument_type) const noexcept = 0;

/**
* Get the cardinality limit for a given instrument type.
* Returns 0 if no limit is configured for this instrument type.
*
* @param instrument_type The instrument type to get the limit for
* @return The cardinality limit, or 0 if not configured
*/
size_t GetCardinalityLimit(InstrumentType instrument_type) const noexcept;

/**
* Set cardinality limit options for this reader.
*
* @param options The cardinality limit options
*/
void SetCardinalityLimitOptions(const CardinalityLimitOptions &options) noexcept;

/**
* Shutdown the metric reader.
*/
Expand Down Expand Up @@ -73,6 +106,7 @@ class MetricReader
private:
MetricProducer *metric_producer_{nullptr};
std::atomic<bool> shutdown_{false};
CardinalityLimitOptions cardinality_limit_options_;
};
} // namespace metrics
} // namespace sdk
Expand Down
16 changes: 16 additions & 0 deletions sdk/include/opentelemetry/sdk/metrics/state/metric_collector.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#pragma once

#include <chrono>
#include <cstddef>
#include <memory>

#include "opentelemetry/nostd/function_ref.h"
Expand Down Expand Up @@ -36,6 +37,19 @@ class CollectorHandle

virtual AggregationTemporality GetAggregationTemporality(
InstrumentType instrument_type) noexcept = 0;

/**
* Get the cardinality limit for a given instrument type.
* Returns 0 if no limit is configured.
*
* @param instrument_type The instrument type to get the limit for
* @return The cardinality limit, or 0 if not configured
*/
virtual size_t GetCardinalityLimit(InstrumentType instrument_type) noexcept
{
(void)instrument_type;
return 0;
}
};

/**
Expand All @@ -61,6 +75,8 @@ class MetricCollector : public MetricProducer, public CollectorHandle
AggregationTemporality GetAggregationTemporality(
InstrumentType instrument_type) noexcept override;

size_t GetCardinalityLimit(InstrumentType instrument_type) noexcept override;

/**
* The callback to be called for each metric exporter. This will only be those
* metrics that have been produced since the last time this method was called.
Expand Down
45 changes: 40 additions & 5 deletions sdk/src/configuration/sdk_builder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "opentelemetry/sdk/configuration/batch_span_processor_configuration.h"
#include "opentelemetry/sdk/configuration/boolean_array_attribute_value_configuration.h"
#include "opentelemetry/sdk/configuration/boolean_attribute_value_configuration.h"
#include "opentelemetry/sdk/configuration/cardinality_limits_configuration.h"
#include "opentelemetry/sdk/configuration/composable_probability_sampler_configuration.h"
#include "opentelemetry/sdk/configuration/configuration.h"
#include "opentelemetry/sdk/configuration/configured_sdk.h"
Expand Down Expand Up @@ -1471,14 +1472,24 @@ std::unique_ptr<opentelemetry::sdk::metrics::MetricReader> SdkBuilder::CreatePer
OTEL_INTERNAL_LOG_WARN("metric producer not supported, ignoring");
}

sdk = opentelemetry::sdk::metrics::PeriodicExportingMetricReaderFactory::Create(
std::move(exporter_sdk), options);

if (model->cardinality_limits != nullptr)
{
OTEL_INTERNAL_LOG_WARN("cardinality limits not supported, ignoring");
opentelemetry::sdk::metrics::CardinalityLimitOptions cardinality_options;
cardinality_options.default_limit = model->cardinality_limits->default_limit;
cardinality_options.counter = model->cardinality_limits->counter;
cardinality_options.gauge = model->cardinality_limits->gauge;
cardinality_options.histogram = model->cardinality_limits->histogram;
cardinality_options.observable_counter = model->cardinality_limits->observable_counter;
cardinality_options.observable_gauge = model->cardinality_limits->observable_gauge;
cardinality_options.observable_up_down_counter =
model->cardinality_limits->observable_up_down_counter;
cardinality_options.up_down_counter = model->cardinality_limits->up_down_counter;
sdk->SetCardinalityLimitOptions(cardinality_options);
}

sdk = opentelemetry::sdk::metrics::PeriodicExportingMetricReaderFactory::Create(
std::move(exporter_sdk), options);

return sdk;
}

Expand All @@ -1496,7 +1507,17 @@ std::unique_ptr<opentelemetry::sdk::metrics::MetricReader> SdkBuilder::CreatePul

if (model->cardinality_limits != nullptr)
{
OTEL_INTERNAL_LOG_WARN("cardinality limits not supported, ignoring");
opentelemetry::sdk::metrics::CardinalityLimitOptions cardinality_options;
cardinality_options.default_limit = model->cardinality_limits->default_limit;
cardinality_options.counter = model->cardinality_limits->counter;
cardinality_options.gauge = model->cardinality_limits->gauge;
cardinality_options.histogram = model->cardinality_limits->histogram;
cardinality_options.observable_counter = model->cardinality_limits->observable_counter;
cardinality_options.observable_gauge = model->cardinality_limits->observable_gauge;
cardinality_options.observable_up_down_counter =
model->cardinality_limits->observable_up_down_counter;
cardinality_options.up_down_counter = model->cardinality_limits->up_down_counter;
sdk->SetCardinalityLimitOptions(cardinality_options);
}

return sdk;
Expand Down Expand Up @@ -1600,6 +1621,20 @@ void SdkBuilder::AddView(

sdk_aggregation_config = CreateAggregationConfig(stream->aggregation, sdk_aggregation_type);

// Apply aggregation_cardinality_limit from the view stream configuration
if (stream->aggregation_cardinality_limit != 0)
{
if (sdk_aggregation_config)
{
sdk_aggregation_config->cardinality_limit_ = stream->aggregation_cardinality_limit;
}
else
{
sdk_aggregation_config = std::make_shared<opentelemetry::sdk::metrics::AggregationConfig>(
stream->aggregation_cardinality_limit);
}
}

std::unique_ptr<opentelemetry::sdk::metrics::AttributesProcessor> sdk_attribute_processor;

if (stream->attribute_keys != nullptr)
Expand Down
2 changes: 2 additions & 0 deletions sdk/src/metrics/meter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,7 @@ std::unique_ptr<SyncWritableMetricStorage> Meter::RegisterSyncMetricStorage(
else
{
WarnOnDuplicateInstrument(GetInstrumentationScope(), storage_registry_, view_instr_desc);

sync_storage = std::shared_ptr<SyncMetricStorage>(new SyncMetricStorage(
view_instr_desc, view.GetAggregationType(), view.GetAttributesProcessor(),
#ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW
Expand Down Expand Up @@ -615,6 +616,7 @@ std::unique_ptr<AsyncWritableMetricStorage> Meter::RegisterAsyncMetricStorage(
else
{
WarnOnDuplicateInstrument(GetInstrumentationScope(), storage_registry_, view_instr_desc);

async_storage = std::shared_ptr<AsyncMetricStorage>(new AsyncMetricStorage(
view_instr_desc, view.GetAggregationType(),
#ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW
Expand Down
16 changes: 16 additions & 0 deletions sdk/src/metrics/meter_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <atomic>
#include <chrono>
#include <cstddef>
#include <memory>
#include <mutex>
#include <ostream>
Expand All @@ -18,6 +19,7 @@
#include "opentelemetry/sdk/instrumentationscope/instrumentation_scope.h"
#include "opentelemetry/sdk/instrumentationscope/scope_configurator.h"
#include "opentelemetry/sdk/metrics/export/metric_filter.h"
#include "opentelemetry/sdk/metrics/instruments.h"
#include "opentelemetry/sdk/metrics/meter.h"
#include "opentelemetry/sdk/metrics/meter_config.h"
#include "opentelemetry/sdk/metrics/meter_context.h"
Expand Down Expand Up @@ -91,6 +93,20 @@ nostd::span<std::shared_ptr<CollectorHandle>> MeterContext::GetCollectors() noex
return nostd::span<std::shared_ptr<CollectorHandle>>(collectors_.data(), collectors_.size());
}

size_t MeterContext::GetReaderCardinalityLimit(InstrumentType instrument_type) noexcept
{
size_t max_limit = 0;
for (const auto &collector : collectors_)
{
size_t limit = collector->GetCardinalityLimit(instrument_type);
if (limit > max_limit)
{
max_limit = limit;
}
}
return max_limit;
}

opentelemetry::common::SystemTimestamp MeterContext::GetSDKStartTime() noexcept
{
return sdk_start_ts_;
Expand Down
47 changes: 46 additions & 1 deletion sdk/src/metrics/metric_reader.cc
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

#include "opentelemetry/sdk/metrics/metric_reader.h"
#include <atomic>
#include <chrono>
#include <cstddef>

#include "opentelemetry/nostd/function_ref.h"
#include "opentelemetry/sdk/common/global_log_handler.h"
#include "opentelemetry/sdk/metrics/export/metric_producer.h"
#include "opentelemetry/sdk/metrics/instruments.h"
#include "opentelemetry/sdk/metrics/metric_reader.h"
#include "opentelemetry/version.h"

OPENTELEMETRY_BEGIN_NAMESPACE
Expand Down Expand Up @@ -84,6 +90,45 @@ bool MetricReader::IsShutdown() const noexcept
return shutdown_.load(std::memory_order_acquire);
}

size_t MetricReader::GetCardinalityLimit(InstrumentType instrument_type) const noexcept
{
switch (instrument_type)
{
case InstrumentType::kCounter:
return cardinality_limit_options_.counter != 0 ? cardinality_limit_options_.counter
: cardinality_limit_options_.default_limit;
case InstrumentType::kHistogram:
return cardinality_limit_options_.histogram != 0 ? cardinality_limit_options_.histogram
: cardinality_limit_options_.default_limit;
case InstrumentType::kUpDownCounter:
return cardinality_limit_options_.up_down_counter != 0
? cardinality_limit_options_.up_down_counter
: cardinality_limit_options_.default_limit;
case InstrumentType::kObservableCounter:
return cardinality_limit_options_.observable_counter != 0
? cardinality_limit_options_.observable_counter
: cardinality_limit_options_.default_limit;
case InstrumentType::kObservableGauge:
return cardinality_limit_options_.observable_gauge != 0
? cardinality_limit_options_.observable_gauge
: cardinality_limit_options_.default_limit;
case InstrumentType::kObservableUpDownCounter:
return cardinality_limit_options_.observable_up_down_counter != 0
? cardinality_limit_options_.observable_up_down_counter
: cardinality_limit_options_.default_limit;
case InstrumentType::kGauge:
return cardinality_limit_options_.gauge != 0 ? cardinality_limit_options_.gauge
: cardinality_limit_options_.default_limit;
default:
return cardinality_limit_options_.default_limit;
}
}

void MetricReader::SetCardinalityLimitOptions(const CardinalityLimitOptions &options) noexcept
{
cardinality_limit_options_ = options;
}

} // namespace metrics
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
6 changes: 6 additions & 0 deletions sdk/src/metrics/state/metric_collector.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0

#include <chrono>
#include <cstddef>
#include <memory>
#include <ostream>
#include <utility>
Expand Down Expand Up @@ -45,6 +46,11 @@ AggregationTemporality MetricCollector::GetAggregationTemporality(
return aggregation_temporality;
}

size_t MetricCollector::GetCardinalityLimit(InstrumentType instrument_type) noexcept
{
return metric_reader_->GetCardinalityLimit(instrument_type);
}

MetricProducer::Result MetricCollector::Produce() noexcept
{
if (!meter_context_)
Expand Down
Loading
Loading