statsd-instrument 3.9.4 → 3.9.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8248b85fead25773388f7bec728c5a6347f7b7af61e37e064ee8ed93ba31397d
4
- data.tar.gz: 110ab2e5db1b66ef7c76e11ed7b82c925f767df0b09a1ca442afe95c31e30a40
3
+ metadata.gz: 90a8111f77847ab11ea592d7b4a15c91a1d52b1f706b9296f29afa0c943658e8
4
+ data.tar.gz: 444ef926b623f13fa9cb453b4179969a3655071a20c39b0f429dee3f22272662
5
5
  SHA512:
6
- metadata.gz: e85d2333cae7f6e843b25b3a1e64cf8bd1e68e47bcb530b6483dfa05e2672374791209c65f888cc6c9354f0e5bca997098f776c5db10f4dfd155005dd3f22bc9
7
- data.tar.gz: 330d5d152a42dd76fae018e4af8c4daa64f9be50391468f64bd338ddd91ecd668a6775f590e45452b552c6fe28f0e82e125a3a91476d5269e52d19ad0adee092
6
+ metadata.gz: ead57ab89be89a51dabe4eb08c93fdd73cb5a439d5605f38305268b81e079a62c18555e1cf462ce1aa231b1928301dfe62376fa31f073c419408e478dd5cfef3
7
+ data.tar.gz: 372737145878f6b8eda3c1e2d498fd40dbb7f5aa38acf13e94b93b2ace670e2bf787162dcf54b1489fb9d057ea76511b07a83b03a3bbcc740edf1c64081b403f
data/CHANGELOG.md CHANGED
@@ -6,6 +6,11 @@ section below.
6
6
 
7
7
  ## Unreleased changes
8
8
 
9
+ ## Version 3.9.5
10
+
11
+ - [#387](https://github.com/Shopify/statsd-instrument/pull/387) - Fixing bug when using aggregation and sending sampled
12
+ histogram metrics, they will not be scaled properly because of missing sampling rate in the final sent sample.
13
+
9
14
  ## Version 3.9.4
10
15
 
11
16
  - [#384](https://github.com/Shopify/statsd-instrument/pull/384) - Aggregation: fixing bug when sending metrics synchronously
@@ -3,13 +3,14 @@
3
3
  module StatsD
4
4
  module Instrument
5
5
  class AggregationKey
6
- attr_reader :name, :tags, :no_prefix, :type, :hash
6
+ attr_reader :name, :tags, :no_prefix, :type, :hash, :sample_rate
7
7
 
8
- def initialize(name, tags, no_prefix, type)
8
+ def initialize(name, tags, no_prefix, type, sample_rate: 1.0)
9
9
  @name = name
10
10
  @tags = tags
11
11
  @no_prefix = no_prefix
12
12
  @type = type
13
+ @sample_rate = sample_rate
13
14
  @hash = [@name, @tags, @no_prefix, @type].hash
14
15
  end
15
16
 
@@ -56,7 +57,7 @@ module StatsD
56
57
  key.name,
57
58
  key.type.to_s,
58
59
  agg_value,
59
- CONST_SAMPLE_RATE,
60
+ key.sample_rate,
60
61
  key.tags,
61
62
  )
62
63
  when GAUGE
@@ -134,7 +135,7 @@ module StatsD
134
135
  end
135
136
  end
136
137
 
137
- def aggregate_timing(name, value, tags: [], no_prefix: false, type: DISTRIBUTION)
138
+ def aggregate_timing(name, value, tags: [], no_prefix: false, type: DISTRIBUTION, sample_rate: CONST_SAMPLE_RATE)
138
139
  unless thread_healthcheck
139
140
  @sink << datagram_builder(no_prefix: no_prefix).timing_value_packed(
140
141
  name, type.to_s, [value], CONST_SAMPLE_RATE, tags
@@ -143,7 +144,7 @@ module StatsD
143
144
  end
144
145
 
145
146
  tags = tags_sorted(tags)
146
- key = packet_key(name, tags, no_prefix, type)
147
+ key = packet_key(name, tags, no_prefix, type, sample_rate: sample_rate)
147
148
 
148
149
  @mutex.synchronize do
149
150
  values = @aggregation_state[key] ||= []
@@ -176,6 +177,9 @@ module StatsD
176
177
 
177
178
  EMPTY_ARRAY = [].freeze
178
179
 
180
+ # Flushes the aggregated metrics to the sink.
181
+ # Iterates over the aggregation state and sends each metric to the sink.
182
+ # If you change this function, you need to update the logic in the finalizer as well.
179
183
  def do_flush
180
184
  @aggregation_state.each do |key, value|
181
185
  case key.type
@@ -191,7 +195,7 @@ module StatsD
191
195
  key.name,
192
196
  key.type.to_s,
193
197
  value,
194
- CONST_SAMPLE_RATE,
198
+ key.sample_rate,
195
199
  key.tags,
196
200
  )
197
201
  when GAUGE
@@ -219,8 +223,14 @@ module StatsD
219
223
  datagram_builder(no_prefix: false).normalize_tags(tags)
220
224
  end
221
225
 
222
- def packet_key(name, tags = "".b, no_prefix = false, type = COUNT)
223
- AggregationKey.new(DatagramBuilder.normalize_string(name), tags, no_prefix, type).freeze
226
+ def packet_key(name, tags = "".b, no_prefix = false, type = COUNT, sample_rate: CONST_SAMPLE_RATE)
227
+ AggregationKey.new(
228
+ DatagramBuilder.normalize_string(name),
229
+ tags,
230
+ no_prefix,
231
+ type,
232
+ sample_rate: sample_rate,
233
+ ).freeze
224
234
  end
225
235
 
226
236
  def datagram_builder(no_prefix:)
@@ -2,6 +2,6 @@
2
2
 
3
3
  module StatsD
4
4
  module Instrument
5
- VERSION = "3.9.4"
5
+ VERSION = "3.9.5"
6
6
  end
7
7
  end
@@ -58,6 +58,23 @@ class AggregatorTest < Minitest::Test
58
58
  assert_equal([1.0, 100.0], datagram.value)
59
59
  end
60
60
 
61
+ def test_timing_sampling_scaling
62
+ @subject.aggregate_timing("timing.sampled", 60.0, sample_rate: 0.01)
63
+ @subject.aggregate_timing("timing.sampled", 80.0, sample_rate: 0.01)
64
+ @subject.aggregate_timing("timing.unsampled", 60.0, sample_rate: 1.0)
65
+
66
+ @subject.flush
67
+
68
+ assert_equal(2, @sink.datagrams.size)
69
+
70
+ sampled_datagram = @sink.datagrams.find { |d| d.name == "timing.sampled" }
71
+ assert_equal([60.0, 80.0], sampled_datagram.value)
72
+ assert_equal(0.01, sampled_datagram.sample_rate)
73
+
74
+ unsampled_datagram = @sink.datagrams.find { |d| d.name == "timing.unsampled" }
75
+ assert_equal(60.0, unsampled_datagram.value)
76
+ end
77
+
61
78
  def test_mixed_type_timings
62
79
  @subject.aggregate_timing("foo_ms", 1, tags: { foo: "bar" }, type: :ms)
63
80
  @subject.aggregate_timing("foo_ms", 100, tags: { foo: "bar" }, type: :ms)
@@ -304,6 +321,7 @@ class AggregatorTest < Minitest::Test
304
321
  @subject.increment("foo", 1, tags: { foo: "bar" })
305
322
  @subject.aggregate_timing("bar", 100, tags: { foo: "bar" })
306
323
  @subject.gauge("baz", 100, tags: { foo: "bar" })
324
+ @subject.aggregate_timing("sampled_timing", 100, tags: { foo: "bar" }, sample_rate: 0.01)
307
325
 
308
326
  # Manually trigger the finalizer
309
327
  finalizer = StatsD::Instrument::Aggregator.finalize(
@@ -316,7 +334,7 @@ class AggregatorTest < Minitest::Test
316
334
  finalizer.call
317
335
 
318
336
  # Verify that all pending metrics are sent
319
- assert_equal(3, @sink.datagrams.size)
337
+ assert_equal(4, @sink.datagrams.size)
320
338
 
321
339
  counter_datagram = @sink.datagrams.find { |d| d.name == "foo" }
322
340
  assert_equal(1, counter_datagram.value)
@@ -329,5 +347,9 @@ class AggregatorTest < Minitest::Test
329
347
  gauge_datagram = @sink.datagrams.find { |d| d.name == "baz" }
330
348
  assert_equal(100, gauge_datagram.value)
331
349
  assert_equal(["foo:bar"], gauge_datagram.tags)
350
+
351
+ sampled_timing_datagram = @sink.datagrams.find { |d| d.name == "sampled_timing" }
352
+ assert_equal(100.0, sampled_timing_datagram.value)
353
+ assert_equal(0.01, sampled_timing_datagram.sample_rate)
332
354
  end
333
355
  end
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.9.4
4
+ version: 3.9.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jesse Storimer
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2024-10-29 00:00:00.000000000 Z
13
+ date: 2024-10-30 00:00:00.000000000 Z
14
14
  dependencies: []
15
15
  description: A StatsD client for Ruby apps. Provides metaprogramming methods to inject
16
16
  StatsD instrumentation into your code.