diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/CHANGELOG.md b/sdk/monitor/azure-monitor-opentelemetry-exporter/CHANGELOG.md index bd372f491e81..3cc2b39de100 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/CHANGELOG.md +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/CHANGELOG.md @@ -9,6 +9,8 @@ ### Breaking Changes ### Bugs Fixed +- Fix attributes override in Rate Limited Sampler + ([#45592](https://github.com/Azure/azure-sdk-for-python/pull/45592)) - Add environment variable to disable/enable custom properties truncation ([#45479](https://github.com/Azure/azure-sdk-for-python/pull/45479)) - Fix io counters import issue in performance counters diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_rate_limited_sampling.py b/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_rate_limited_sampling.py index 2c2a103c5a01..3061fcafaa03 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_rate_limited_sampling.py +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_rate_limited_sampling.py @@ -109,10 +109,8 @@ def should_sample( else: decision = Decision.DROP - if sampling_percentage == 100.0: - new_attributes = {} - else: - new_attributes = {} if attributes is None else dict(attributes) + new_attributes = {} if attributes is None else dict(attributes) + if sampling_percentage != 100.0: new_attributes[_SAMPLE_RATE_KEY] = sampling_percentage return SamplingResult( diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/trace/test_rate_limited_sampling.py b/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/trace/test_rate_limited_sampling.py index 9a6d0401498e..03133d065aef 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/trace/test_rate_limited_sampling.py +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/trace/test_rate_limited_sampling.py @@ -224,6 +224,39 @@ def test_sampling_attributes(self): self.assertGreaterEqual(float(sample_rate), 0.0) self.assertLessEqual(float(sample_rate), 100.0) + def test_sampling_percentage_100_does_not_add_sample_rate_attribute(self): + sampler = RateLimitedSampler(25.0) + + sampler._sampling_percentage_generator.get = Mock(return_value=100.0) + + original_attributes = {"service.name": "test-service", "operation.name": "test-operation"} + result = sampler.should_sample( + parent_context=None, trace_id=123, name="test-span", attributes=original_attributes + ) + + self.assertEqual(dict(result.attributes), original_attributes) + self.assertNotIn(_SAMPLE_RATE_KEY, result.attributes) + self.assertNotIn(_SAMPLE_RATE_KEY, original_attributes) + + result_none = sampler.should_sample(parent_context=None, trace_id=124, name="test-span", attributes=None) + self.assertEqual(dict(result_none.attributes), {}) + self.assertNotIn(_SAMPLE_RATE_KEY, result_none.attributes) + + def test_sampling_percentage_non_100_adds_sample_rate_attribute(self): + sampler = RateLimitedSampler(25.0) + + sampler._sampling_percentage_generator.get = Mock(return_value=42.0) + + original_attributes = {"service.name": "test-service", "operation.name": "test-operation"} + result = sampler.should_sample( + parent_context=None, trace_id=123, name="test-span", attributes=original_attributes + ) + + self.assertEqual(dict(result.attributes), {**original_attributes, _SAMPLE_RATE_KEY: 42.0}) + self.assertIn(_SAMPLE_RATE_KEY, result.attributes) + self.assertEqual(result.attributes[_SAMPLE_RATE_KEY], 42.0) + self.assertNotIn(_SAMPLE_RATE_KEY, original_attributes) + # Test sampling behavior with edge case trace ID values def test_sampler_with_extreme_trace_ids(self): sampler = RateLimitedSampler(1.0)