statsd-instrument 3.9.0 → 3.9.2

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: 9776ac7b9f3dc12364a1ba286d7b77330c52b0aa8560c29c0ff47c8033c066df
4
- data.tar.gz: ecfc23f01f345eabc82d1c696c2fb280cc3185f2d30b47e8e5c75326077f10bd
3
+ metadata.gz: a0d94832ea51c0d6253bc8e1d0255b3d17dc2fa46d900c8159c86855a30ed333
4
+ data.tar.gz: ce59be3645a74e337c9484834cd40f1d37ed5ee16a1ebaabd88ef6b299697e4a
5
5
  SHA512:
6
- metadata.gz: e831388ae5824bd7d1e53b9eefc399dd639210648976adeafd48fabd9d4a37705af2d5814868e75922cc27840cba42d5066054751a8120e4ea8d055efdaea379
7
- data.tar.gz: 91f63290ef5d9dcc032e0fcdad8e34acdc5448d563e1eedd71b23a68330060ba58af3999ace24b4a82567f2e5c96182996c3f8dda940684a1df93fe9acee02ef
6
+ metadata.gz: 72350208478d416e44bb8f939d398c3359c7d45daae1c41fc39bae490fd16ea97932a107075c993cdb46ca7285cac00242acf13e0d68c21d392bc879a133b7f8
7
+ data.tar.gz: 9401843bc9a07b36028d11749a0c813a43d5f307a650ce62823d7d8e953129a148fbdbcb9cf57aec8556973a752cb3a87daf2a874244cf0bc73e62e6bfba61e0
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 3.3.1
1
+ 3.3.3
data/CHANGELOG.md CHANGED
@@ -6,6 +6,17 @@ section below.
6
6
 
7
7
  ## Unreleased changes
8
8
 
9
+ ## Version 3.9.2
10
+
11
+ - [#381](https://github.com/Shopify/statsd-instrument/pull/381) - Reduce log level of some messages inside new Aggregator
12
+ to avoid contention and verbosity.
13
+
14
+ ## Version 3.9.1
15
+
16
+ - [#378](https://github.com/Shopify/statsd-instrument/pull/378) - Respect sampling rate when aggregation is enabled, just for timing metrics.
17
+ Not respecting sampling rate, incurs in a performance penalty, as we will send more metrics than expected.
18
+ Moreover, it overloads the StatsD server, which has to send out and process more metrics than expected.
19
+
9
20
  ## Version 3.9.0
10
21
 
11
22
  - Introduced an experimental aggregation feature to improve the efficiency of metrics reporting by aggregating
@@ -15,7 +26,7 @@ decrease the overhead associated with high-frequency metric reporting. To enable
15
26
  - Added support for sending StatsD via Unix domain sockets. This feature is enabled by
16
27
  setting the `STATSD_SOCKET` environment variable to the path of the Unix domain socket.
17
28
  - :warning: **Possible breaking change**: We removed/renamed some classes and now Sinks are generic, so the classes `UDPSink` and `UDPBatchedSink` are now called
18
- `StatsD::Instrument::Sink` and `StatsD::Instrument::Sink` respectively.
29
+ `StatsD::Instrument::Sink` and `StatsD::Instrument::BatchedSink` respectively.
19
30
  If you used those internal classes, you will need to update your code to use the new classes.
20
31
 
21
32
  ## Version 3.8.0
@@ -24,12 +24,15 @@ module StatsD
24
24
  end
25
25
 
26
26
  class Aggregator
27
+ DEFAULT_MAX_CONTEXT_SIZE = 250
28
+
27
29
  CONST_SAMPLE_RATE = 1.0
28
30
  COUNT = :c
29
31
  DISTRIBUTION = :d
30
32
  MEASURE = :ms
31
33
  HISTOGRAM = :h
32
34
  GAUGE = :g
35
+ private_constant :COUNT, :DISTRIBUTION, :MEASURE, :HISTOGRAM, :GAUGE, :CONST_SAMPLE_RATE
33
36
 
34
37
  class << self
35
38
  def finalize(aggregation_state, sink, datagram_builders, datagram_builder_class, default_tags)
@@ -78,7 +81,14 @@ module StatsD
78
81
  # @param default_tags [Array<String>] The tags to add to all metrics.
79
82
  # @param flush_interval [Float] The interval at which to flush the aggregated metrics.
80
83
  # @param max_values [Integer] The maximum number of values to aggregate before flushing.
81
- def initialize(sink, datagram_builder_class, prefix, default_tags, flush_interval: 5.0, max_values: 100)
84
+ def initialize(
85
+ sink,
86
+ datagram_builder_class,
87
+ prefix,
88
+ default_tags,
89
+ flush_interval: 5.0,
90
+ max_values: DEFAULT_MAX_CONTEXT_SIZE
91
+ )
82
92
  @sink = sink
83
93
  @datagram_builder_class = datagram_builder_class
84
94
  @metric_prefix = prefix
@@ -236,11 +246,11 @@ module StatsD
236
246
  return false unless Thread.main.alive?
237
247
 
238
248
  if @pid != Process.pid
239
- StatsD.logger.info { "[#{self.class.name}] Restarting the flush thread after fork" }
249
+ StatsD.logger.debug { "[#{self.class.name}] Restarting the flush thread after fork" }
240
250
  @pid = Process.pid
241
251
  @aggregation_state.clear
242
252
  else
243
- StatsD.logger.info { "[#{self.class.name}] Restarting the flush thread" }
253
+ StatsD.logger.debug { "[#{self.class.name}] Restarting the flush thread" }
244
254
  end
245
255
  @flush_thread = Thread.new do
246
256
  Thread.current.abort_on_exception = true
@@ -156,7 +156,8 @@ module StatsD
156
156
  sink: StatsD::Instrument::NullSink.new,
157
157
  datagram_builder_class: self.class.datagram_builder_class_for_implementation(implementation),
158
158
  enable_aggregation: false,
159
- aggregation_flush_interval: 2.0
159
+ aggregation_flush_interval: 2.0,
160
+ aggregation_max_context_size: StatsD::Instrument::Aggregator::DEFAULT_MAX_CONTEXT_SIZE
160
161
  )
161
162
  @sink = sink
162
163
  @datagram_builder_class = datagram_builder_class
@@ -176,6 +177,7 @@ module StatsD
176
177
  prefix,
177
178
  default_tags,
178
179
  flush_interval: @aggregation_flush_interval,
180
+ max_values: aggregation_max_context_size,
179
181
  )
180
182
  end
181
183
  end
@@ -237,6 +239,19 @@ module StatsD
237
239
  # @param tags (see #increment)
238
240
  # @return [void]
239
241
  def measure(name, value = nil, sample_rate: nil, tags: nil, no_prefix: false, &block)
242
+ sample_rate ||= @default_sample_rate
243
+ if sample_rate && !sample?(sample_rate)
244
+ # For all timing metrics, we have to use the sampling logic.
245
+ # Not doing so would impact performance and CPU usage.
246
+ # See Datadog's documentation for more details: https://github.com/DataDog/datadog-go/blob/20af2dbfabbbe6bd0347780cd57ed931f903f223/statsd/aggregator.go#L281-L283
247
+
248
+ if block_given?
249
+ return yield
250
+ end
251
+
252
+ return StatsD::Instrument::VOID
253
+ end
254
+
240
255
  if block_given?
241
256
  return latency(name, sample_rate: sample_rate, tags: tags, metric_type: :ms, no_prefix: no_prefix, &block)
242
257
  end
@@ -245,10 +260,7 @@ module StatsD
245
260
  @aggregator.aggregate_timing(name, value, tags: tags, no_prefix: no_prefix, type: :ms)
246
261
  return StatsD::Instrument::VOID
247
262
  end
248
- sample_rate ||= @default_sample_rate
249
- if sample_rate.nil? || sample?(sample_rate)
250
- emit(datagram_builder(no_prefix: no_prefix).ms(name, value, sample_rate, tags))
251
- end
263
+ emit(datagram_builder(no_prefix: no_prefix).ms(name, value, sample_rate, tags))
252
264
  StatsD::Instrument::VOID
253
265
  end
254
266
 
@@ -306,6 +318,19 @@ module StatsD
306
318
  # @param tags (see #increment)
307
319
  # @return [void]
308
320
  def distribution(name, value = nil, sample_rate: nil, tags: nil, no_prefix: false, &block)
321
+ sample_rate ||= @default_sample_rate
322
+ if sample_rate && !sample?(sample_rate)
323
+ # For all timing metrics, we have to use the sampling logic.
324
+ # Not doing so would impact performance and CPU usage.
325
+ # See Datadog's documentation for more details: https://github.com/DataDog/datadog-go/blob/20af2dbfabbbe6bd0347780cd57ed931f903f223/statsd/aggregator.go#L281-L283
326
+
327
+ if block_given?
328
+ return yield
329
+ end
330
+
331
+ return StatsD::Instrument::VOID
332
+ end
333
+
309
334
  if block_given?
310
335
  return latency(name, sample_rate: sample_rate, tags: tags, metric_type: :d, no_prefix: no_prefix, &block)
311
336
  end
@@ -315,10 +340,7 @@ module StatsD
315
340
  return StatsD::Instrument::VOID
316
341
  end
317
342
 
318
- sample_rate ||= @default_sample_rate
319
- if sample_rate.nil? || sample?(sample_rate)
320
- emit(datagram_builder(no_prefix: no_prefix).d(name, value, sample_rate, tags))
321
- end
343
+ emit(datagram_builder(no_prefix: no_prefix).d(name, value, sample_rate, tags))
322
344
  StatsD::Instrument::VOID
323
345
  end
324
346
 
@@ -334,14 +356,20 @@ module StatsD
334
356
  # @param tags (see #increment)
335
357
  # @return [void]
336
358
  def histogram(name, value, sample_rate: nil, tags: nil, no_prefix: false)
359
+ sample_rate ||= @default_sample_rate
360
+ if sample_rate && !sample?(sample_rate)
361
+ # For all timing metrics, we have to use the sampling logic.
362
+ # Not doing so would impact performance and CPU usage.
363
+ # See Datadog's documentation for more details: https://github.com/DataDog/datadog-go/blob/20af2dbfabbbe6bd0347780cd57ed931f903f223/statsd/aggregator.go#L281-L283
364
+ return StatsD::Instrument::VOID
365
+ end
366
+
337
367
  if @enable_aggregation
338
368
  @aggregator.aggregate_timing(name, value, tags: tags, no_prefix: no_prefix, type: :h)
369
+ return StatsD::Instrument::VOID
339
370
  end
340
371
 
341
- sample_rate ||= @default_sample_rate
342
- if sample_rate.nil? || sample?(sample_rate)
343
- emit(datagram_builder(no_prefix: no_prefix).h(name, value, sample_rate, tags))
344
- end
372
+ emit(datagram_builder(no_prefix: no_prefix).h(name, value, sample_rate, tags))
345
373
  StatsD::Instrument::VOID
346
374
  end
347
375
 
@@ -125,6 +125,13 @@ module StatsD
125
125
  Float(env.fetch("STATSD_AGGREGATION_INTERVAL", 2.0))
126
126
  end
127
127
 
128
+ def aggregation_max_context_size
129
+ Integer(env.fetch(
130
+ "STATSD_AGGREGATION_MAX_CONTEXT_SIZE",
131
+ StatsD::Instrument::Aggregator::DEFAULT_MAX_CONTEXT_SIZE,
132
+ ))
133
+ end
134
+
128
135
  def client
129
136
  StatsD::Instrument::Client.from_env(self)
130
137
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module StatsD
4
4
  module Instrument
5
- VERSION = "3.9.0"
5
+ VERSION = "3.9.2"
6
6
  end
7
7
  end
data/test/client_test.rb CHANGED
@@ -245,6 +245,18 @@ class ClientTest < Minitest::Test
245
245
  5.times { client.increment("metric") }
246
246
  end
247
247
 
248
+ def test_sampling_with_aggregation
249
+ mock_sink = mock("sink")
250
+ mock_sink.stubs(:sample?).returns(false, true, false, false, true)
251
+ # Since we are aggregating, we only expect a single datagram.
252
+ mock_sink.expects(:<<).with("metric:60:60|d").once
253
+ mock_sink.expects(:flush).once
254
+
255
+ client = StatsD::Instrument::Client.new(sink: mock_sink, default_sample_rate: 0.5, enable_aggregation: true)
256
+ 5.times { client.distribution("metric", 60) }
257
+ client.force_flush
258
+ end
259
+
248
260
  def test_clone_with_prefix_option
249
261
  # Both clients will use the same sink.
250
262
  mock_sink = mock("sink")
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.0
4
+ version: 3.9.2
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-08-19 00:00:00.000000000 Z
13
+ date: 2024-10-09 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.
@@ -130,7 +130,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
130
130
  - !ruby/object:Gem::Version
131
131
  version: '0'
132
132
  requirements: []
133
- rubygems_version: 3.5.17
133
+ rubygems_version: 3.5.21
134
134
  signing_key:
135
135
  specification_version: 4
136
136
  summary: A StatsD client for Ruby apps