statsd-instrument 3.11.0 → 3.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1f2b45a3e809ef0e5ca26b7faf52512632705f62120b3b73987a10282e19ed76
4
- data.tar.gz: 7d7574e77adea4dc54fcf0355b83e1392623bcf2d4ecccd60a2cc101f62c84bb
3
+ metadata.gz: 3da8fd9b1f80c7cf776c41d335ab14858dd625299bbec536c7f8994dfe93baf6
4
+ data.tar.gz: b1ca1c4049a5f3956ea510074027bb577d26ab8a2033cf96d4af5fcc39fc90c9
5
5
  SHA512:
6
- metadata.gz: bb416ef206605fb8204acec2b0501e4722a2bd51d81fbc1083c4a4a96203a2838dd329355908ee83b64b7a3943f8f8af862cbf7d8433363d4452e68f14292f95
7
- data.tar.gz: bf0597922ce2dbe8837ef29b0de1f7c4fa1ca0e9623dc4d15628661b49059577d31499c46164a14e98744c5e765d68b407a15f14153c212ec245f3d90ed691e7
6
+ metadata.gz: f8774b020de05ec35687a82aca947a19b095ea34867fdcd73518748c9ccddfe28e41cdc41c2dfe1b9c2e4f657b4416218d67fe3b0e259a8bf10a810580f8ea60
7
+ data.tar.gz: 420ea1eb853426b83d2d5f546dde091d402aaff31ef243b912df3869dd02882e8ef24bde4b124f860beccb0e9528dcfbcd7ab6b25b36b3d2fc3e02798fa209e1
data/CHANGELOG.md CHANGED
@@ -6,6 +6,10 @@ section below.
6
6
 
7
7
  ## Unreleased changes
8
8
 
9
+ ## Version 3.11.1
10
+
11
+ - Fix `CompiledMetric::Distribution` applying `sample_rate` twice.
12
+
9
13
  ## Version 3.11.0
10
14
 
11
15
  - [#418](https://github.com/Shopify/statsd-instrument/pull/418) - Prevent misuse of `CompiledMetric` definitions by requiring a subclass when defining one.
@@ -285,6 +285,25 @@ module StatsD
285
285
  StatsD::Instrument::VOID
286
286
  end
287
287
 
288
+ # Emits a pre-sampled compiled distribution metric.
289
+ # This method is used when the generated compiled metric method already made
290
+ # the sampling decision before measuring block latency.
291
+ #
292
+ # @param precompiled_datagram [StatsD::Instrument::CompiledMetric::PrecompiledDatagram]
293
+ # The precompiled metric datagram
294
+ # @param value [Numeric] The metric value
295
+ # @return [void]
296
+ # @api private
297
+ def emit_presampled_precompiled_distribution_metric(precompiled_datagram, value)
298
+ if @enable_aggregation
299
+ @aggregator.aggregate_precompiled_timing_metric(precompiled_datagram, value)
300
+ return StatsD::Instrument::VOID
301
+ end
302
+
303
+ emit(precompiled_datagram.to_datagram(value))
304
+ StatsD::Instrument::VOID
305
+ end
306
+
288
307
  # Emits a precompiled metric for high-performance use cases.
289
308
  # This method is used by {StatsD::Instrument::CompiledMetric::Gauge} to emit metrics
290
309
  # with minimal allocations.
@@ -177,6 +177,10 @@ module StatsD
177
177
  default_val = default_value
178
178
  default_val_assignment = default_val.nil? ? "" : " = #{default_val.inspect}"
179
179
  allow_block = allow_measuring_latency
180
+ # Block-enabled compiled metrics run through generate_block_handler first,
181
+ # which applies sample_rate before emitting. Use the presampled client helper
182
+ # here so distributions don't make a second sampling decision.
183
+ client_emit_method = allow_block ? "emit_presampled_precompiled_#{method}_metric" : "emit_precompiled_#{method}_metric"
180
184
 
181
185
  method_code = <<~RUBY
182
186
  def self.#{method}(__value__#{default_val_assignment}, #{tag_names.map { |name| "#{name}:" }.join(", ")})
@@ -218,7 +222,7 @@ module StatsD
218
222
 
219
223
  __datagram__ ||= PrecompiledDatagram.new([#{tag_names.join(", ")}], @datagram_blueprint, @sample_rate)
220
224
 
221
- @singleton_client.emit_precompiled_#{method}_metric(__datagram__, __value__)
225
+ @singleton_client.#{client_emit_method}(__datagram__, __value__)
222
226
  __return_value__
223
227
  end
224
228
  RUBY
@@ -233,12 +237,16 @@ module StatsD
233
237
  method = method_name
234
238
  default_val = default_value
235
239
  allow_block = allow_measuring_latency
240
+ # Block-enabled compiled metrics run through generate_block_handler first,
241
+ # which applies sample_rate before emitting. Use the presampled client helper
242
+ # here so distributions don't make a second sampling decision.
243
+ client_emit_method = allow_block ? "emit_presampled_precompiled_#{method}_metric" : "emit_precompiled_#{method}_metric"
236
244
 
237
245
  instance_eval(<<~RUBY, __FILE__, __LINE__ + 1)
238
246
  def self.#{method}(__value__ = #{default_val.inspect})
239
247
  __return_value__ = StatsD::Instrument::VOID
240
248
  #{generate_block_handler if allow_block}
241
- @singleton_client.emit_precompiled_#{method}_metric(@static_datagram, __value__)
249
+ @singleton_client.#{client_emit_method}(@static_datagram, __value__)
242
250
  __return_value__
243
251
  end
244
252
  RUBY
@@ -2,6 +2,6 @@
2
2
 
3
3
  module StatsD
4
4
  module Instrument
5
- VERSION = "3.11.0"
5
+ VERSION = "3.11.1"
6
6
  end
7
7
  end
@@ -230,6 +230,43 @@ class CompiledMetricDistributionTest < Minitest::Test
230
230
  assert_equal(["env:production", "region:us-east", "service:web"], datagram.tags.sort)
231
231
  end
232
232
 
233
+ def test_sampled_distribution_value_uses_one_sampling_decision
234
+ sample_rate = 0.5
235
+ @sink.expects(:sample?).with(sample_rate).once.returns(true)
236
+
237
+ metric = Class.new(StatsD::Instrument::CompiledMetric::Distribution) do
238
+ define(
239
+ name: "foo.bar",
240
+ tags: { shop_id: Integer },
241
+ sample_rate: sample_rate,
242
+ )
243
+ end
244
+
245
+ metric.distribution(5, shop_id: 123)
246
+
247
+ assert_equal(1, @sink.datagrams.size)
248
+ assert_equal("test.foo.bar:5|d|@0.5|#shop_id:123", @sink.datagrams.first.source)
249
+ end
250
+
251
+ def test_sampled_distribution_block_uses_one_sampling_decision
252
+ sample_rate = 0.5
253
+ @sink.expects(:sample?).with(sample_rate).once.returns(true)
254
+ Process.stubs(:clock_gettime).with(Process::CLOCK_MONOTONIC, :float_millisecond).returns(100.0, 125.0)
255
+
256
+ metric = Class.new(StatsD::Instrument::CompiledMetric::Distribution) do
257
+ define(
258
+ name: "foo.bar",
259
+ sample_rate: sample_rate,
260
+ )
261
+ end
262
+
263
+ returned_value = metric.distribution { :result }
264
+
265
+ assert_equal(:result, returned_value)
266
+ assert_equal(1, @sink.datagrams.size)
267
+ assert_equal("test.foo.bar:25.0|d|@0.5", @sink.datagrams.first.source)
268
+ end
269
+
233
270
  def test_latency_as_value_when_block_provided
234
271
  metric = Class.new(StatsD::Instrument::CompiledMetric::Distribution) do
235
272
  define(
@@ -415,18 +452,17 @@ class CompiledMetricDistributionWithAggregationTest < Minitest::Test
415
452
  end
416
453
 
417
454
  def test_sample_rate_with_aggregation
418
- # When aggregating with sample_rate, sampling happens before aggregation
419
- # This test verifies that with a sample_rate >0, a subset of distributions are aggregated
455
+ sample_rate = 0.5
456
+ @sink.expects(:sample?).with(sample_rate).times(5).returns(false, true, false, false, true)
457
+
420
458
  metric = Class.new(StatsD::Instrument::CompiledMetric::Distribution) do
421
459
  define(
422
460
  name: "foo.bar",
423
461
  static_tags: { service: "web" },
424
- sample_rate: 0.5,
462
+ sample_rate: sample_rate,
425
463
  )
426
464
  end
427
465
 
428
- metric.stubs(:sample?).returns(false, true, false, false, true)
429
-
430
466
  metric.distribution(1)
431
467
  metric.distribution(2)
432
468
  metric.distribution(3)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: statsd-instrument
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.11.0
4
+ version: 3.11.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jesse Storimer
@@ -135,7 +135,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
135
135
  - !ruby/object:Gem::Version
136
136
  version: '0'
137
137
  requirements: []
138
- rubygems_version: 4.0.9
138
+ rubygems_version: 4.0.14
139
139
  specification_version: 4
140
140
  summary: A StatsD client for Ruby apps
141
141
  test_files: