Skip to content

[Metrics SDK] Make cardinality limit configurable through View class #3514

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

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

Copilot
Copy link

@Copilot Copilot AI commented Jul 2, 2025

This PR implements configurable cardinality limits for metrics aggregation according to the OpenTelemetry specification. The cardinality limit controls how many unique attribute combinations are stored before overflow behavior is triggered.

Changes Made

1. View Class Enhancement

  • Added aggregation_cardinality_limit parameter to View constructor
  • Added HasAggregationCardinalityLimit() method to check if custom limit is set
  • Added GetAggregationCardinalityLimit() method to retrieve the limit value
  • Default value of 0 means no limit is set (falls back to default)

2. Meter Integration

  • Updated Meter::RegisterSyncMetricStorage to use View cardinality limits
  • Falls back to kAggregationCardinalityLimit (2000) when View has no limit
  • Cardinality limit is passed to SyncMetricStorage constructor

3. MetricReader Infrastructure

  • Added virtual GetDefaultCardinalityLimit method to MetricReader base class
  • Prepared for future implementation of MetricReader-based limits

Usage Example

// Create a View with cardinality limit of 1000
View view("my_counter", "Counter with limit", "count",
          AggregationType::kSum, nullptr,
          std::make_unique<DefaultAttributesProcessor>(),
          1000);

// Check if view has cardinality limit
if (view.HasAggregationCardinalityLimit()) {
    std::cout << "Limit: " << view.GetAggregationCardinalityLimit() << std::endl;
}

// Create a View without cardinality limit (uses default 2000)
View default_view("my_other_counter");
assert(!default_view.HasAggregationCardinalityLimit());

Specification Compliance

According to the OpenTelemetry specification, cardinality limits should be defined in priority order:

  1. View-specific cardinality limit (highest priority) - IMPLEMENTED
  2. 🔄 MetricReader default cardinality limit (fallback) - Infrastructure added, full implementation requires architectural changes
  3. Default value of 2000 (last resort) - IMPLEMENTED

Cardinality Limit Behavior

When the number of unique attribute combinations exceeds the cardinality limit:

  • The first (limit-1) unique combinations are stored as separate metric points
  • All additional combinations are aggregated into a single overflow metric point
  • The overflow metric point has attribute {"otel.metrics.overflow": true}
  • Total metric points = min(unique_combinations, cardinality_limit)

Example with limit=3:

  • Attribute sets: {service=A}, {service=B}, {service=C}, {service=D}, {service=E}
  • Stored as: {service=A}, {service=B}, {otel.metrics.overflow=true}
  • Overflow point contains aggregated values from {service=C}, {service=D}, {service=E}

Backward Compatibility

This implementation maintains full backward compatibility:

  • Existing View constructors continue to work unchanged
  • Default cardinality limit remains 2000 as before
  • All existing tests pass without modification

Testing

Added comprehensive tests covering:

  • View cardinality limit configuration
  • Integration with SyncMetricStorage
  • Cardinality enforcement during metric collection
  • Overflow behavior validation
  • Backward compatibility verification

Fixes #3292.


💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click here to start the survey.

Copy link

linux-foundation-easycla bot commented Jul 2, 2025

CLA Missing ID CLA Not Signed

Copy link

netlify bot commented Jul 2, 2025

Deploy Preview for opentelemetry-cpp-api-docs canceled.

Name Link
🔨 Latest commit e5393a7
🔍 Latest deploy log https://app.netlify.com/projects/opentelemetry-cpp-api-docs/deploys/6865624458ba6b00086e511e

@Copilot Copilot AI changed the title [WIP] [Metrics SDK] Make cardinality limit configurable [Metrics SDK] Make cardinality limit configurable through View class Jul 2, 2025
@Copilot Copilot AI requested a review from lalitb July 2, 2025 01:33
Copilot finished work on behalf of lalitb July 2, 2025 01:33
@lalitb
Copy link
Member

lalitb commented Jul 2, 2025

Seems the unit test failed in CI:
375/521 Test #375: metrics.CardinalityLimit.SyncMetricStorageWithViewCardinalityLimit ...................................***Failed 0.00 sec
Running main() from /tmp/tmp.wagOU0vcg5/googletest-1.14.0/googletest/src/gtest_main.cc
Note: Google Test filter = CardinalityLimit.SyncMetricStorageWithViewCardinalityLimit
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from CardinalityLimit
[ RUN ] CardinalityLimit.SyncMetricStorageWithViewCardinalityLimit
/home/runner/work/opentelemetry-cpp/opentelemetry-cpp/sdk/test/metrics/cardinality_limit_test.cc:242: Failure
Expected equality of these values:
nostd::get<int64_t>(data.value_)
Which is: 400
record_value * 3
Which is: 300

[ FAILED ] CardinalityLimit.SyncMetricStorageWithViewCardinalityLimit (0 ms)
[----------] 1 test from CardinalityLimit (0 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[ PASSED ] 0 tests.
[ FAILED ] 1 test, listed below:
[ FAILED ] CardinalityLimit.SyncMetricStorageWithViewCardinalityLimit

1 FAILED TEST

    Start 376: metrics.Histogram.Double

376/521 Test #376: metrics.Histogram.Double ............................................................................. Passed 0.00 sec
Start 377: metrics.Histogram.DoubleCustomBuckets
377/521 Test #377: metrics.Histogram.DoubleCustomBuckets ................................................................ Passed 0.00 sec

Copy link
Author

Copilot AI commented Jul 2, 2025

Seems the unit test failed in CI:
375/521 Test #375: metrics.CardinalityLimit.SyncMetricStorageWithViewCardinalityLimit ...................................***Failed 0.00 sec
Running main() from /...

Fixed the test expectation in commit 804fa54. The test was expecting wrong behavior - with cardinality limit 5, the first 4 attribute combinations get individual metric points and the remaining 4 combinations are aggregated into the overflow point (400 = 100 × 4). This matches the OpenTelemetry specification where total points equal the cardinality limit.

Warning

Firewall rules blocked me from connecting to one or more addresses

I tried to connect to the following addresses, but was blocked by firewall rules:

  • esm.ubuntu.com
    • Triggering command: /usr/lib/apt/methods/https (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot finished work on behalf of lalitb July 2, 2025 07:10
Copy link
Member

@marcalff marcalff left a comment

Choose a reason for hiding this comment

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

On one hand, it is technically interesting to see what generative AI can do.

On the other hand, I am extremely concerned about:

  • legal implications here, in particular about the risk to taint intellectual property of the repository
  • compatibility of AI generated code, trained on unknown code with unknown licenses, with the opentelemetry-cpp license

We need to clarify first whether using generative AI in general, or Copilot in particular, can be allowed or not.

In the mean time, blocking this PR, and will block any PR involving generative AI, until this is clarified and resolved.

Copy link

codecov bot commented Jul 2, 2025

Codecov Report

Attention: Patch coverage is 83.33333% with 2 lines in your changes missing coverage. Please review.

Project coverage is 89.94%. Comparing base (f4897b2) to head (e5393a7).

Files with missing lines Patch % Lines
.../include/opentelemetry/sdk/metrics/metric_reader.h 0.00% 2 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #3514      +/-   ##
==========================================
- Coverage   89.95%   89.94%   -0.01%     
==========================================
  Files         219      219              
  Lines        7051     7061      +10     
==========================================
+ Hits         6342     6350       +8     
- Misses        709      711       +2     
Files with missing lines Coverage Δ
sdk/include/opentelemetry/sdk/metrics/view/view.h 100.00% <100.00%> (ø)
sdk/src/metrics/meter.cc 86.06% <100.00%> (+0.17%) ⬆️
.../include/opentelemetry/sdk/metrics/metric_reader.h 25.00% <0.00%> (-25.00%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@lalitb
Copy link
Member

lalitb commented Jul 2, 2025

More CI failures:

[ 36%] Building CXX object sdk/src/metrics/CMakeFiles/opentelemetry_metrics.dir/meter_config.cc.o
[ 36%] Building CXX object sdk/src/metrics/CMakeFiles/opentelemetry_metrics.dir/meter_context.cc.o
[ 36%] Building CXX object sdk/src/trace/CMakeFiles/opentelemetry_trace.dir/exporter.cc.o
Warning: include-what-you-use reported diagnostics:

/home/runner/work/opentelemetry-cpp/opentelemetry-cpp/sdk/src/metrics/meter.cc should add these lines:
#include <stddef.h>
#include "opentelemetry/sdk/metrics/state/attributes_hashmap.h"

/home/runner/work/opentelemetry-cpp/opentelemetry-cpp/sdk/src/metrics/meter.cc should remove these lines:

The full include-list for /home/runner/work/opentelemetry-cpp/opentelemetry-cpp/sdk/src/metrics/meter.cc:
#include <stddef.h>
#include <cstdint>
#include <mutex>
#include <ostream>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include "opentelemetry/common/spin_lock_mutex.h"
#include "opentelemetry/common/timestamp.h"
#include "opentelemetry/metrics/async_instruments.h"
#include "opentelemetry/metrics/noop.h"
#include "opentelemetry/metrics/sync_instruments.h"
#include "opentelemetry/nostd/function_ref.h"
#include "opentelemetry/nostd/shared_ptr.h"
#include "opentelemetry/nostd/span.h"
#include "opentelemetry/nostd/string_view.h"
#include "opentelemetry/nostd/unique_ptr.h"
#include "opentelemetry/sdk/common/global_log_handler.h"
#include "opentelemetry/sdk/instrumentationscope/instrumentation_scope.h"
#include "opentelemetry/sdk/instrumentationscope/scope_configurator.h"
#include "opentelemetry/sdk/metrics/async_instruments.h"
#include "opentelemetry/sdk/metrics/data/metric_data.h"
#include "opentelemetry/sdk/metrics/exemplar/filter_type.h"
#include "opentelemetry/sdk/metrics/exemplar/reservoir_utils.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"
#include "opentelemetry/sdk/metrics/state/async_metric_storage.h"
#include "opentelemetry/sdk/metrics/state/attributes_hashmap.h"
#include "opentelemetry/sdk/metrics/state/metric_collector.h"
#include "opentelemetry/sdk/metrics/state/metric_storage.h"
#include "opentelemetry/sdk/metrics/state/multi_metric_storage.h"
#include "opentelemetry/sdk/metrics/state/observable_registry.h"
#include "opentelemetry/sdk/metrics/state/sync_metric_storage.h"
#include "opentelemetry/sdk/metrics/sync_instruments.h"
#include "opentelemetry/sdk/metrics/view/view.h"
#include "opentelemetry/sdk/metrics/view/view_registry.h"
#include "opentelemetry/version.h"
---

[ 36%] Building CXX object sdk/src/logs/CMakeFiles/opentelemetry_logs.dir/logger.cc.o
[ 36%] Building CXX object sdk/src/logs/CMakeFiles/opentelemetry_logs.dir/exporter.cc.o
[ 36%] Building CXX object sdk/src/trace/CMakeFiles/opentelemetry_trace.dir/provider.cc.o
[ 37%] Building CXX object sdk/src/metrics/CMakeFiles/opentelemetry_metrics.dir/meter_context_factory.cc.o
[ 37%] Building CXX object ext/test/http/CMakeFiles/curl_http_test.dir/curl_http_test.cc.o
[ 37%] Building CXX object sdk/src/logs/CMakeFiles/opentelemetry_logs.dir/event_logger_provider.cc.o
[ 37%] Building CXX object sdk/src/trace/CMakeFiles/opentelemetry_trace.dir/batch_span_processor.cc.o
[ 37%] Building CXX object sdk/src/metrics/CMakeFiles/opentelemetry_metrics.dir/metric_reader.cc.o
[ 38%] Linking CXX executable curl_http_test
[ 38%] Built target curl_http_test
[ 38%] Building CXX object sdk/src/logs/CMakeFiles/opentelemetry_logs.dir/event_logger_provider_factory.cc.o
[ 38%] Building CXX object exporters/otlp/CMakeFiles/opentelemetry_exporter_otlp_http_client.dir/src/otlp_http.cc.o
[ 38%] Building CXX object exporters/otlp/CMakeFiles/opentelemetry_exporter_otlp_http_client.dir/src/otlp_http_client.cc.o
Warning: include-what-you-use reported diagnostics:

/home/runner/work/opentelemetry-cpp/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/metric_reader.h should add these lines:
#include <stddef.h>                                            // for size_t

/home/runner/work/opentelemetry-cpp/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/metric_reader.h should remove these lines:

The full include-list for /home/runner/work/opentelemetry-cpp/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/metric_reader.h:
#include <stddef.h>                                            // for size_t
#include <atomic>                                              // for atomic
#include <chrono>                                              // for micros...
#include "opentelemetry/nostd/function_ref.h"                  // for functi...
#include "opentelemetry/sdk/metrics/export/metric_producer.h"  // for Metric...
#include "opentelemetry/sdk/metrics/instruments.h"             // for Instru...
#include "opentelemetry/version.h"                             // for OPENTE...
---

(/home/runner/work/opentelemetry-cpp/opentelemetry-cpp/sdk/src/metrics/metric_reader.cc has correct #includes/fwd-decls)

[ 38%] Building CXX object sdk/src/trace/CMakeFiles/opentelemetry_trace.dir/batch_span_processor_factory.cc.o
[ 38%] Building CXX object sdk/src/logs/CMakeFiles/opentelemetry_logs.dir/event_logger.cc.o
[ 38%] Building CXX object sdk/src/metrics/CMakeFiles/opentelemetry_metrics.dir/instrument_metadata_validator.cc.o

Copy link
Author

Copilot AI commented Jul 2, 2025

More CI failures:

...

Fixed the IWYU warnings in commit e5393a7 by adding the missing includes:

  • Added #include <stddef.h> to metric_reader.h for size_t type
  • Added #include <stddef.h> to meter.cc for size_t type
  • Added #include "opentelemetry/sdk/metrics/state/attributes_hashmap.h" to meter.cc

The build now completes successfully and all tests pass.

Warning

Firewall rules blocked me from connecting to one or more addresses

I tried to connect to the following addresses, but was blocked by firewall rules:

  • esm.ubuntu.com
    • Triggering command: /usr/lib/apt/methods/https (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot finished work on behalf of lalitb July 2, 2025 16:46
@lalitb
Copy link
Member

lalitb commented Jul 2, 2025

We need to clarify first whether using generative AI in general, or Copilot in particular, can be allowed or not.

@marcalff If I understood correctly, you blocked the PR due the lack of clarity whether Gen AI is allowed by OpenTelemetry and Linux Foundation. Sharing the policy links from both these Orgs, and they allow the use of the Generative AI:

Linux Foundation Gen AI policy: https://www.linuxfoundation.org/legal/generative-ai
OpenTelemetry Gen AI policy: https://github.com/open-telemetry/community/blob/main/guides/contributor/genai.md

Let me know if these links address your concerns to unblock the PRs from GitHub.

@marcalff
Copy link
Member

marcalff commented Jul 2, 2025

We need to clarify first whether using generative AI in general, or Copilot in particular, can be allowed or not.

@marcalff If I understood correctly, you blocked the PR due the lack of clarity whether Gen AI is allowed by OpenTelemetry and Linux Foundation. Sharing the policy links from both these Orgs, and they allow the use of the Generative AI:

Linux Foundation Gen AI policy: https://www.linuxfoundation.org/legal/generative-ai OpenTelemetry Gen AI policy: https://github.com/open-telemetry/community/blob/main/guides/contributor/genai.md

Let me know if these links address your concerns to unblock the PRs from GitHub.

Thanks for the links.

No, this does not address my concerns, in particular around Intellectual Property (IP) and compatibility or the generated code with the Opentelemetry-cpp license.

@lalitb
Copy link
Member

lalitb commented Jul 2, 2025

No, this does not address my concerns, in particular around Intellectual Property (IP) and compatibility or the generated code with the Opentelemetry-cpp license.

@marcalff, Regarding Intellectual property and ownership concerns, GitHub copilot terms and conditions clearly specifies that

GitHub does not own Suggestions.  You retain ownership of Your Code. 

i.e., GitHub retains no ownership on the suggestion and code generated by the copilot. And the code, once merged will belong to the OpenTelemetry.

edit - Also to add, The Copilot user must sign the EasyCLA before any changes can be merged - this is currently being addressed for the OpenTelemetry organization. Once this is resolved, any contributed code will formally belong to the project under our licensing terms. We won't merge any PRs without proper EasyCLA compliance regardless.

@ThomsonTan
Copy link
Contributor

ThomsonTan commented Jul 2, 2025

edit - Also to ad, The Copilot user must sign the EasyCLA before any changes can be merged - this is currently being addressed for the OpenTelemetry organization. Once this is resolved, any contributed code will formally belong to the project under our licensing terms. We won't merge any PRs without proper EasyCLA compliance regardless.

Who is the Copilot user referenced here? The github user who assigned the issue to Copilot? Will other user involved in the issue discussion be also considered as the Copilot user?

@lalitb
Copy link
Member

lalitb commented Jul 2, 2025

Who i the Copilot user referenced here? The github user who assigned the issue to Copilot? Will other user involved in the issue discussion be also considered as the Copilot user?

It's the user which generated this PR.

@marcalff marcalff self-requested a review July 2, 2025 23:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Metrics SDK] Make cardinality limit configurable
4 participants