statsd-instrument 3.9.9 → 3.10.0
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/.github/workflows/tests.yml +1 -1
- data/.ruby-version +1 -1
- data/CHANGELOG.md +21 -0
- data/lib/statsd/instrument/aggregator.rb +166 -45
- data/lib/statsd/instrument/client.rb +85 -4
- data/lib/statsd/instrument/compiled_metric.rb +465 -0
- data/lib/statsd/instrument/version.rb +1 -1
- data/lib/statsd/instrument.rb +2 -1
- data/test/aggregator_test.rb +158 -6
- data/test/client_test.rb +75 -4
- data/test/compiled_metric/counter_test.rb +396 -0
- data/test/compiled_metric/distribution_test.rb +503 -0
- data/test/compiled_metric/gauge_test.rb +395 -0
- data/test/compiled_metric_test.rb +447 -0
- data/test/dispatcher_stats_test.rb +6 -6
- data/test/integration_test.rb +52 -0
- metadata +12 -3
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class CompiledMetricGaugeTest < Minitest::Test
|
|
6
|
+
def setup
|
|
7
|
+
super
|
|
8
|
+
@old_client = StatsD.singleton_client
|
|
9
|
+
@sink = StatsD::Instrument::CaptureSink.new(parent: StatsD::Instrument::NullSink.new)
|
|
10
|
+
StatsD.singleton_client = StatsD::Instrument::Client.new(
|
|
11
|
+
sink: @sink,
|
|
12
|
+
prefix: "test",
|
|
13
|
+
default_tags: [],
|
|
14
|
+
enable_aggregation: false,
|
|
15
|
+
)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def teardown
|
|
19
|
+
super
|
|
20
|
+
@sink.clear
|
|
21
|
+
StatsD.singleton_client = @old_client
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def test_gauge_without_define
|
|
25
|
+
metric = Class.new(StatsD::Instrument::CompiledMetric::Gauge)
|
|
26
|
+
|
|
27
|
+
error = assert_raises(ArgumentError) do
|
|
28
|
+
metric.gauge(5)
|
|
29
|
+
end
|
|
30
|
+
assert_equal("Every CompiledMetric subclass needs to call `define` before first invocation of gauge.", error.message)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def test_define_counter_without_tags
|
|
34
|
+
metric = Class.new(StatsD::Instrument::CompiledMetric::Gauge) do
|
|
35
|
+
define(name: "foo.bar")
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
metric.gauge(5)
|
|
39
|
+
|
|
40
|
+
datagram = @sink.datagrams.first
|
|
41
|
+
assert_equal("test.foo.bar", datagram.name)
|
|
42
|
+
assert_equal(5, datagram.value)
|
|
43
|
+
assert_equal(:g, datagram.type)
|
|
44
|
+
assert_nil(datagram.tags)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def test_define_counter_with_static_tags
|
|
48
|
+
metric = Class.new(StatsD::Instrument::CompiledMetric::Gauge) do
|
|
49
|
+
define(
|
|
50
|
+
name: "foo.bar",
|
|
51
|
+
static_tags: { service: "web", env: "prod" },
|
|
52
|
+
)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
metric.gauge(5)
|
|
56
|
+
|
|
57
|
+
datagram = @sink.datagrams.first
|
|
58
|
+
assert_equal("test.foo.bar", datagram.name)
|
|
59
|
+
assert_equal(5, datagram.value)
|
|
60
|
+
assert_equal(:g, datagram.type)
|
|
61
|
+
assert_equal(["env:prod", "service:web"], datagram.tags.sort)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def test_define_counter_with_dynamic_tags
|
|
65
|
+
metric = Class.new(StatsD::Instrument::CompiledMetric::Gauge) do
|
|
66
|
+
define(
|
|
67
|
+
name: "foo.bar",
|
|
68
|
+
tags: { shop_id: Integer, user_id: Integer },
|
|
69
|
+
)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
metric.gauge(1, shop_id: 123, user_id: 456)
|
|
73
|
+
|
|
74
|
+
datagram = @sink.datagrams.first
|
|
75
|
+
assert_equal("test.foo.bar", datagram.name)
|
|
76
|
+
assert_equal(1, datagram.value)
|
|
77
|
+
assert_equal(:g, datagram.type)
|
|
78
|
+
assert_equal(["shop_id:123", "user_id:456"], datagram.tags.sort)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def test_define_counter_with_mixed_tags
|
|
82
|
+
metric = Class.new(StatsD::Instrument::CompiledMetric::Gauge) do
|
|
83
|
+
define(
|
|
84
|
+
name: "foo.bar",
|
|
85
|
+
static_tags: { service: "web" },
|
|
86
|
+
tags: { shop_id: Integer },
|
|
87
|
+
)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
metric.gauge(3, shop_id: 999)
|
|
91
|
+
|
|
92
|
+
datagram = @sink.datagrams.first
|
|
93
|
+
assert_equal("test.foo.bar", datagram.name)
|
|
94
|
+
assert_equal(3, datagram.value)
|
|
95
|
+
assert_equal(["service:web", "shop_id:999"], datagram.tags.sort)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def test_define_counter_with_string_tags
|
|
99
|
+
metric = Class.new(StatsD::Instrument::CompiledMetric::Gauge) do
|
|
100
|
+
define(
|
|
101
|
+
name: "foo.bar",
|
|
102
|
+
tags: { country: String, region: String },
|
|
103
|
+
)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
metric.gauge(2, country: "US", region: "West")
|
|
107
|
+
|
|
108
|
+
datagram = @sink.datagrams.first
|
|
109
|
+
assert_equal("test.foo.bar", datagram.name)
|
|
110
|
+
assert_equal(2, datagram.value)
|
|
111
|
+
assert_equal(["country:US", "region:West"], datagram.tags.sort)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def test_define_counter_with_float_tags
|
|
115
|
+
metric = Class.new(StatsD::Instrument::CompiledMetric::Gauge) do
|
|
116
|
+
define(
|
|
117
|
+
name: "foo.bar",
|
|
118
|
+
tags: { rate: Float },
|
|
119
|
+
)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
metric.gauge(1, rate: 1.5)
|
|
123
|
+
|
|
124
|
+
datagram = @sink.datagrams.first
|
|
125
|
+
assert_equal("test.foo.bar", datagram.name)
|
|
126
|
+
assert_equal(1, datagram.value)
|
|
127
|
+
# Float formatting uses %f which outputs full precision
|
|
128
|
+
assert_equal(1, datagram.tags.size)
|
|
129
|
+
assert_match(/^rate:1\.5/, datagram.tags.first)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def test_define_counter_no_prefix
|
|
133
|
+
metric = Class.new(StatsD::Instrument::CompiledMetric::Gauge) do
|
|
134
|
+
define(
|
|
135
|
+
name: "foo.bar",
|
|
136
|
+
no_prefix: true,
|
|
137
|
+
)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
metric.gauge(1)
|
|
141
|
+
|
|
142
|
+
datagram = @sink.datagrams.first
|
|
143
|
+
assert_equal("foo.bar", datagram.name) # No "test." prefix
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def test_multiple_gauge_same_tags
|
|
147
|
+
metric = Class.new(StatsD::Instrument::CompiledMetric::Gauge) do
|
|
148
|
+
define(
|
|
149
|
+
name: "foo.bar",
|
|
150
|
+
tags: { shop_id: Integer },
|
|
151
|
+
)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
metric.gauge(1, shop_id: 123)
|
|
155
|
+
metric.gauge(2, shop_id: 123)
|
|
156
|
+
metric.gauge(3, shop_id: 123)
|
|
157
|
+
|
|
158
|
+
assert_equal(3, @sink.datagrams.size)
|
|
159
|
+
@sink.datagrams.each do |datagram|
|
|
160
|
+
assert_equal(["shop_id:123"], datagram.tags)
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def test_multiple_increments_different_tags
|
|
165
|
+
metric = Class.new(StatsD::Instrument::CompiledMetric::Gauge) do
|
|
166
|
+
define(
|
|
167
|
+
name: "foo.bar",
|
|
168
|
+
tags: { shop_id: Integer },
|
|
169
|
+
)
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
metric.gauge(1, shop_id: 123)
|
|
173
|
+
metric.gauge(1, shop_id: 456)
|
|
174
|
+
metric.gauge(1, shop_id: 789)
|
|
175
|
+
|
|
176
|
+
assert_equal(3, @sink.datagrams.size)
|
|
177
|
+
assert_equal(["shop_id:123"], @sink.datagrams[0].tags)
|
|
178
|
+
assert_equal(["shop_id:456"], @sink.datagrams[1].tags)
|
|
179
|
+
assert_equal(["shop_id:789"], @sink.datagrams[2].tags)
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def test_gauge_includes_default_tags_from_client
|
|
183
|
+
# Create a client with default tags
|
|
184
|
+
client = StatsD::Instrument::Client.new(
|
|
185
|
+
sink: @sink,
|
|
186
|
+
prefix: "test",
|
|
187
|
+
default_tags: ["env:production", "region:us-east"],
|
|
188
|
+
enable_aggregation: false,
|
|
189
|
+
)
|
|
190
|
+
StatsD.singleton_client = client
|
|
191
|
+
|
|
192
|
+
metric = Class.new(StatsD::Instrument::CompiledMetric::Gauge) do
|
|
193
|
+
define(
|
|
194
|
+
name: "foo.bar",
|
|
195
|
+
static_tags: { service: "web" },
|
|
196
|
+
)
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
metric.gauge(1)
|
|
200
|
+
|
|
201
|
+
datagram = @sink.datagrams.first
|
|
202
|
+
assert_equal("test.foo.bar", datagram.name)
|
|
203
|
+
# Should include default tags from client + static tags
|
|
204
|
+
assert_equal(["env:production", "region:us-east", "service:web"], datagram.tags.sort)
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def test_gauge_includes_default_tags_with_no_prefix
|
|
208
|
+
# Create a client with default tags
|
|
209
|
+
client = StatsD::Instrument::Client.new(
|
|
210
|
+
sink: @sink,
|
|
211
|
+
prefix: "test",
|
|
212
|
+
default_tags: ["env:production", "region:us-east"],
|
|
213
|
+
enable_aggregation: false,
|
|
214
|
+
)
|
|
215
|
+
StatsD.singleton_client = client
|
|
216
|
+
|
|
217
|
+
metric = Class.new(StatsD::Instrument::CompiledMetric::Gauge) do
|
|
218
|
+
define(
|
|
219
|
+
name: "foo.bar",
|
|
220
|
+
static_tags: { service: "web" },
|
|
221
|
+
no_prefix: true,
|
|
222
|
+
)
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
metric.gauge(1)
|
|
226
|
+
|
|
227
|
+
datagram = @sink.datagrams.first
|
|
228
|
+
assert_equal("foo.bar", datagram.name) # No prefix
|
|
229
|
+
# Should include default tags even when no_prefix is true
|
|
230
|
+
assert_equal(["env:production", "region:us-east", "service:web"], datagram.tags.sort)
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
def test_gauge_does_not_support_blocks
|
|
234
|
+
metric = Class.new(StatsD::Instrument::CompiledMetric::Gauge) do
|
|
235
|
+
define(
|
|
236
|
+
name: "foo.bar",
|
|
237
|
+
static_tags: { service: "web" },
|
|
238
|
+
tags: { shop_id: Integer },
|
|
239
|
+
)
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
block_called = false
|
|
243
|
+
metric.gauge(42, shop_id: 999) do
|
|
244
|
+
block_called = true
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
datagram = @sink.datagrams.first
|
|
248
|
+
assert_equal("test.foo.bar", datagram.name)
|
|
249
|
+
assert_equal(42, datagram.value)
|
|
250
|
+
refute(block_called)
|
|
251
|
+
assert_equal(["service:web", "shop_id:999"], datagram.tags.sort)
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
class CompiledMetricGaugeWithAggregationTest < Minitest::Test
|
|
256
|
+
def setup
|
|
257
|
+
super
|
|
258
|
+
@old_client = StatsD.singleton_client
|
|
259
|
+
@sink = StatsD::Instrument::CaptureSink.new(parent: StatsD::Instrument::NullSink.new)
|
|
260
|
+
@aggregator = StatsD::Instrument::Aggregator.new(
|
|
261
|
+
@sink,
|
|
262
|
+
StatsD::Instrument::DatagramBuilder,
|
|
263
|
+
"test",
|
|
264
|
+
[],
|
|
265
|
+
flush_interval: 0.1,
|
|
266
|
+
)
|
|
267
|
+
client = StatsD::Instrument::Client.new(
|
|
268
|
+
sink: @sink,
|
|
269
|
+
prefix: "test",
|
|
270
|
+
default_tags: [],
|
|
271
|
+
enable_aggregation: true,
|
|
272
|
+
)
|
|
273
|
+
client.instance_variable_set(:@aggregator, @aggregator)
|
|
274
|
+
StatsD.singleton_client = client
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
def teardown
|
|
278
|
+
super
|
|
279
|
+
@sink.clear
|
|
280
|
+
StatsD.singleton_client = @old_client
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
def test_aggregates_precompiled_metrics
|
|
284
|
+
metric = Class.new(StatsD::Instrument::CompiledMetric::Gauge) do
|
|
285
|
+
define(
|
|
286
|
+
name: "foo.bar",
|
|
287
|
+
tags: { shop_id: Integer },
|
|
288
|
+
)
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
metric.gauge(1, shop_id: 123)
|
|
292
|
+
metric.gauge(2, shop_id: 123)
|
|
293
|
+
metric.gauge(3, shop_id: 123)
|
|
294
|
+
|
|
295
|
+
@aggregator.flush
|
|
296
|
+
|
|
297
|
+
assert_equal(1, @sink.datagrams.size)
|
|
298
|
+
datagram = @sink.datagrams.first
|
|
299
|
+
assert_equal(3, datagram.value)
|
|
300
|
+
assert_equal(["shop_id:123"], datagram.tags)
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
def test_aggregates_different_tag_combinations_separately
|
|
304
|
+
metric = Class.new(StatsD::Instrument::CompiledMetric::Gauge) do
|
|
305
|
+
define(
|
|
306
|
+
name: "foo.bar",
|
|
307
|
+
tags: { shop_id: Integer },
|
|
308
|
+
)
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
metric.gauge(1, shop_id: 123)
|
|
312
|
+
metric.gauge(2, shop_id: 456)
|
|
313
|
+
metric.gauge(3, shop_id: 123)
|
|
314
|
+
|
|
315
|
+
@aggregator.flush
|
|
316
|
+
|
|
317
|
+
assert_equal(2, @sink.datagrams.size)
|
|
318
|
+
|
|
319
|
+
shop_123_datagram = @sink.datagrams.find { |d| d.tags.include?("shop_id:123") }
|
|
320
|
+
shop_456_datagram = @sink.datagrams.find { |d| d.tags.include?("shop_id:456") }
|
|
321
|
+
|
|
322
|
+
assert_equal(3, shop_123_datagram.value)
|
|
323
|
+
assert_equal(2, shop_456_datagram.value)
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
def test_aggregates_static_tag_metrics
|
|
327
|
+
metric = Class.new(StatsD::Instrument::CompiledMetric::Gauge) do
|
|
328
|
+
define(
|
|
329
|
+
name: "foo.bar",
|
|
330
|
+
static_tags: { service: "web" },
|
|
331
|
+
)
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
metric.gauge(1)
|
|
335
|
+
metric.gauge(2)
|
|
336
|
+
metric.gauge(5)
|
|
337
|
+
|
|
338
|
+
@aggregator.flush
|
|
339
|
+
|
|
340
|
+
assert_equal(1, @sink.datagrams.size)
|
|
341
|
+
datagram = @sink.datagrams.first
|
|
342
|
+
assert_equal(5, datagram.value)
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
def test_sample_rate_equal_to_1_with_aggregation
|
|
346
|
+
# When aggregating with sample_rate, sampling happens before aggregation
|
|
347
|
+
# This test verifies that with sample_rate=1.0, all increments are aggregated
|
|
348
|
+
metric = Class.new(StatsD::Instrument::CompiledMetric::Gauge) do
|
|
349
|
+
define(
|
|
350
|
+
name: "foo.bar",
|
|
351
|
+
static_tags: { service: "web" },
|
|
352
|
+
sample_rate: 1.0,
|
|
353
|
+
)
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
# With sample_rate=1.0, all increments should be aggregated
|
|
357
|
+
metric.gauge(5)
|
|
358
|
+
metric.gauge(3)
|
|
359
|
+
|
|
360
|
+
@aggregator.flush
|
|
361
|
+
|
|
362
|
+
assert_equal(1, @sink.datagrams.size)
|
|
363
|
+
datagram = @sink.datagrams.first
|
|
364
|
+
assert_equal("test.foo.bar", datagram.name)
|
|
365
|
+
assert_equal(3, datagram.value)
|
|
366
|
+
# Sample rate should be 1.0 when aggregating
|
|
367
|
+
assert_equal(1.0, datagram.sample_rate)
|
|
368
|
+
refute_includes(datagram.source, "|@")
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
def test_sample_rate_applied_with_aggregation
|
|
372
|
+
# When aggregating with sample_rate, sampling happens before aggregation
|
|
373
|
+
# This test verifies that with sample_rate=0.5, all gauges are aggregated
|
|
374
|
+
metric = Class.new(StatsD::Instrument::CompiledMetric::Gauge) do
|
|
375
|
+
define(
|
|
376
|
+
name: "foo.bar",
|
|
377
|
+
static_tags: { service: "web" },
|
|
378
|
+
sample_rate: 0.5,
|
|
379
|
+
)
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
metric.gauge(5)
|
|
383
|
+
metric.gauge(3)
|
|
384
|
+
|
|
385
|
+
@aggregator.flush
|
|
386
|
+
|
|
387
|
+
assert_equal(1, @sink.datagrams.size)
|
|
388
|
+
datagram = @sink.datagrams.first
|
|
389
|
+
assert_equal("test.foo.bar", datagram.name)
|
|
390
|
+
assert_equal(3, datagram.value) # 5 + 3
|
|
391
|
+
# Sample rate should be 1.0 when aggregating
|
|
392
|
+
assert_equal(0.5, datagram.sample_rate)
|
|
393
|
+
assert_includes(datagram.source, "|@")
|
|
394
|
+
end
|
|
395
|
+
end
|