statsd-instrument 3.11.2 → 4.0.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.
@@ -36,8 +36,8 @@ class AggregatorTest < Minitest::Test
36
36
  end
37
37
 
38
38
  def test_increment_simple
39
- @subject.increment("foo", 1, tags: { foo: "bar" })
40
- @subject.increment("foo", 1, tags: { foo: "bar" })
39
+ @subject.increment("foo", 1, ["foo:bar"], false, 1.0)
40
+ @subject.increment("foo", 1, ["foo:bar"], false, 1.0)
41
41
  @subject.flush
42
42
 
43
43
  datagram = @sink.datagrams.first
@@ -48,10 +48,9 @@ class AggregatorTest < Minitest::Test
48
48
  end
49
49
 
50
50
  def test_increment_with_sample_rate
51
- # Test that increment properly passes through sample_rate
52
- @subject.increment("counter.sampled", 1, tags: { foo: "bar" }, sample_rate: 0.5)
53
- @subject.increment("counter.sampled", 2, tags: { foo: "bar" }, sample_rate: 0.5)
54
- @subject.increment("counter.unsampled", 1, tags: { foo: "bar" })
51
+ @subject.increment("counter.sampled", 1, ["foo:bar"], false, 0.5)
52
+ @subject.increment("counter.sampled", 2, ["foo:bar"], false, 0.5)
53
+ @subject.increment("counter.unsampled", 1, ["foo:bar"], false, 1.0)
55
54
  @subject.flush
56
55
 
57
56
  assert_equal(2, @sink.datagrams.size)
@@ -68,11 +67,10 @@ class AggregatorTest < Minitest::Test
68
67
  end
69
68
 
70
69
  def test_increment_different_sample_rates_create_different_aggregation_keys
71
- # Counters with different sample rates should be aggregated separately
72
- @subject.increment("counter", 1, sample_rate: 0.5)
73
- @subject.increment("counter", 2, sample_rate: 0.5)
74
- @subject.increment("counter", 10, sample_rate: 0.1)
75
- @subject.increment("counter", 20, sample_rate: 0.1)
70
+ @subject.increment("counter", 1, [], false, 0.5)
71
+ @subject.increment("counter", 2, [], false, 0.5)
72
+ @subject.increment("counter", 10, [], false, 0.1)
73
+ @subject.increment("counter", 20, [], false, 0.1)
76
74
  @subject.flush
77
75
 
78
76
  assert_equal(2, @sink.datagrams.size)
@@ -85,8 +83,8 @@ class AggregatorTest < Minitest::Test
85
83
  end
86
84
 
87
85
  def test_distribution_simple
88
- @subject.aggregate_timing("foo", 1, tags: { foo: "bar" })
89
- @subject.aggregate_timing("foo", 100, tags: { foo: "bar" })
86
+ @subject.aggregate_timing("foo", 1, ["foo:bar"], false, :d, 1.0)
87
+ @subject.aggregate_timing("foo", 100, ["foo:bar"], false, :d, 1.0)
90
88
  @subject.flush
91
89
 
92
90
  datagram = @sink.datagrams.first
@@ -96,9 +94,9 @@ class AggregatorTest < Minitest::Test
96
94
  end
97
95
 
98
96
  def test_timing_sampling_scaling
99
- @subject.aggregate_timing("timing.sampled", 60.0, sample_rate: 0.01)
100
- @subject.aggregate_timing("timing.sampled", 80.0, sample_rate: 0.01)
101
- @subject.aggregate_timing("timing.unsampled", 60.0, sample_rate: 1.0)
97
+ @subject.aggregate_timing("timing.sampled", 60.0, [], false, :d, 0.01)
98
+ @subject.aggregate_timing("timing.sampled", 80.0, [], false, :d, 0.01)
99
+ @subject.aggregate_timing("timing.unsampled", 60.0, [], false, :d, 1.0)
102
100
 
103
101
  @subject.flush
104
102
 
@@ -114,11 +112,11 @@ class AggregatorTest < Minitest::Test
114
112
  end
115
113
 
116
114
  def test_mixed_type_timings
117
- @subject.aggregate_timing("foo_ms", 1, tags: { foo: "bar" }, type: :ms)
118
- @subject.aggregate_timing("foo_ms", 100, tags: { foo: "bar" }, type: :ms)
115
+ @subject.aggregate_timing("foo_ms", 1, ["foo:bar"], false, :ms, 1.0)
116
+ @subject.aggregate_timing("foo_ms", 100, ["foo:bar"], false, :ms, 1.0)
119
117
 
120
- @subject.aggregate_timing("foo_d", 100, tags: { foo: "bar" }, type: :d)
121
- @subject.aggregate_timing("foo_d", 120, tags: { foo: "bar" }, type: :d)
118
+ @subject.aggregate_timing("foo_d", 100, ["foo:bar"], false, :d, 1.0)
119
+ @subject.aggregate_timing("foo_d", 120, ["foo:bar"], false, :d, 1.0)
122
120
 
123
121
  @subject.flush
124
122
 
@@ -130,8 +128,8 @@ class AggregatorTest < Minitest::Test
130
128
  end
131
129
 
132
130
  def test_gauge_simple
133
- @subject.gauge("foo", 1, tags: { foo: "bar" })
134
- @subject.gauge("foo", 100, tags: { foo: "bar" })
131
+ @subject.gauge("foo", 1, ["foo:bar"], false)
132
+ @subject.gauge("foo", 100, ["foo:bar"], false)
135
133
  @subject.flush
136
134
 
137
135
  datagram = @sink.datagrams.first
@@ -141,18 +139,18 @@ class AggregatorTest < Minitest::Test
141
139
  end
142
140
 
143
141
  def test_increment_with_tags_in_different_orders
144
- @subject.increment("foo", 1, tags: ["tag1:val1", "tag2:val2"])
145
- @subject.increment("foo", 1, tags: ["tag2:val2", "tag1:val1"])
142
+ @subject.increment("foo", 1, ["tag1:val1", "tag2:val2"], false, 1.0)
143
+ @subject.increment("foo", 1, ["tag2:val2", "tag1:val1"], false, 1.0)
146
144
  @subject.flush
147
145
 
148
146
  assert_equal(2, @sink.datagrams.first.value)
149
147
  end
150
148
 
151
149
  def test_increment_with_different_tag_values
152
- @subject.increment("foo", 1, tags: ["tag1:val1", "tag2:val2"])
153
- @subject.increment("foo", 1, tags: { tag1: "val1", tag2: "val2" })
150
+ @subject.increment("foo", 1, ["tag1:val1", "tag2:val2"], false, 1.0)
151
+ @subject.increment("foo", 1, { tag1: "val1", tag2: "val2" }, false, 1.0)
154
152
 
155
- @subject.increment("bar")
153
+ @subject.increment("bar", 1, [], false, 1.0)
156
154
  @subject.flush
157
155
 
158
156
  assert_equal(2, @sink.datagrams.first.value)
@@ -161,8 +159,8 @@ class AggregatorTest < Minitest::Test
161
159
  end
162
160
 
163
161
  def test_increment_with_different_metric_names
164
- @subject.increment("foo", 1, tags: ["tag1:val1", "tag2:val2"])
165
- @subject.increment("bar", 1, tags: ["tag1:val1", "tag2:val2"])
162
+ @subject.increment("foo", 1, ["tag1:val1", "tag2:val2"], false, 1.0)
163
+ @subject.increment("bar", 1, ["tag1:val1", "tag2:val2"], false, 1.0)
166
164
  @subject.flush
167
165
 
168
166
  assert_equal(1, @sink.datagrams.find { |d| d.name == "foo" }.value)
@@ -170,22 +168,22 @@ class AggregatorTest < Minitest::Test
170
168
  end
171
169
 
172
170
  def test_increment_with_different_values
173
- @subject.increment("foo", 1, tags: ["tag1:val1", "tag2:val2"])
174
- @subject.increment("foo", 2, tags: ["tag1:val1", "tag2:val2"])
171
+ @subject.increment("foo", 1, ["tag1:val1", "tag2:val2"], false, 1.0)
172
+ @subject.increment("foo", 2, ["tag1:val1", "tag2:val2"], false, 1.0)
175
173
  @subject.flush
176
174
 
177
175
  assert_equal(3, @sink.datagrams.first.value)
178
176
  end
179
177
 
180
178
  def test_send_mixed_types_will_pass_through
181
- @subject.increment("test_counter", 1, tags: ["tag1:val1", "tag2:val2"])
182
- @subject.aggregate_timing("test_counter", 100, tags: ["tag1:val1", "tag2:val2"])
179
+ @subject.increment("test_counter", 1, ["tag1:val1", "tag2:val2"], false, 1.0)
180
+ @subject.aggregate_timing("test_counter", 100, ["tag1:val1", "tag2:val2"], false, :d, 1.0)
183
181
 
184
- @subject.gauge("test_gauge", 100, tags: ["tag1:val1", "tag2:val2"])
185
- @subject.increment("test_gauge", 1, tags: ["tag1:val1", "tag2:val2"])
182
+ @subject.gauge("test_gauge", 100, ["tag1:val1", "tag2:val2"], false)
183
+ @subject.increment("test_gauge", 1, ["tag1:val1", "tag2:val2"], false, 1.0)
186
184
 
187
- @subject.aggregate_timing("test_timing", 100, tags: ["tag1:val1", "tag2:val2"])
188
- @subject.gauge("test_timing", 100, tags: ["tag1:val1", "tag2:val2"])
185
+ @subject.aggregate_timing("test_timing", 100, ["tag1:val1", "tag2:val2"], false, :d, 1.0)
186
+ @subject.gauge("test_timing", 100, ["tag1:val1", "tag2:val2"], false)
189
187
  @subject.flush
190
188
 
191
189
  assert_equal(6, @sink.datagrams.size)
@@ -202,10 +200,10 @@ class AggregatorTest < Minitest::Test
202
200
  def test_with_prefix
203
201
  aggregator = StatsD::Instrument::Aggregator.new(@sink, StatsD::Instrument::DatagramBuilder, "MyApp", [])
204
202
 
205
- aggregator.increment("foo", 1, tags: ["tag1:val1", "tag2:val2"])
206
- aggregator.increment("foo", 1, tags: ["tag1:val1", "tag2:val2"])
203
+ aggregator.increment("foo", 1, ["tag1:val1", "tag2:val2"], false, 1.0)
204
+ aggregator.increment("foo", 1, ["tag1:val1", "tag2:val2"], false, 1.0)
207
205
 
208
- aggregator.increment("foo", 1, tags: ["tag1:val1", "tag2:val2"], no_prefix: true)
206
+ aggregator.increment("foo", 1, ["tag1:val1", "tag2:val2"], true, 1.0)
209
207
  aggregator.flush
210
208
 
211
209
  assert_equal(2, @sink.datagrams.size)
@@ -217,14 +215,11 @@ class AggregatorTest < Minitest::Test
217
215
  end
218
216
 
219
217
  def test_finalizer_with_prefix
220
- # Test that the finalizer correctly uses the prefix when flushing metrics
221
- # IMPORTANT: Use empty tags to ensure datagram_builder is not pre-created by tags_sorted
222
218
  aggregator = StatsD::Instrument::Aggregator.new(@sink, StatsD::Instrument::DatagramBuilder, "MyApp", [])
223
219
 
224
- aggregator.increment("foo", 1, tags: [])
225
- aggregator.increment("bar", 1, tags: [], no_prefix: true)
220
+ aggregator.increment("foo", 1, [], false, 1.0)
221
+ aggregator.increment("bar", 1, [], true, 1.0)
226
222
 
227
- # Manually trigger the finalizer (simulates GC cleanup)
228
223
  finalizer = StatsD::Instrument::Aggregator.finalize(
229
224
  aggregator.instance_variable_get(:@finalizer),
230
225
  )
@@ -242,18 +237,15 @@ class AggregatorTest < Minitest::Test
242
237
  end
243
238
 
244
239
  def test_synchronous_operation_on_thread_failure
245
- # Force thread_healthcheck to return false
246
240
  @subject.stubs(:thread_healthcheck).returns(false)
247
241
 
248
- # Stub methods on @aggregation_state to ensure they are not called
249
242
  aggregation_state = @subject.instance_variable_get(:@aggregation_state)
250
243
  aggregation_state.stubs(:[]=).never
251
244
 
252
- @subject.increment("foo", 1, tags: { foo: "bar" })
253
- @subject.aggregate_timing("bar", 100, tags: { foo: "bar" })
254
- @subject.gauge("baz", 100, tags: { foo: "bar" })
245
+ @subject.increment("foo", 1, ["foo:bar"], false, 1.0)
246
+ @subject.aggregate_timing("bar", 100, ["foo:bar"], false, :d, 1.0)
247
+ @subject.gauge("baz", 100, ["foo:bar"], false)
255
248
 
256
- # Verify metrics were sent immediately
257
249
  assert_equal(3, @sink.datagrams.size)
258
250
 
259
251
  counter_datagram = @sink.datagrams.find { |d| d.name == "foo" }
@@ -268,11 +260,9 @@ class AggregatorTest < Minitest::Test
268
260
  assert_equal(100, gauge_datagram.value)
269
261
  assert_equal(["foo:bar"], gauge_datagram.tags)
270
262
 
271
- # Additional metrics should also go through synchronously
272
- @subject.increment("foo", 1, tags: { foo: "bar" })
273
- @subject.aggregate_timing("bar", 200, tags: { foo: "bar" }, sample_rate: 0.5)
263
+ @subject.increment("foo", 1, ["foo:bar"], false, 1.0)
264
+ @subject.aggregate_timing("bar", 200, ["foo:bar"], false, :d, 0.5)
274
265
 
275
- # Verify new metrics were also sent immediately
276
266
  assert_equal(5, @sink.datagrams.size)
277
267
 
278
268
  counter_datagram = @sink.datagrams.select { |d| d.name == "foo" }.last
@@ -287,65 +277,52 @@ class AggregatorTest < Minitest::Test
287
277
  after_aggregation_state = @subject.instance_variable_get(:@aggregation_state)
288
278
  assert_same(after_aggregation_state, aggregation_state)
289
279
 
290
- # undo the stubbing
291
280
  @subject.unstub(:thread_healthcheck)
292
281
  end
293
282
 
294
283
  def test_recreate_thread_after_fork
295
284
  skip("#{RUBY_ENGINE} not supported for this test. Reason: fork()") if RUBY_ENGINE != "ruby"
296
- # Record initial metrics
297
- @subject.increment("foo", 1, tags: { foo: "bar" })
298
- @subject.aggregate_timing("bar", 100, tags: { foo: "bar" })
285
+ @subject.increment("foo", 1, ["foo:bar"], false, 1.0)
286
+ @subject.aggregate_timing("bar", 100, ["foo:bar"], false, :d, 1.0)
299
287
 
300
- # kill the flush thread
301
288
  @subject.instance_variable_get(:@flush_thread).kill
302
289
 
303
- # Fork the process
304
290
  pid = Process.fork do
305
- # In forked process, send more metrics
306
- @subject.increment("foo", 2, tags: { foo: "bar" })
307
- @subject.aggregate_timing("bar", 200, tags: { foo: "bar" })
291
+ @subject.increment("foo", 2, ["foo:bar"], false, 1.0)
292
+ @subject.aggregate_timing("bar", 200, ["foo:bar"], false, :d, 1.0)
308
293
  @subject.flush
309
294
 
310
295
  assert_equal(2, @sink.datagrams.size)
311
296
  exit!
312
297
  end
313
298
 
314
- # Wait for forked process to complete
315
299
  Process.wait(pid)
316
300
 
317
- # Send metrics in parent process
318
- @subject.increment("foo", 3, tags: { foo: "bar" })
319
- @subject.aggregate_timing("bar", 300, tags: { foo: "bar" })
301
+ @subject.increment("foo", 3, ["foo:bar"], false, 1.0)
302
+ @subject.aggregate_timing("bar", 300, ["foo:bar"], false, :d, 1.0)
320
303
  @subject.flush
321
304
 
322
305
  assert_equal(2, @sink.datagrams.size)
323
306
 
324
- # Verify metrics were properly aggregated in parent process
325
307
  counter_datagrams = @sink.datagrams.select { |d| d.name == "foo" }
326
308
  timing_datagrams = @sink.datagrams.select { |d| d.name == "bar" }
327
309
 
328
310
  assert_equal(1, counter_datagrams.size)
329
311
  assert_equal(1, timing_datagrams.size)
330
312
 
331
- # Aggregate despite fork
332
313
  assert_equal(4, counter_datagrams.last.value)
333
314
  assert_equal([100.0, 300.0], timing_datagrams.last.value)
334
315
  end
335
316
 
336
317
  def test_race_condition_during_forking
337
318
  skip("#{RUBY_ENGINE} not supported for this test. Reason: fork()") if RUBY_ENGINE != "ruby"
338
- # Record initial metrics
339
- @subject.increment("before_fork.count", 1, tags: { foo: "bar" })
340
- @subject.aggregate_timing("before_fork.timing", 100, tags: { foo: "bar" })
319
+ @subject.increment("before_fork.count", 1, ["foo:bar"], false, 1.0)
320
+ @subject.aggregate_timing("before_fork.timing", 100, ["foo:bar"], false, :d, 1.0)
341
321
 
342
- # Fork the process
343
322
  pid = Process.fork do
344
- # In forked process, send more metrics
345
- @subject.increment("in_child.count", 2, tags: { foo: "bar" })
346
- @subject.aggregate_timing("in_child.timing", 200, tags: { foo: "bar" })
323
+ @subject.increment("in_child.count", 2, ["foo:bar"], false, 1.0)
324
+ @subject.aggregate_timing("in_child.timing", 200, ["foo:bar"], false, :d, 1.0)
347
325
 
348
- # Simulate thread waiting for flush
349
326
  sleep(0.1)
350
327
  @subject.flush
351
328
 
@@ -353,20 +330,16 @@ class AggregatorTest < Minitest::Test
353
330
  exit!
354
331
  end
355
332
 
356
- # Call flush concurrently in parent process
357
333
  @subject.flush
358
334
 
359
- # Wait for forked process to complete
360
335
  Process.wait(pid)
361
336
 
362
- # Send metrics in parent process
363
- @subject.increment("after_fork.count", 3, tags: { foo: "bar" })
364
- @subject.aggregate_timing("after_fork.timing", 300, tags: { foo: "bar" })
337
+ @subject.increment("after_fork.count", 3, ["foo:bar"], false, 1.0)
338
+ @subject.aggregate_timing("after_fork.timing", 300, ["foo:bar"], false, :d, 1.0)
365
339
  @subject.flush
366
340
 
367
341
  assert_equal(4, @sink.datagrams.size)
368
342
 
369
- # Verify metrics were properly aggregated in parent process
370
343
  counter_datagrams = @sink.datagrams.select { |d| d.name == "before_fork.count" }
371
344
  timing_datagrams = @sink.datagrams.select { |d| d.name == "before_fork.count" }
372
345
  assert_equal(
@@ -376,7 +349,6 @@ class AggregatorTest < Minitest::Test
376
349
  )
377
350
  assert_equal(1, timing_datagrams.size)
378
351
 
379
- # After fork metrics
380
352
  counter_datagrams = @sink.datagrams.select { |d| d.name == "after_fork.count" }
381
353
  timing_datagrams = @sink.datagrams.select { |d| d.name == "after_fork.count" }
382
354
  assert_equal(1, counter_datagrams.size)
@@ -384,18 +356,16 @@ class AggregatorTest < Minitest::Test
384
356
  end
385
357
 
386
358
  def test_finalizer_flushes_pending_metrics
387
- @subject.increment("foo", 1, tags: { foo: "bar" })
388
- @subject.aggregate_timing("bar", 100, tags: { foo: "bar" })
389
- @subject.gauge("baz", 100, tags: { foo: "bar" })
390
- @subject.aggregate_timing("sampled_timing", 100, tags: { foo: "bar" }, sample_rate: 0.01)
359
+ @subject.increment("foo", 1, ["foo:bar"], false, 1.0)
360
+ @subject.aggregate_timing("bar", 100, ["foo:bar"], false, :d, 1.0)
361
+ @subject.gauge("baz", 100, ["foo:bar"], false)
362
+ @subject.aggregate_timing("sampled_timing", 100, ["foo:bar"], false, :d, 0.01)
391
363
 
392
- # Manually trigger the finalizer
393
364
  finalizer = StatsD::Instrument::Aggregator.finalize(
394
365
  @subject.instance_variable_get(:@finalizer),
395
366
  )
396
367
  finalizer.call
397
368
 
398
- # Verify that all pending metrics are sent
399
369
  assert_equal(4, @sink.datagrams.size)
400
370
 
401
371
  counter_datagram = @sink.datagrams.find { |d| d.name == "foo" }
@@ -418,13 +388,11 @@ class AggregatorTest < Minitest::Test
418
388
  def test_aggregator_finalizer_is_called_on_gc
419
389
  skip_on_jruby("JRuby's GC does not guarantee finalizers are called promptly")
420
390
 
421
- 5.times { @subject.increment("foo", 1, tags: { foo: "bar" }) }
391
+ 5.times { @subject.increment("foo", 1, ["foo:bar"], false, 1.0) }
422
392
 
423
393
  @subject.instance_variable_get(:@flush_thread)&.kill
424
- # Unbind the aggregator to allow GC to collect it.
425
394
  @subject = nil
426
395
 
427
- # We expect the finalizer to flush the aggregated metrics.
428
396
  assert_empty(@sink.datagrams)
429
397
 
430
398
  5.times do
@@ -441,10 +409,11 @@ class AggregatorTest < Minitest::Test
441
409
  end
442
410
 
443
411
  def test_aggregator_finalizer_is_called_on_gc_after_aggregation_state_move
444
- (StatsD::Instrument::Aggregator::DEFAULT_MAX_CONTEXT_SIZE + 5).times { @subject.aggregate_timing("foo", 1) }
412
+ (StatsD::Instrument::Aggregator::DEFAULT_MAX_CONTEXT_SIZE + 5).times do
413
+ @subject.aggregate_timing("foo", 1, [], false, :d, 1.0)
414
+ end
445
415
  assert_equal(1, @sink.datagrams.size)
446
416
 
447
- # Unbind the aggregator to allow GC to collect it.
448
417
  @subject = nil
449
418
  5.times do
450
419
  GC.start(full_mark: true, immediate_mark: true, immediate_sweep: true)
@@ -468,10 +437,9 @@ class AggregatorTest < Minitest::Test
468
437
 
469
438
  old_trap = Signal.trap("USR1") do
470
439
  signal_received = true
471
- # These operations should now fall back to direct writes
472
- @subject.increment("trap_counter", 1)
473
- @subject.gauge("trap_gauge", 42)
474
- @subject.aggregate_timing("trap_timing", 100)
440
+ @subject.increment("trap_counter", 1, [], false, 1.0)
441
+ @subject.gauge("trap_gauge", 42, [], false)
442
+ @subject.aggregate_timing("trap_timing", 100, [], false, :d, 1.0)
475
443
 
476
444
  metrics_sent_in_trap = @sink.datagrams.map(&:name)
477
445
  end
data/test/client_test.rb CHANGED
@@ -102,6 +102,70 @@ class ClientTest < Minitest::Test
102
102
  assert_equal(true, !datagram.nil?)
103
103
  end
104
104
 
105
+ def test_aggregation_preserves_block_timing_and_return_value
106
+ sink = StatsD::Instrument::CaptureSink.new(parent: StatsD::Instrument::NullSink.new)
107
+ client = StatsD::Instrument::Client.new(sink: sink, enable_aggregation: true)
108
+ Process.stubs(:clock_gettime).with(Process::CLOCK_MONOTONIC, :float_millisecond).returns(100.0, 125.0)
109
+
110
+ result = client.distribution("latency", tags: ["route:cart"]) { :result }
111
+
112
+ assert_equal(:result, result)
113
+ client.force_flush
114
+ datagram = sink.datagrams.find { |d| d.name == "latency" }
115
+ assert_equal(25.0, datagram.value)
116
+ ensure
117
+ client&.instance_variable_get(:@aggregator)&.instance_variable_get(:@flush_thread)&.kill
118
+ end
119
+
120
+ def test_injected_aggregator_receives_positional_calls
121
+ aggregator = mock("aggregator")
122
+ tags = ["route:cart"]
123
+ aggregator.expects(:increment).with("requests", 2, tags, false, nil)
124
+ aggregator.expects(:flush)
125
+
126
+ client = StatsD::Instrument::Client.new(
127
+ aggregator: aggregator,
128
+ sink: StatsD::Instrument::NullSink.new,
129
+ )
130
+
131
+ client.increment("requests", 2, tags: tags)
132
+ client.force_flush
133
+ end
134
+
135
+ def test_aggregation_supports_existing_compiled_metrics
136
+ sink = StatsD::Instrument::CaptureSink.new(parent: StatsD::Instrument::NullSink.new)
137
+ client = StatsD::Instrument::Client.new(sink: sink, enable_aggregation: true)
138
+ old_client = StatsD.singleton_client
139
+ StatsD.singleton_client = client
140
+ metric = Class.new(StatsD::Instrument::CompiledMetric::Counter) do
141
+ define(name: "compiled.requests")
142
+ end
143
+
144
+ metric.increment(2)
145
+ client.force_flush
146
+
147
+ datagram = sink.datagrams.find { |d| d.name == "compiled.requests" }
148
+ assert_equal(2, datagram.value)
149
+ ensure
150
+ StatsD.singleton_client = old_client
151
+ client&.instance_variable_get(:@aggregator)&.instance_variable_get(:@flush_thread)&.kill
152
+ end
153
+
154
+ def test_clone_with_options_preserves_aggregator
155
+ sink = StatsD::Instrument::CaptureSink.new(parent: StatsD::Instrument::NullSink.new)
156
+ client = StatsD::Instrument::Client.new(sink: sink, enable_aggregation: true)
157
+ clone = client.clone_with_options(prefix: "clone")
158
+
159
+ clone.increment("requests")
160
+ clone.force_flush
161
+
162
+ datagram = sink.datagrams.find { |d| d.name == "clone.requests" }
163
+ assert_equal(1, datagram.value)
164
+ ensure
165
+ client&.instance_variable_get(:@aggregator)&.instance_variable_get(:@flush_thread)&.kill
166
+ clone&.instance_variable_get(:@aggregator)&.instance_variable_get(:@flush_thread)&.kill
167
+ end
168
+
105
169
  def test_capture
106
170
  inner_datagrams = nil
107
171