diff --git a/CHANGELOG.md b/CHANGELOG.md index a3b8a685..9f1d6cc0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ section below. ## Unreleased changes +- [#416](https://github.com/Shopify/statsd-instrument/pull/416) - Fix missing `metric_prefix` in Aggregator finalizer, causing metrics to lose their prefix when flushed during GC. - [#415](https://github.com/Shopify/statsd-instrument/pull/415) - Fix `sample_rate` being ignored when aggregation is enabled. Previously, `increment`, `measure`, and `histogram` calls would bypass sampling entirely when aggregation was enabled, causing metrics to be emitted at 100% rate regardless of the configured sample rate. - [#411](https://github.com/Shopify/statsd-instrument/pull/403) - Add `CompiledMetric::Gauge` as the second metric type to support pre-compiled metric datagrams. It can be used as a replacement over standard `StatsD.gauge`. - Add support for `nil` tag values in `CompiledMetric` dynamic tags (converted to empty string). diff --git a/lib/statsd/instrument/aggregator.rb b/lib/statsd/instrument/aggregator.rb index e32b3fcc..f47fba40 100644 --- a/lib/statsd/instrument/aggregator.rb +++ b/lib/statsd/instrument/aggregator.rb @@ -133,6 +133,7 @@ def initialize( @datagram_builders, @datagram_builder_class, @default_tags, + @metric_prefix, ) ObjectSpace.define_finalizer( diff --git a/test/aggregator_test.rb b/test/aggregator_test.rb index 8ce7c7f0..f7e5c29b 100644 --- a/test/aggregator_test.rb +++ b/test/aggregator_test.rb @@ -216,6 +216,31 @@ def test_with_prefix assert_equal(1, @sink.datagrams.last.value) end + def test_finalizer_with_prefix + # Test that the finalizer correctly uses the prefix when flushing metrics + # IMPORTANT: Use empty tags to ensure datagram_builder is not pre-created by tags_sorted + aggregator = StatsD::Instrument::Aggregator.new(@sink, StatsD::Instrument::DatagramBuilder, "MyApp", []) + + aggregator.increment("foo", 1, tags: []) + aggregator.increment("bar", 1, tags: [], no_prefix: true) + + # Manually trigger the finalizer (simulates GC cleanup) + finalizer = StatsD::Instrument::Aggregator.finalize( + aggregator.instance_variable_get(:@finalizer), + ) + finalizer.call + + assert_equal(2, @sink.datagrams.size) + + prefixed_datagram = @sink.datagrams.find { |d| d.name == "MyApp.foo" } + refute_nil(prefixed_datagram, "Expected to find datagram with prefix 'MyApp.foo'") + assert_equal(1, prefixed_datagram.value) + + unprefixed_datagram = @sink.datagrams.find { |d| d.name == "bar" } + refute_nil(unprefixed_datagram, "Expected to find datagram without prefix 'bar'") + assert_equal(1, unprefixed_datagram.value) + end + def test_synchronous_operation_on_thread_failure # Force thread_healthcheck to return false @subject.stubs(:thread_healthcheck).returns(false)