statsd-instrument 2.3.2 → 2.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/CODEOWNERS +1 -0
- data/.github/workflows/benchmark.yml +32 -0
- data/.github/workflows/ci.yml +47 -0
- data/.gitignore +1 -0
- data/.rubocop-https---shopify-github-io-ruby-style-guide-rubocop-yml +1027 -0
- data/.rubocop.yml +50 -0
- data/.yardopts +5 -0
- data/CHANGELOG.md +288 -2
- data/CONTRIBUTING.md +28 -6
- data/Gemfile +5 -0
- data/README.md +54 -46
- data/Rakefile +4 -2
- data/benchmark/README.md +29 -0
- data/benchmark/datagram-client +41 -0
- data/benchmark/send-metrics-to-dev-null-log +47 -0
- data/benchmark/send-metrics-to-local-udp-receiver +57 -0
- data/lib/statsd/instrument/assertions.rb +179 -30
- data/lib/statsd/instrument/backend.rb +3 -2
- data/lib/statsd/instrument/backends/capture_backend.rb +4 -1
- data/lib/statsd/instrument/backends/logger_backend.rb +3 -3
- data/lib/statsd/instrument/backends/null_backend.rb +2 -0
- data/lib/statsd/instrument/backends/udp_backend.rb +39 -45
- data/lib/statsd/instrument/capture_sink.rb +27 -0
- data/lib/statsd/instrument/client.rb +313 -0
- data/lib/statsd/instrument/datagram.rb +75 -0
- data/lib/statsd/instrument/datagram_builder.rb +101 -0
- data/lib/statsd/instrument/dogstatsd_datagram_builder.rb +71 -0
- data/lib/statsd/instrument/environment.rb +108 -29
- data/lib/statsd/instrument/helpers.rb +16 -8
- data/lib/statsd/instrument/log_sink.rb +24 -0
- data/lib/statsd/instrument/matchers.rb +14 -11
- data/lib/statsd/instrument/metric.rb +72 -45
- data/lib/statsd/instrument/metric_expectation.rb +32 -18
- data/lib/statsd/instrument/null_sink.rb +13 -0
- data/lib/statsd/instrument/railtie.rb +2 -1
- data/lib/statsd/instrument/rubocop/measure_as_dist_argument.rb +39 -0
- data/lib/statsd/instrument/rubocop/metaprogramming_positional_arguments.rb +42 -0
- data/lib/statsd/instrument/rubocop/metric_prefix_argument.rb +37 -0
- data/lib/statsd/instrument/rubocop/metric_return_value.rb +32 -0
- data/lib/statsd/instrument/rubocop/metric_value_keyword_argument.rb +36 -0
- data/lib/statsd/instrument/rubocop/positional_arguments.rb +99 -0
- data/lib/statsd/instrument/rubocop/splat_arguments.rb +31 -0
- data/lib/statsd/instrument/rubocop.rb +64 -0
- data/lib/statsd/instrument/statsd_datagram_builder.rb +14 -0
- data/lib/statsd/instrument/strict.rb +235 -0
- data/lib/statsd/instrument/udp_sink.rb +62 -0
- data/lib/statsd/instrument/version.rb +3 -1
- data/lib/statsd/instrument.rb +340 -163
- data/lib/statsd-instrument.rb +2 -0
- data/statsd-instrument.gemspec +13 -10
- data/test/assertions_test.rb +167 -156
- data/test/benchmark/clock_gettime.rb +27 -0
- data/test/benchmark/default_tags.rb +47 -0
- data/test/benchmark/metrics.rb +9 -8
- data/test/benchmark/tags.rb +5 -3
- data/test/capture_backend_test.rb +4 -2
- data/test/capture_sink_test.rb +44 -0
- data/test/client_test.rb +164 -0
- data/test/compatibility/dogstatsd_datagram_compatibility_test.rb +162 -0
- data/test/datagram_builder_test.rb +120 -0
- data/test/deprecations_test.rb +132 -0
- data/test/dogstatsd_datagram_builder_test.rb +32 -0
- data/test/environment_test.rb +75 -8
- data/test/helpers/rubocop_helper.rb +47 -0
- data/test/helpers_test.rb +2 -1
- data/test/integration_test.rb +31 -7
- data/test/log_sink_test.rb +37 -0
- data/test/logger_backend_test.rb +10 -8
- data/test/matchers_test.rb +42 -28
- data/test/metric_test.rb +18 -22
- data/test/null_sink_test.rb +13 -0
- data/test/rubocop/measure_as_dist_argument_test.rb +44 -0
- data/test/rubocop/metaprogramming_positional_arguments_test.rb +58 -0
- data/test/rubocop/metric_prefix_argument_test.rb +38 -0
- data/test/rubocop/metric_return_value_test.rb +78 -0
- data/test/rubocop/metric_value_keyword_argument_test.rb +39 -0
- data/test/rubocop/positional_arguments_test.rb +110 -0
- data/test/rubocop/splat_arguments_test.rb +27 -0
- data/test/statsd_datagram_builder_test.rb +22 -0
- data/test/statsd_instrumentation_test.rb +109 -100
- data/test/statsd_test.rb +113 -79
- data/test/test_helper.rb +12 -1
- data/test/udp_backend_test.rb +38 -36
- data/test/udp_sink_test.rb +85 -0
- metadata +85 -5
- data/.travis.yml +0 -12
data/test/statsd_test.rb
CHANGED
@@ -1,166 +1,177 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'test_helper'
|
2
4
|
|
3
5
|
class StatsDTest < Minitest::Test
|
4
6
|
include StatsD::Instrument::Assertions
|
5
7
|
|
8
|
+
def teardown
|
9
|
+
StatsD.default_tags = nil
|
10
|
+
end
|
11
|
+
|
6
12
|
def test_statsd_passed_collections_to_backend
|
7
13
|
StatsD.backend.expects(:collect_metric).with(instance_of(StatsD::Instrument::Metric))
|
8
14
|
StatsD.increment('test')
|
9
15
|
end
|
10
16
|
|
11
17
|
def test_statsd_measure_with_explicit_value
|
12
|
-
|
13
|
-
metric = capture_statsd_call { result = StatsD.measure('values.foobar', 42) }
|
14
|
-
assert_equal metric, result
|
18
|
+
metric = capture_statsd_call { StatsD.measure('values.foobar', 42) }
|
15
19
|
assert_equal 'values.foobar', metric.name
|
16
20
|
assert_equal 42, metric.value
|
17
21
|
assert_equal :ms, metric.type
|
18
22
|
end
|
19
23
|
|
20
|
-
def test_statsd_measure_with_explicit_value_and_distribution_override
|
21
|
-
metric = capture_statsd_call { result = StatsD.measure('values.foobar', 42, as_dist: true) }
|
22
|
-
assert_equal :d, metric.type
|
23
|
-
end
|
24
|
-
|
25
|
-
def test_statsd_measure_with_explicit_value_as_keyword_argument
|
26
|
-
result = nil
|
27
|
-
metric = capture_statsd_call { result = StatsD.measure('values.foobar', value: 42) }
|
28
|
-
assert_equal metric, result
|
29
|
-
assert_equal 'values.foobar', metric.name
|
30
|
-
assert_equal 42, metric.value
|
31
|
-
assert_equal :ms, metric.type
|
32
|
-
end
|
33
|
-
|
34
|
-
def test_statsd_measure_with_explicit_value_keyword_and_distribution_override
|
35
|
-
metric = capture_statsd_call { result = StatsD.measure('values.foobar', value: 42, as_dist: true) }
|
36
|
-
assert_equal :d, metric.type
|
37
|
-
end
|
38
|
-
|
39
24
|
def test_statsd_measure_without_value_or_block
|
40
25
|
assert_raises(ArgumentError) { StatsD.measure('values.foobar', tags: 123) }
|
41
26
|
end
|
42
27
|
|
43
28
|
def test_statsd_measure_with_explicit_value_and_sample_rate
|
44
|
-
metric = capture_statsd_call { StatsD.measure('values.foobar', 42, :
|
29
|
+
metric = capture_statsd_call { StatsD.measure('values.foobar', 42, sample_rate: 0.1) }
|
45
30
|
assert_equal 0.1, metric.sample_rate
|
46
31
|
end
|
47
32
|
|
48
33
|
def test_statsd_measure_with_benchmarked_block_duration
|
49
|
-
|
34
|
+
Process.stubs(:clock_gettime).returns(5.0, 5.0 + 1.12)
|
50
35
|
metric = capture_statsd_call do
|
51
36
|
StatsD.measure('values.foobar') { 'foo' }
|
52
37
|
end
|
53
38
|
assert_equal 1120.0, metric.value
|
54
39
|
end
|
55
40
|
|
56
|
-
def test_statsd_measure_use_distribution_override_for_a_block
|
57
|
-
metric = capture_statsd_call do
|
58
|
-
StatsD.measure('values.foobar', as_dist: true) { 'foo' }
|
59
|
-
end
|
60
|
-
assert_equal :d, metric.type
|
61
|
-
end
|
62
|
-
|
63
41
|
def test_statsd_measure_returns_return_value_of_block
|
64
42
|
return_value = StatsD.measure('values.foobar') { 'sarah' }
|
65
43
|
assert_equal 'sarah', return_value
|
66
44
|
end
|
67
45
|
|
68
|
-
def
|
69
|
-
|
70
|
-
|
46
|
+
def test_statsd_measure_with_return_in_block_still_captures
|
47
|
+
Process.stubs(:clock_gettime).returns(5.0, 6.12)
|
48
|
+
result = nil
|
49
|
+
metric = capture_statsd_call do
|
50
|
+
lambda = -> do
|
51
|
+
StatsD.measure('values.foobar') { return 'from lambda' }
|
52
|
+
end
|
53
|
+
|
54
|
+
result = lambda.call
|
55
|
+
end
|
56
|
+
|
57
|
+
assert_equal 'from lambda', result
|
58
|
+
assert_equal 1120.0, metric.value
|
71
59
|
end
|
72
60
|
|
73
|
-
def
|
61
|
+
def test_statsd_measure_with_exception_in_block_still_captures
|
62
|
+
Process.stubs(:clock_gettime).returns(5.0, 6.12)
|
74
63
|
result = nil
|
75
|
-
metric = capture_statsd_call
|
76
|
-
|
64
|
+
metric = capture_statsd_call do
|
65
|
+
lambda = -> do
|
66
|
+
StatsD.measure('values.foobar') { raise 'from lambda' }
|
67
|
+
end
|
68
|
+
|
69
|
+
begin
|
70
|
+
result = lambda.call
|
71
|
+
rescue # rubocop:disable Lint/HandleExceptions:
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
assert_nil result
|
76
|
+
assert_equal 1120.0, metric.value
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_statsd_increment
|
80
|
+
metric = capture_statsd_call { StatsD.increment('values.foobar', 3) }
|
77
81
|
assert_equal :c, metric.type
|
78
82
|
assert_equal 'values.foobar', metric.name
|
79
83
|
assert_equal 3, metric.value
|
80
84
|
end
|
81
85
|
|
82
86
|
def test_statsd_increment_with_hash_argument
|
83
|
-
metric = capture_statsd_call { StatsD.increment('values.foobar', :
|
87
|
+
metric = capture_statsd_call { StatsD.increment('values.foobar', tags: ['test']) }
|
84
88
|
assert_equal StatsD.default_sample_rate, metric.sample_rate
|
85
89
|
assert_equal ['test'], metric.tags
|
86
90
|
assert_equal 1, metric.value
|
87
91
|
end
|
88
92
|
|
89
|
-
def test_statsd_increment_with_value_as_keyword_argument
|
90
|
-
metric = capture_statsd_call { StatsD.increment('values.foobar', :value => 2) }
|
91
|
-
assert_equal StatsD.default_sample_rate, metric.sample_rate
|
92
|
-
assert_equal 2, metric.value
|
93
|
-
end
|
94
|
-
|
95
|
-
def test_statsd_increment_with_multiple_arguments
|
96
|
-
metric = capture_statsd_call { StatsD.increment('values.foobar', 12, nil, ['test']) }
|
97
|
-
assert_equal StatsD.default_sample_rate, metric.sample_rate
|
98
|
-
assert_equal ['test'], metric.tags
|
99
|
-
assert_equal 12, metric.value
|
100
|
-
end
|
101
|
-
|
102
93
|
def test_statsd_gauge
|
103
|
-
|
104
|
-
metric = capture_statsd_call { result = StatsD.gauge('values.foobar', 12) }
|
105
|
-
assert_equal metric, result
|
94
|
+
metric = capture_statsd_call { StatsD.gauge('values.foobar', 12) }
|
106
95
|
assert_equal :g, metric.type
|
107
96
|
assert_equal 'values.foobar', metric.name
|
108
97
|
assert_equal 12, metric.value
|
109
98
|
end
|
110
99
|
|
111
|
-
def test_statsd_gauge_with_keyword_argument
|
112
|
-
result = nil
|
113
|
-
metric = capture_statsd_call { result = StatsD.gauge('values.foobar', value: 13) }
|
114
|
-
assert_equal metric, result
|
115
|
-
assert_equal :g, metric.type
|
116
|
-
assert_equal 'values.foobar', metric.name
|
117
|
-
assert_equal 13, metric.value
|
118
|
-
end
|
119
|
-
|
120
100
|
def test_statsd_gauge_without_value
|
121
101
|
assert_raises(ArgumentError) { StatsD.gauge('values.foobar', tags: 123) }
|
122
102
|
end
|
123
103
|
|
124
104
|
def test_statsd_set
|
125
|
-
|
126
|
-
metric = capture_statsd_call { result = StatsD.set('values.foobar', 'unique_identifier') }
|
127
|
-
assert_equal metric, result
|
105
|
+
metric = capture_statsd_call { StatsD.set('values.foobar', 'unique_identifier') }
|
128
106
|
assert_equal :s, metric.type
|
129
107
|
assert_equal 'values.foobar', metric.name
|
130
108
|
assert_equal 'unique_identifier', metric.value
|
131
109
|
end
|
132
110
|
|
133
111
|
def test_statsd_histogram
|
134
|
-
|
135
|
-
metric = capture_statsd_call { result = StatsD.histogram('values.foobar', 42) }
|
136
|
-
assert_equal metric, result
|
112
|
+
metric = capture_statsd_call { StatsD.histogram('values.foobar', 42) }
|
137
113
|
assert_equal :h, metric.type
|
138
114
|
assert_equal 'values.foobar', metric.name
|
139
115
|
assert_equal 42, metric.value
|
140
116
|
end
|
141
117
|
|
142
118
|
def test_statsd_distribution
|
143
|
-
|
144
|
-
metric = capture_statsd_call { result = StatsD.distribution('values.foobar', 42) }
|
145
|
-
assert_equal metric, result
|
119
|
+
metric = capture_statsd_call { StatsD.distribution('values.foobar', 42) }
|
146
120
|
assert_equal :d, metric.type
|
147
121
|
assert_equal 'values.foobar', metric.name
|
148
122
|
assert_equal 42, metric.value
|
149
123
|
end
|
150
124
|
|
151
125
|
def test_statsd_distribution_with_benchmarked_block_duration
|
152
|
-
|
126
|
+
Process.stubs(:clock_gettime).returns(5.0, 5.0 + 1.12)
|
153
127
|
metric = capture_statsd_call do
|
154
|
-
StatsD.distribution('values.foobar') { 'foo' }
|
128
|
+
result = StatsD.distribution('values.foobar') { 'foo' }
|
129
|
+
assert_equal 'foo', result
|
155
130
|
end
|
156
131
|
assert_equal :d, metric.type
|
157
132
|
assert_equal 1120.0, metric.value
|
158
133
|
end
|
159
134
|
|
135
|
+
def test_statsd_distribution_with_return_in_block_still_captures
|
136
|
+
Process.stubs(:clock_gettime).returns(5.0, 5.0 + 1.12)
|
137
|
+
result = nil
|
138
|
+
metric = capture_statsd_call do
|
139
|
+
lambda = -> do
|
140
|
+
StatsD.distribution('values.foobar') { return 'from lambda' }
|
141
|
+
flunk("This code should not be reached")
|
142
|
+
end
|
143
|
+
|
144
|
+
result = lambda.call
|
145
|
+
end
|
146
|
+
|
147
|
+
assert_equal 'from lambda', result
|
148
|
+
assert_equal :d, metric.type
|
149
|
+
assert_equal 1120.0, metric.value
|
150
|
+
end
|
151
|
+
|
152
|
+
def test_statsd_distribution_with_exception_in_block_still_captures
|
153
|
+
Process.stubs(:clock_gettime).returns(5.0, 5.0 + 1.12)
|
154
|
+
result = nil
|
155
|
+
metric = capture_statsd_call do
|
156
|
+
lambda = -> do
|
157
|
+
StatsD.distribution('values.foobar') { raise 'from lambda' }
|
158
|
+
end
|
159
|
+
|
160
|
+
begin
|
161
|
+
result = lambda.call
|
162
|
+
rescue # rubocop:disable Lint/HandleExceptions
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
assert_nil result
|
167
|
+
assert_equal :d, metric.type
|
168
|
+
assert_equal 1120.0, metric.value
|
169
|
+
end
|
170
|
+
|
160
171
|
def test_statsd_distribution_with_block_and_options
|
161
|
-
|
172
|
+
Process.stubs(:clock_gettime).returns(5.0, 5.0 + 1.12)
|
162
173
|
metric = capture_statsd_call do
|
163
|
-
StatsD.distribution('values.foobar', :
|
174
|
+
StatsD.distribution('values.foobar', tags: ['test'], sample_rate: 0.9) { 'foo' }
|
164
175
|
end
|
165
176
|
assert_equal 1120.0, metric.value
|
166
177
|
assert_equal 'values.foobar', metric.name
|
@@ -179,14 +190,37 @@ class StatsDTest < Minitest::Test
|
|
179
190
|
end
|
180
191
|
|
181
192
|
def test_statsd_key_value
|
182
|
-
|
183
|
-
metric = capture_statsd_call { result = StatsD.key_value('values.foobar', 42) }
|
184
|
-
assert_equal metric, result
|
193
|
+
metric = capture_statsd_call { StatsD.key_value('values.foobar', 42) }
|
185
194
|
assert_equal :kv, metric.type
|
186
195
|
assert_equal 'values.foobar', metric.name
|
187
196
|
assert_equal 42, metric.value
|
188
197
|
end
|
189
198
|
|
199
|
+
def test_statsd_durarion_returns_time_in_seconds
|
200
|
+
duration = StatsD::Instrument.duration {}
|
201
|
+
assert_kind_of Float, duration
|
202
|
+
end
|
203
|
+
|
204
|
+
def test_statsd_durarion_does_not_swallow_exceptions
|
205
|
+
assert_raises(RuntimeError) do
|
206
|
+
StatsD::Instrument.duration { raise "Foo" }
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def test_statsd_default_tags_get_normalized
|
211
|
+
StatsD.default_tags = { first_tag: 'first_value', second_tag: 'second_value' }
|
212
|
+
assert_equal ['first_tag:first_value', 'second_tag:second_value'], StatsD.default_tags
|
213
|
+
end
|
214
|
+
|
215
|
+
def test_name_prefix
|
216
|
+
StatsD.stubs(:prefix).returns('prefix')
|
217
|
+
m = capture_statsd_call { StatsD.increment('counter') }
|
218
|
+
assert_equal 'prefix.counter', m.name
|
219
|
+
|
220
|
+
m = capture_statsd_call { StatsD.increment('counter', no_prefix: true) }
|
221
|
+
assert_equal 'counter', m.name
|
222
|
+
end
|
223
|
+
|
190
224
|
protected
|
191
225
|
|
192
226
|
def capture_statsd_call(&block)
|
data/test/test_helper.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
ENV['ENV'] = 'test'
|
2
4
|
|
3
5
|
require 'minitest/autorun'
|
@@ -7,4 +9,13 @@ require 'set'
|
|
7
9
|
require 'logger'
|
8
10
|
require 'statsd-instrument'
|
9
11
|
|
10
|
-
|
12
|
+
require_relative 'helpers/rubocop_helper'
|
13
|
+
|
14
|
+
module StatsD::Instrument
|
15
|
+
def self.strict_mode_enabled?
|
16
|
+
StatsD::Instrument.const_defined?(:Strict) &&
|
17
|
+
StatsD.singleton_class.ancestors.include?(StatsD::Instrument::Strict)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
StatsD.logger = Logger.new(File::NULL)
|
data/test/udp_backend_test.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'test_helper'
|
2
4
|
|
3
5
|
class UDPBackendTest < Minitest::Test
|
@@ -76,7 +78,7 @@ class UDPBackendTest < Minitest::Test
|
|
76
78
|
StatsD.histogram('fooh', 42.4)
|
77
79
|
end
|
78
80
|
|
79
|
-
|
81
|
+
def test_distribution_syntax_on_datadog
|
80
82
|
@backend.implementation = :datadog
|
81
83
|
@backend.expects(:write_packet).with('fooh:42.4|d')
|
82
84
|
StatsD.distribution('fooh', 42.4)
|
@@ -84,20 +86,25 @@ class UDPBackendTest < Minitest::Test
|
|
84
86
|
|
85
87
|
def test_event_on_datadog
|
86
88
|
@backend.implementation = :datadog
|
87
|
-
@backend.expects(:write_packet).with('_e{4,3}:fooh|baz|h:localhost
|
88
|
-
StatsD.event('fooh', 'baz', hostname: 'localhost
|
89
|
+
@backend.expects(:write_packet).with('_e{4,3}:fooh|baz|h:localhost|#foo')
|
90
|
+
StatsD.event('fooh', 'baz', hostname: 'localhost', tags: ["foo"])
|
89
91
|
end
|
90
92
|
|
91
93
|
def test_event_on_datadog_escapes_newlines
|
92
94
|
@backend.implementation = :datadog
|
93
|
-
@backend.expects(:write_packet).with(
|
94
|
-
StatsD.event(
|
95
|
+
@backend.expects(:write_packet).with("_e{8,5}:fooh\\n\\n|baz\\n")
|
96
|
+
StatsD.event("fooh\n\n", "baz\n")
|
95
97
|
end
|
96
98
|
|
97
99
|
def test_event_on_datadog_ignores_invalid_metadata
|
98
100
|
@backend.implementation = :datadog
|
99
|
-
|
100
|
-
|
101
|
+
if StatsD::Instrument.strict_mode_enabled?
|
102
|
+
assert_raises(ArgumentError) { StatsD.event('fooh', 'baz', sample_rate: 0.01) }
|
103
|
+
assert_raises(ArgumentError) { StatsD.event('fooh', 'baz', unsupported: 'foo') }
|
104
|
+
else
|
105
|
+
@backend.expects(:write_packet).with('_e{4,3}:fooh|baz')
|
106
|
+
StatsD.event('fooh', 'baz', sample_rate: 0.01, i_am_not_supported: 'not-supported')
|
107
|
+
end
|
101
108
|
end
|
102
109
|
|
103
110
|
def test_event_warns_when_not_using_datadog
|
@@ -109,14 +116,26 @@ class UDPBackendTest < Minitest::Test
|
|
109
116
|
|
110
117
|
def test_service_check_on_datadog
|
111
118
|
@backend.implementation = :datadog
|
112
|
-
@backend.expects(:write_packet).with('_sc|fooh|
|
113
|
-
StatsD.service_check('fooh',
|
119
|
+
@backend.expects(:write_packet).with('_sc|fooh|0|h:localhost|#foo')
|
120
|
+
StatsD.service_check('fooh', 0, hostname: 'localhost', tags: ["foo"])
|
114
121
|
end
|
115
122
|
|
116
123
|
def test_service_check_on_datadog_ignores_invalid_metadata
|
117
124
|
@backend.implementation = :datadog
|
118
|
-
|
119
|
-
|
125
|
+
if StatsD::Instrument.strict_mode_enabled?
|
126
|
+
assert_raises(ArgumentError) { StatsD.service_check('fooh', "warning", sample_rate: 0.01) }
|
127
|
+
assert_raises(ArgumentError) { StatsD.service_check('fooh', "warning", unsupported: 'foo') }
|
128
|
+
else
|
129
|
+
@backend.expects(:write_packet).with('_sc|fooh|1')
|
130
|
+
StatsD.service_check('fooh', "warning", sample_rate: 0.01, i_am_not_supported: 'not-supported')
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_service_check_on_datadog_will_append_message_as_final_metadata_field
|
135
|
+
@backend.implementation = :datadog
|
136
|
+
@backend.expects(:write_packet).with('_sc|fooh|0|d:1230768000|#quc|m:Everything OK')
|
137
|
+
StatsD.service_check('fooh', :ok, message: "Everything OK",
|
138
|
+
timestamp: Time.parse('2009-01-01T00:00:00Z'), tags: ['quc'])
|
120
139
|
end
|
121
140
|
|
122
141
|
def test_service_check_warns_when_not_using_datadog
|
@@ -146,11 +165,19 @@ class UDPBackendTest < Minitest::Test
|
|
146
165
|
StatsD.key_value('fooy', 42)
|
147
166
|
end
|
148
167
|
|
168
|
+
# For key_value metrics (only supported by statsite), the sample rate
|
169
|
+
# part of the datagram format is (ab)used to be set to a timestamp instead.
|
170
|
+
# Changing that to `sample_rate: timestamp` does not make sense, so we
|
171
|
+
# disable the rubocop rule for positional arguments for now,
|
172
|
+
# until we figure out how we want to handle this.
|
173
|
+
|
174
|
+
# rubocop:disable StatsD/PositionalArguments
|
149
175
|
def test_supports_key_value_with_timestamp_on_statsite
|
150
176
|
@backend.implementation = :statsite
|
151
177
|
@backend.expects(:write_packet).with("fooy:42|kv|@123456\n")
|
152
178
|
StatsD.key_value('fooy', 42, 123456)
|
153
179
|
end
|
180
|
+
# rubocop:enable StatsD/PositionalArguments
|
154
181
|
|
155
182
|
def test_warn_when_using_key_value_and_not_on_statsite
|
156
183
|
@backend.implementation = :other
|
@@ -183,31 +210,6 @@ class UDPBackendTest < Minitest::Test
|
|
183
210
|
StatsD.increment('fail')
|
184
211
|
end
|
185
212
|
|
186
|
-
def test_synchronize_in_exit_handler_handles_thread_error_and_exits_cleanly
|
187
|
-
pid = fork do
|
188
|
-
Signal.trap('TERM') do
|
189
|
-
$sent_packet = false
|
190
|
-
|
191
|
-
class << @backend.socket
|
192
|
-
def send(command, *args)
|
193
|
-
$sent_packet = true if command == 'exiting:1|c'
|
194
|
-
command.length
|
195
|
-
end
|
196
|
-
end
|
197
|
-
|
198
|
-
StatsD.increment('exiting')
|
199
|
-
Process.exit!($sent_packet)
|
200
|
-
end
|
201
|
-
|
202
|
-
sleep 100
|
203
|
-
end
|
204
|
-
|
205
|
-
Process.kill('TERM', pid)
|
206
|
-
Process.waitpid(pid)
|
207
|
-
|
208
|
-
assert $?.success?, 'socket did not write on exit'
|
209
|
-
end
|
210
|
-
|
211
213
|
def test_socket_error_should_invalidate_socket
|
212
214
|
seq = sequence('fail_then_succeed')
|
213
215
|
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
require 'statsd/instrument/client'
|
6
|
+
|
7
|
+
class UDPSinktest < Minitest::Test
|
8
|
+
def setup
|
9
|
+
@receiver = UDPSocket.new
|
10
|
+
@receiver.bind('localhost', 0)
|
11
|
+
@host = @receiver.addr[2]
|
12
|
+
@port = @receiver.addr[1]
|
13
|
+
end
|
14
|
+
|
15
|
+
def teardown
|
16
|
+
@receiver.close
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_udp_sink_sends_data_over_udp
|
20
|
+
udp_sink = StatsD::Instrument::UDPSink.new(@host, @port)
|
21
|
+
udp_sink << 'foo:1|c'
|
22
|
+
|
23
|
+
datagram, _source = @receiver.recvfrom(100)
|
24
|
+
assert_equal 'foo:1|c', datagram
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_sample?
|
28
|
+
udp_sink = StatsD::Instrument::UDPSink.new(@host, @port)
|
29
|
+
assert udp_sink.sample?(1)
|
30
|
+
refute udp_sink.sample?(0)
|
31
|
+
|
32
|
+
udp_sink.stubs(:rand).returns(0.3)
|
33
|
+
assert udp_sink.sample?(0.5)
|
34
|
+
|
35
|
+
udp_sink.stubs(:rand).returns(0.7)
|
36
|
+
refute udp_sink.sample?(0.5)
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_parallelism
|
40
|
+
udp_sink = StatsD::Instrument::UDPSink.new(@host, @port)
|
41
|
+
50.times { |i| Thread.new { udp_sink << "foo:#{i}|c" << "bar:#{i}|c" } }
|
42
|
+
datagrams = []
|
43
|
+
100.times do
|
44
|
+
datagram, _source = @receiver.recvfrom(100)
|
45
|
+
datagrams << datagram
|
46
|
+
end
|
47
|
+
|
48
|
+
assert_equal 100, datagrams.size
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_socket_error_should_invalidate_socket
|
52
|
+
UDPSocket.stubs(:new).returns(socket = mock('socket'))
|
53
|
+
|
54
|
+
seq = sequence('connect_fail_connect_succeed')
|
55
|
+
socket.expects(:connect).with('localhost', 8125).in_sequence(seq)
|
56
|
+
socket.expects(:send).raises(Errno::EDESTADDRREQ).in_sequence(seq)
|
57
|
+
socket.expects(:connect).with('localhost', 8125).in_sequence(seq)
|
58
|
+
socket.expects(:send).returns(1).in_sequence(seq)
|
59
|
+
|
60
|
+
udp_sink = StatsD::Instrument::UDPSink.new('localhost', 8125)
|
61
|
+
udp_sink << 'foo:1|c'
|
62
|
+
udp_sink << 'bar:1|c'
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_sends_datagram_in_signal_handler
|
66
|
+
udp_sink = StatsD::Instrument::UDPSink.new(@host, @port)
|
67
|
+
pid = fork do
|
68
|
+
Signal.trap('TERM') do
|
69
|
+
udp_sink << "exiting:1|c"
|
70
|
+
Process.exit!(0)
|
71
|
+
end
|
72
|
+
|
73
|
+
sleep(10)
|
74
|
+
end
|
75
|
+
|
76
|
+
Process.kill('TERM', pid)
|
77
|
+
_, exit_status = Process.waitpid2(pid)
|
78
|
+
|
79
|
+
assert_equal 0, exit_status, "The forked process did not exit cleanly"
|
80
|
+
assert_equal "exiting:1|c", @receiver.recvfrom_nonblock(100).first
|
81
|
+
|
82
|
+
rescue NotImplementedError
|
83
|
+
pass("Fork is not implemented on #{RUBY_PLATFORM}")
|
84
|
+
end
|
85
|
+
end
|