From 402e3142a94ebc438b3da693178c98c29b6f1a53 Mon Sep 17 00:00:00 2001 From: Karim El-Husseiny Date: Mon, 9 Feb 2026 16:38:51 +0200 Subject: [PATCH 1/2] fix: Pass metric_prefix to Aggregator finalizer The Finalizer struct expects 6 arguments but only 5 were passed, leaving metric_prefix as nil. This caused metrics to lose their prefix when flushed during garbage collection. The bug only manifests when: 1. Aggregator is created with a prefix 2. Metrics are added without tags (tags trigger datagram_builder creation) 3. GC runs before normal flush, triggering the finalizer --- CHANGELOG.md | 1 + lib/statsd/instrument/aggregator.rb | 1 + test/aggregator_test.rb | 25 +++++++++++++++++++++++++ 3 files changed, 27 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dbf3d20a..470b0cac 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. - [#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). - [#407](https://github.com/Shopify/statsd-instrument/pull/407) - Add support for `Symbol` and `:Boolean` types in `CompiledMetric` dynamic tags, allowing symbol and boolean values to be used as tag values. diff --git a/lib/statsd/instrument/aggregator.rb b/lib/statsd/instrument/aggregator.rb index f32f6104..f36d1b0e 100644 --- a/lib/statsd/instrument/aggregator.rb +++ b/lib/statsd/instrument/aggregator.rb @@ -132,6 +132,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 6745330d..555bb301 100644 --- a/test/aggregator_test.rb +++ b/test/aggregator_test.rb @@ -179,6 +179,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) From cdc997d58c3a61eb42076dd981fd956b7598046a Mon Sep 17 00:00:00 2001 From: Karim El-Husseiny Date: Mon, 9 Feb 2026 16:44:21 +0200 Subject: [PATCH 2/2] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cdfd720..9f1d6cc0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ creating a pull request, please add an entry to the "unreleased changes" 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`.