Skip to content

Conversation

@Joshua-Elsner
Copy link

Fixes #3303

This PR implements collection limits (max attributes, max events, max links, etc.) directly in the OTLP Exporter options. This allows users to enforce limits at the exporter level, which is useful when the exporter is used in a "firehose" mode or independently of the SDK limits.

Changes

  • OtlpRecordable: Added logic to check limits in SetAttribute, AddEvent, and AddLink. Drops are tracked in the proto dropped_counts.

  • Options: Added 5 limit fields to OtlpHttpExporterOptions and OtlpGrpcExporterOptions (default: UINT32_MAX / no limit).

  • Exporters: Updated MakeRecordable in both HTTP and gRPC exporters to pass the configured limits to the recordable.

  • Tests: Added unit tests in otlp_recordable_test.cc to verify drops occur when limits are exceeded.
    For significant contributions please make sure you have completed the following items:

  • CHANGELOG.md updated for non-trivial changes
    I did not update CHANGELOG.md to avoid merge conflicts, but I am happy to add an entry if requested.

  • Unit tests have been added

  • Changes in public API reviewed

@Joshua-Elsner Joshua-Elsner requested a review from a team as a code owner January 19, 2026 04:31
@linux-foundation-easycla
Copy link

linux-foundation-easycla bot commented Jan 19, 2026

CLA Signed

The committers listed above are authorized under a signed CLA.

  • ✅ login: Joshua-Elsner / name: Joshua (b38001d, c0d5c17)
  • ✅ login: lalitb / name: Lalit Kumar Bhasin (144d389)

@codecov
Copy link

codecov bot commented Jan 19, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 89.96%. Comparing base (2245926) to head (b38001d).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #3816      +/-   ##
==========================================
+ Coverage   89.94%   89.96%   +0.03%     
==========================================
  Files         225      225              
  Lines        7170     7170              
==========================================
+ Hits         6448     6450       +2     
+ Misses        722      720       -2     

see 2 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR implements collection limits for the OTLP exporter, allowing users to enforce constraints on attributes, events, and links at the exporter level. These limits are useful in "firehose" mode scenarios where the exporter operates independently of SDK limits. The implementation adds limit checks that increment dropped counters when thresholds are exceeded, providing proper telemetry signal loss tracking.

Changes:

  • Added five configurable limit parameters to both HTTP and gRPC OTLP exporter options with UINT32_MAX defaults (no limit)
  • Implemented limit enforcement in OtlpRecordable for attributes, events, links, and their nested attributes
  • Added comprehensive unit tests verifying limit enforcement and dropped count tracking

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
exporters/otlp/include/opentelemetry/exporters/otlp/otlp_recordable.h Added constructor parameters and private members for collection limits
exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_exporter_options.h Added five limit configuration fields to HTTP exporter options
exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_exporter_options.h Added five limit configuration fields to gRPC exporter options
exporters/otlp/src/otlp_recordable.cc Implemented limit checking logic in SetAttribute, AddEvent, and AddLink methods
exporters/otlp/src/otlp_http_exporter.cc Updated MakeRecordable to pass configured limits from options
exporters/otlp/src/otlp_grpc_exporter.cc Updated MakeRecordable to pass configured limits from options
exporters/otlp/test/otlp_recordable_test.cc Added test case validating limit enforcement for attributes, events, and per-event attributes

Comment on lines +602 to +641
TEST(OtlpRecordableTest, TestCollectionLimits)
{
// Initialize recordable with strict limits:
// Max Attributes: 2, Max Events: 2, Max Links: 2
// Max Attributes Per Event: 1, Max Attributes Per Link: 1
OtlpRecordable recordable(2, 2, 2, 1, 1);

// Test Attribute Limits
recordable.SetAttribute("attr1", 1);
recordable.SetAttribute("attr2", 2);
recordable.SetAttribute("attr3", 3); // Should be dropped

EXPECT_EQ(recordable.span().attributes_size(), 2);
EXPECT_EQ(recordable.span().dropped_attributes_count(), 1);

// Test Event Limits
std::map<std::string, int> empty_map;
common::KeyValueIterableView<std::map<std::string, int>> empty_attrs(empty_map);

recordable.AddEvent("event1", std::chrono::system_clock::now(), empty_attrs);
recordable.AddEvent("event2", std::chrono::system_clock::now(), empty_attrs);
recordable.AddEvent("event3", std::chrono::system_clock::now(),
empty_attrs); // Should be dropped

EXPECT_EQ(recordable.span().events_size(), 2);
EXPECT_EQ(recordable.span().dropped_events_count(), 1);

// Test Per-Event Attribute Limits
std::map<std::string, int> attr_map = {{"e_attr1", 1}, {"e_attr2", 2}};
common::KeyValueIterableView<std::map<std::string, int>> event_attrs(attr_map);

OtlpRecordable event_recordable(10, 10, 10, 1, 1);
event_recordable.AddEvent("event_with_attrs", std::chrono::system_clock::now(), event_attrs);

auto &event_list = event_recordable.span().events();
ASSERT_EQ(event_list.size(), 1);
// The event itself should have 1 attribute, and 1 dropped
EXPECT_EQ(event_list[0].attributes_size(), 1);
EXPECT_EQ(event_list[0].dropped_attributes_count(), 1);
}
Copy link

Copilot AI Jan 21, 2026

Choose a reason for hiding this comment

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

The test case validates attribute limits, event limits, and per-event attribute limits, but it does not test the link limits (max_links) or per-link attribute limits (max_attributes_per_link). Add test coverage for these scenarios to ensure the AddLink method correctly enforces limits and tracks dropped links and dropped link attributes.

Copilot uses AI. Check for mistakes.
Copy link
Member

Choose a reason for hiding this comment

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

@Joshua-Elsner

At first glance, looks like cp is correct here, and the test can be expanded for more coverage.
Please check and add test cases as needed.

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.

Thanks for the contribution.

See a minor comment, looks good otherwise.

Comment on lines +40 to +44
explicit OtlpRecordable(uint32_t max_attributes = UINT32_MAX,
uint32_t max_events = UINT32_MAX,
uint32_t max_links = UINT32_MAX,
uint32_t max_attributes_per_event = UINT32_MAX,
uint32_t max_attributes_per_link = UINT32_MAX)
Copy link
Member

Choose a reason for hiding this comment

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

For consistency, please use std::uint32_t and std::numeric_limits<std::uint32_t>::max() as well.

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.

Also, see comment on code coverage.

Comment on lines +602 to +641
TEST(OtlpRecordableTest, TestCollectionLimits)
{
// Initialize recordable with strict limits:
// Max Attributes: 2, Max Events: 2, Max Links: 2
// Max Attributes Per Event: 1, Max Attributes Per Link: 1
OtlpRecordable recordable(2, 2, 2, 1, 1);

// Test Attribute Limits
recordable.SetAttribute("attr1", 1);
recordable.SetAttribute("attr2", 2);
recordable.SetAttribute("attr3", 3); // Should be dropped

EXPECT_EQ(recordable.span().attributes_size(), 2);
EXPECT_EQ(recordable.span().dropped_attributes_count(), 1);

// Test Event Limits
std::map<std::string, int> empty_map;
common::KeyValueIterableView<std::map<std::string, int>> empty_attrs(empty_map);

recordable.AddEvent("event1", std::chrono::system_clock::now(), empty_attrs);
recordable.AddEvent("event2", std::chrono::system_clock::now(), empty_attrs);
recordable.AddEvent("event3", std::chrono::system_clock::now(),
empty_attrs); // Should be dropped

EXPECT_EQ(recordable.span().events_size(), 2);
EXPECT_EQ(recordable.span().dropped_events_count(), 1);

// Test Per-Event Attribute Limits
std::map<std::string, int> attr_map = {{"e_attr1", 1}, {"e_attr2", 2}};
common::KeyValueIterableView<std::map<std::string, int>> event_attrs(attr_map);

OtlpRecordable event_recordable(10, 10, 10, 1, 1);
event_recordable.AddEvent("event_with_attrs", std::chrono::system_clock::now(), event_attrs);

auto &event_list = event_recordable.span().events();
ASSERT_EQ(event_list.size(), 1);
// The event itself should have 1 attribute, and 1 dropped
EXPECT_EQ(event_list[0].attributes_size(), 1);
EXPECT_EQ(event_list[0].dropped_attributes_count(), 1);
}
Copy link
Member

Choose a reason for hiding this comment

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

@Joshua-Elsner

At first glance, looks like cp is correct here, and the test can be expanded for more coverage.
Please check and add test cases as needed.

@marcalff
Copy link
Member

  • I did not update CHANGELOG.md to avoid merge conflicts, but I am happy to add an entry if requested.

Please rebase the patch, fix remaining comments, and add a CHANGELOG entry.

Will merge after that.

@marcalff marcalff changed the title Feature/3303 otlp exporter limits [EXPORTER] Add support for otlp exporter collection limits Jan 28, 2026
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.

SDK Implement collection limits

5 participants