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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +5 -0
- data/lib/statsd/instrument/aggregator.rb +3 -3
- data/lib/statsd/instrument/client.rb +38 -24
- data/lib/statsd/instrument/compiled_metric.rb +9 -9
- data/lib/statsd/instrument/datagram.rb +3 -3
- data/lib/statsd/instrument/datagram_builder.rb +12 -12
- data/lib/statsd/instrument/dogstatsd_datagram.rb +11 -11
- data/lib/statsd/instrument/dogstatsd_datagram_builder.rb +1 -1
- data/lib/statsd/instrument/sanitization.rb +34 -0
- data/lib/statsd/instrument/version.rb +1 -1
- data/lib/statsd/instrument.rb +1 -0
- data/test/aggregator_test.rb +68 -100
- data/test/client_test.rb +64 -0
- data/test/newline_normalization_test.rb +262 -0
- data/test/rubocop/singleton_configuration_test.rb +1 -3
- data/test/sanitization_test.rb +49 -0
- metadata +7 -2
data/test/aggregator_test.rb
CHANGED
|
@@ -36,8 +36,8 @@ class AggregatorTest < Minitest::Test
|
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
def test_increment_simple
|
|
39
|
-
@subject.increment("foo", 1,
|
|
40
|
-
@subject.increment("foo", 1,
|
|
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
|
-
|
|
52
|
-
@subject.increment("counter.sampled",
|
|
53
|
-
@subject.increment("counter.
|
|
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
|
-
|
|
72
|
-
@subject.increment("counter",
|
|
73
|
-
@subject.increment("counter",
|
|
74
|
-
@subject.increment("counter",
|
|
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,
|
|
89
|
-
@subject.aggregate_timing("foo", 100,
|
|
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,
|
|
100
|
-
@subject.aggregate_timing("timing.sampled", 80.0,
|
|
101
|
-
@subject.aggregate_timing("timing.unsampled", 60.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,
|
|
118
|
-
@subject.aggregate_timing("foo_ms", 100,
|
|
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,
|
|
121
|
-
@subject.aggregate_timing("foo_d", 120,
|
|
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,
|
|
134
|
-
@subject.gauge("foo", 100,
|
|
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,
|
|
145
|
-
@subject.increment("foo", 1,
|
|
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,
|
|
153
|
-
@subject.increment("foo", 1,
|
|
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,
|
|
165
|
-
@subject.increment("bar", 1,
|
|
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,
|
|
174
|
-
@subject.increment("foo", 2,
|
|
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,
|
|
182
|
-
@subject.aggregate_timing("test_counter", 100,
|
|
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,
|
|
185
|
-
@subject.increment("test_gauge", 1,
|
|
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,
|
|
188
|
-
@subject.gauge("test_timing", 100,
|
|
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,
|
|
206
|
-
aggregator.increment("foo", 1,
|
|
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,
|
|
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,
|
|
225
|
-
aggregator.increment("bar", 1,
|
|
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,
|
|
253
|
-
@subject.aggregate_timing("bar", 100,
|
|
254
|
-
@subject.gauge("baz", 100,
|
|
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
|
-
|
|
272
|
-
@subject.
|
|
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
|
-
|
|
297
|
-
@subject.
|
|
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
|
-
|
|
306
|
-
@subject.
|
|
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
|
-
|
|
318
|
-
@subject.
|
|
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
|
-
|
|
339
|
-
@subject.
|
|
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
|
-
|
|
345
|
-
@subject.
|
|
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
|
-
|
|
363
|
-
@subject.
|
|
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,
|
|
388
|
-
@subject.aggregate_timing("bar", 100,
|
|
389
|
-
@subject.gauge("baz", 100,
|
|
390
|
-
@subject.aggregate_timing("sampled_timing", 100,
|
|
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,
|
|
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
|
|
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
|
-
|
|
472
|
-
@subject.
|
|
473
|
-
@subject.
|
|
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
|
|