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/benchmark/tags.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'statsd-instrument'
|
2
4
|
require 'benchmark/ips'
|
3
5
|
|
4
6
|
Benchmark.ips do |bench|
|
5
7
|
bench.report("normalized tags with simple hash") do
|
6
|
-
StatsD::Instrument::Metric.normalize_tags(:
|
8
|
+
StatsD::Instrument::Metric.normalize_tags(tag: 'value')
|
7
9
|
end
|
8
10
|
|
9
11
|
bench.report("normalized tags with simple array") do
|
@@ -11,14 +13,14 @@ Benchmark.ips do |bench|
|
|
11
13
|
end
|
12
14
|
|
13
15
|
bench.report("normalized tags with large hash") do
|
14
|
-
StatsD::Instrument::Metric.normalize_tags(
|
16
|
+
StatsD::Instrument::Metric.normalize_tags(
|
15
17
|
mobile: true,
|
16
18
|
pod: "1",
|
17
19
|
protocol: "https",
|
18
20
|
country: "Langbortistan",
|
19
21
|
complete: true,
|
20
22
|
shop: "omg shop that has a longer name",
|
21
|
-
|
23
|
+
)
|
22
24
|
end
|
23
25
|
|
24
26
|
bench.report("normalized tags with large array") do
|
@@ -1,10 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'test_helper'
|
2
4
|
|
3
5
|
class CaptureBackendTest < Minitest::Test
|
4
6
|
def setup
|
5
7
|
@backend = StatsD::Instrument::Backends::CaptureBackend.new
|
6
|
-
@metric1 = StatsD::Instrument::Metric
|
7
|
-
@metric2 = StatsD::Instrument::Metric
|
8
|
+
@metric1 = StatsD::Instrument::Metric.new(type: :c, name: 'mock.counter')
|
9
|
+
@metric2 = StatsD::Instrument::Metric.new(type: :ms, name: 'mock.measure', value: 123)
|
8
10
|
end
|
9
11
|
|
10
12
|
def test_collecting_metric
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
require 'statsd/instrument/client'
|
6
|
+
|
7
|
+
class CaptureSinktest < Minitest::Test
|
8
|
+
def test_capture_sink_captures_datagram_instances
|
9
|
+
capture_sink = StatsD::Instrument::CaptureSink.new(parent: [])
|
10
|
+
capture_sink << 'foo:1|c'
|
11
|
+
|
12
|
+
assert_equal 1, capture_sink.datagrams.length
|
13
|
+
assert_kind_of StatsD::Instrument::Datagram, capture_sink.datagrams.first
|
14
|
+
assert_equal 'foo:1|c', capture_sink.datagrams.first.source
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_capture_sink_sends_datagrams_to_parent
|
18
|
+
parent = []
|
19
|
+
capture_sink = StatsD::Instrument::CaptureSink.new(parent: parent)
|
20
|
+
capture_sink << 'foo:1|c' << 'bar:1|c'
|
21
|
+
|
22
|
+
assert_equal ['foo:1|c', 'bar:1|c'], parent
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_nesting_capture_sink_instances
|
26
|
+
null_sink = StatsD::Instrument::NullSink.new
|
27
|
+
outer_capture_sink = StatsD::Instrument::CaptureSink.new(parent: null_sink)
|
28
|
+
inner_capture_sink = StatsD::Instrument::CaptureSink.new(parent: outer_capture_sink)
|
29
|
+
|
30
|
+
outer_capture_sink << 'foo:1|c'
|
31
|
+
inner_capture_sink << 'bar:1|c'
|
32
|
+
|
33
|
+
assert_equal ['foo:1|c', 'bar:1|c'], outer_capture_sink.datagrams.map(&:source)
|
34
|
+
assert_equal ['bar:1|c'], inner_capture_sink.datagrams.map(&:source)
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_using_a_different_datagram_class
|
38
|
+
sink = StatsD::Instrument::CaptureSink.new(parent: [], datagram_class: String)
|
39
|
+
sink << 'foo:1|c'
|
40
|
+
|
41
|
+
assert sink.datagrams.all? { |datagram| datagram.is_a?(String) }
|
42
|
+
assert_equal ['foo:1|c'], sink.datagrams
|
43
|
+
end
|
44
|
+
end
|
data/test/client_test.rb
ADDED
@@ -0,0 +1,164 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
require 'statsd/instrument/client'
|
6
|
+
|
7
|
+
class ClientTest < Minitest::Test
|
8
|
+
def setup
|
9
|
+
@client = StatsD::Instrument::Client.new(datagram_builder_class: StatsD::Instrument::StatsDDatagramBuilder)
|
10
|
+
@dogstatsd_client = StatsD::Instrument::Client.new(
|
11
|
+
datagram_builder_class: StatsD::Instrument::DogStatsDDatagramBuilder,
|
12
|
+
)
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_capture
|
16
|
+
inner_datagrams = nil
|
17
|
+
|
18
|
+
@client.increment('foo')
|
19
|
+
outer_datagrams = @client.capture do
|
20
|
+
@client.increment('bar')
|
21
|
+
inner_datagrams = @client.capture do
|
22
|
+
@client.increment('baz')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
@client.increment('quc')
|
26
|
+
|
27
|
+
assert_equal ['bar', 'baz'], outer_datagrams.map(&:name)
|
28
|
+
assert_equal ['baz'], inner_datagrams.map(&:name)
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_metric_methods_return_nil
|
32
|
+
assert_nil @client.increment('foo')
|
33
|
+
assert_nil @client.measure('bar', 122.54)
|
34
|
+
assert_nil @client.set('baz', 123)
|
35
|
+
assert_nil @client.gauge('baz', 12.3)
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_increment_with_default_value
|
39
|
+
datagrams = @client.capture { @client.increment('foo') }
|
40
|
+
assert_equal 1, datagrams.size
|
41
|
+
assert_equal 'foo:1|c', datagrams.first.source
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_measure_with_value
|
45
|
+
datagrams = @client.capture { @client.measure('foo', 122.54) }
|
46
|
+
assert_equal 1, datagrams.size
|
47
|
+
assert_equal 'foo:122.54|ms', datagrams.first.source
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_measure_with_block
|
51
|
+
Process.stubs(:clock_gettime).with(Process::CLOCK_MONOTONIC).returns(0.1, 0.2)
|
52
|
+
datagrams = @client.capture do
|
53
|
+
@client.measure('foo') {}
|
54
|
+
end
|
55
|
+
assert_equal 1, datagrams.size
|
56
|
+
assert_equal 'foo:100.0|ms', datagrams.first.source
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_gauge
|
60
|
+
datagrams = @client.capture { @client.gauge('foo', 123) }
|
61
|
+
assert_equal 1, datagrams.size
|
62
|
+
assert_equal 'foo:123|g', datagrams.first.source
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_set
|
66
|
+
datagrams = @client.capture { @client.set('foo', 12345) }
|
67
|
+
assert_equal 1, datagrams.size
|
68
|
+
assert_equal 'foo:12345|s', datagrams.first.source
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_histogram
|
72
|
+
datagrams = @dogstatsd_client.capture { @dogstatsd_client.histogram('foo', 12.44) }
|
73
|
+
assert_equal 1, datagrams.size
|
74
|
+
assert_equal 'foo:12.44|h', datagrams.first.source
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_distribution_with_value
|
78
|
+
datagrams = @dogstatsd_client.capture { @dogstatsd_client.distribution('foo', 12.44) }
|
79
|
+
assert_equal 1, datagrams.size
|
80
|
+
assert_equal 'foo:12.44|d', datagrams.first.source
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_distribution_with_block
|
84
|
+
Process.stubs(:clock_gettime).with(Process::CLOCK_MONOTONIC).returns(0.1, 0.2)
|
85
|
+
datagrams = @dogstatsd_client.capture do
|
86
|
+
@dogstatsd_client.distribution('foo') {}
|
87
|
+
end
|
88
|
+
assert_equal 1, datagrams.size
|
89
|
+
assert_equal "foo:100.0|d", datagrams.first.source
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_latency_emits_ms_metric
|
93
|
+
Process.stubs(:clock_gettime).with(Process::CLOCK_MONOTONIC).returns(0.1, 0.2)
|
94
|
+
datagrams = @client.capture do
|
95
|
+
@client.latency('foo') {}
|
96
|
+
end
|
97
|
+
assert_equal 1, datagrams.size
|
98
|
+
assert_equal "foo:100.0|ms", datagrams.first.source
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_latency_on_dogstatsd_prefers_distribution_metric_type
|
102
|
+
Process.stubs(:clock_gettime).with(Process::CLOCK_MONOTONIC).returns(0.1, 0.2)
|
103
|
+
datagrams = @dogstatsd_client.capture do
|
104
|
+
@dogstatsd_client.latency('foo') {}
|
105
|
+
end
|
106
|
+
assert_equal 1, datagrams.size
|
107
|
+
assert_equal "foo:100.0|d", datagrams.first.source
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_latency_calls_block_even_when_not_sending_a_sample
|
111
|
+
called = false
|
112
|
+
@client.capture do
|
113
|
+
@client.latency('foo', sample_rate: 0) { called = true }
|
114
|
+
end
|
115
|
+
assert called, "The block should have been called"
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_service_check
|
119
|
+
datagrams = @dogstatsd_client.capture { @dogstatsd_client.service_check('service', :ok) }
|
120
|
+
assert_equal 1, datagrams.size
|
121
|
+
assert_equal "_sc|service|0", datagrams.first.source
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_event
|
125
|
+
datagrams = @dogstatsd_client.capture { @dogstatsd_client.event('service', "event\ndescription") }
|
126
|
+
assert_equal 1, datagrams.size
|
127
|
+
assert_equal "_e{7,18}:service|event\\ndescription", datagrams.first.source
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_no_prefix
|
131
|
+
client = StatsD::Instrument::Client.new(prefix: 'foo')
|
132
|
+
datagrams = client.capture do
|
133
|
+
client.increment('bar')
|
134
|
+
client.increment('bar', no_prefix: true)
|
135
|
+
end
|
136
|
+
|
137
|
+
assert_equal 2, datagrams.size
|
138
|
+
assert_equal "foo.bar", datagrams[0].name
|
139
|
+
assert_equal "bar", datagrams[1].name
|
140
|
+
end
|
141
|
+
|
142
|
+
def test_sampling
|
143
|
+
mock_sink = mock('sink')
|
144
|
+
mock_sink.stubs(:sample?).returns(false, true, false, false, true)
|
145
|
+
mock_sink.expects(:<<).twice
|
146
|
+
|
147
|
+
client = StatsD::Instrument::Client.new(sink: mock_sink)
|
148
|
+
5.times { client.increment('metric') }
|
149
|
+
end
|
150
|
+
|
151
|
+
def test_clone_with_prefix_option
|
152
|
+
# Both clients will use the same sink.
|
153
|
+
mock_sink = mock('sink')
|
154
|
+
mock_sink.stubs(:sample?).returns(true)
|
155
|
+
mock_sink.expects(:<<).with("metric:1|c").returns(mock_sink)
|
156
|
+
mock_sink.expects(:<<).with("foo.metric:1|c").returns(mock_sink)
|
157
|
+
|
158
|
+
original_client = StatsD::Instrument::Client.new(sink: mock_sink)
|
159
|
+
client_with_other_options = original_client.clone_with_options(prefix: 'foo')
|
160
|
+
|
161
|
+
original_client.increment('metric')
|
162
|
+
client_with_other_options.increment('metric')
|
163
|
+
end
|
164
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
require 'statsd/instrument/client'
|
5
|
+
|
6
|
+
module Compatibility
|
7
|
+
class DogStatsDDatagramCompatibilityTest < Minitest::Test
|
8
|
+
def setup
|
9
|
+
StatsD::Instrument::UDPSink.any_instance.stubs(:sample?).returns(true)
|
10
|
+
StatsD::Instrument::Backends::UDPBackend.any_instance.stubs(:rand).returns(0)
|
11
|
+
|
12
|
+
@server = UDPSocket.new
|
13
|
+
@server.bind('localhost', 0)
|
14
|
+
@host = @server.addr[2]
|
15
|
+
@port = @server.addr[1]
|
16
|
+
end
|
17
|
+
|
18
|
+
def teardown
|
19
|
+
@server.close
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_increment_compatibility
|
23
|
+
assert_equal_datagrams { |client| client.increment('counter') }
|
24
|
+
assert_equal_datagrams { |client| client.increment('counter', no_prefix: true) }
|
25
|
+
assert_equal_datagrams { |client| client.increment('counter', 12) }
|
26
|
+
assert_equal_datagrams { |client| client.increment('counter', sample_rate: 0.1) }
|
27
|
+
assert_equal_datagrams { |client| client.increment('counter', tags: ['foo', 'bar']) }
|
28
|
+
assert_equal_datagrams { |client| client.increment('counter', tags: { foo: 'bar' }) }
|
29
|
+
assert_equal_datagrams { |client| client.increment('counter', sample_rate: 0.1, tags: ['quc']) }
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_measure_compatibility
|
33
|
+
assert_equal_datagrams { |client| client.measure('timing', 12.34) }
|
34
|
+
assert_equal_datagrams { |client| client.measure('timing', 0.01, no_prefix: true) }
|
35
|
+
assert_equal_datagrams { |client| client.measure('timing', 0.12, sample_rate: 0.1) }
|
36
|
+
assert_equal_datagrams { |client| client.measure('timing', 0.12, tags: ['foo', 'bar']) }
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_measure_with_block_compatibility
|
40
|
+
Process.stubs(:clock_gettime).with(Process::CLOCK_MONOTONIC).returns(12.1)
|
41
|
+
assert_equal_datagrams do |client|
|
42
|
+
return_value = client.measure('timing', tags: ['foo'], sample_rate: 0.1) { 'foo' }
|
43
|
+
assert_equal 'foo', return_value
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_gauge_compatibility
|
48
|
+
assert_equal_datagrams { |client| client.gauge('current', 1234) }
|
49
|
+
assert_equal_datagrams { |client| client.gauge('current', 1234, no_prefix: true) }
|
50
|
+
assert_equal_datagrams { |client| client.gauge('current', 1234, sample_rate: 0.1) }
|
51
|
+
assert_equal_datagrams { |client| client.gauge('current', 1234, tags: ['foo', 'bar']) }
|
52
|
+
assert_equal_datagrams { |client| client.gauge('current', 1234, tags: { foo: 'bar' }) }
|
53
|
+
assert_equal_datagrams { |client| client.gauge('current', 1234, sample_rate: 0.1, tags: ['quc']) }
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_set_compatibility
|
57
|
+
assert_equal_datagrams { |client| client.set('unique', 'foo') }
|
58
|
+
assert_equal_datagrams { |client| client.set('unique', 'foo', no_prefix: true) }
|
59
|
+
assert_equal_datagrams { |client| client.set('unique', 'foo', sample_rate: 0.1) }
|
60
|
+
assert_equal_datagrams { |client| client.set('unique', '1234', tags: ['foo', 'bar']) }
|
61
|
+
assert_equal_datagrams { |client| client.set('unique', '1234', tags: { foo: 'bar' }) }
|
62
|
+
assert_equal_datagrams { |client| client.set('unique', '1234', sample_rate: 0.1, tags: ['quc']) }
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_histogram_compatibility
|
66
|
+
assert_equal_datagrams { |client| client.histogram('sample', 12.44) }
|
67
|
+
assert_equal_datagrams { |client| client.histogram('sample', 12.44, no_prefix: true) }
|
68
|
+
assert_equal_datagrams { |client| client.histogram('sample', 12.44, sample_rate: 0.1) }
|
69
|
+
assert_equal_datagrams { |client| client.histogram('sample', 12.44, tags: ['foo', 'bar']) }
|
70
|
+
assert_equal_datagrams { |client| client.histogram('sample', 12.44, tags: { foo: 'bar' }) }
|
71
|
+
assert_equal_datagrams { |client| client.histogram('sample', 12.44, sample_rate: 0.1, tags: ['quc']) }
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_distribution_compatibility
|
75
|
+
assert_equal_datagrams { |client| client.distribution('sample', 12.44) }
|
76
|
+
assert_equal_datagrams { |client| client.distribution('sample', 12.44, no_prefix: true) }
|
77
|
+
assert_equal_datagrams { |client| client.distribution('sample', 12.44, sample_rate: 0.1) }
|
78
|
+
assert_equal_datagrams { |client| client.distribution('sample', 12.44, tags: ['foo', 'bar']) }
|
79
|
+
assert_equal_datagrams { |client| client.distribution('sample', 12.44, tags: { foo: 'bar' }) }
|
80
|
+
assert_equal_datagrams { |client| client.distribution('sample', 12.44, sample_rate: 0.1, tags: ['quc']) }
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_distribution_with_block_compatibility
|
84
|
+
Process.stubs(:clock_gettime).with(Process::CLOCK_MONOTONIC).returns(12.1)
|
85
|
+
assert_equal_datagrams do |client|
|
86
|
+
return_value = client.distribution('timing', tags: ['foo'], sample_rate: 0.1) { 'foo' }
|
87
|
+
assert_equal 'foo', return_value
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_service_check_compatibility
|
92
|
+
assert_equal_datagrams { |client| client.service_check('service', 0) }
|
93
|
+
assert_equal_datagrams { |client| client.service_check('service', :critical, no_prefix: true) }
|
94
|
+
assert_equal_datagrams { |client| client.event('foo', "bar\nbaz") }
|
95
|
+
assert_equal_datagrams do |client|
|
96
|
+
client.service_check('service', "ok", timestamp: Time.parse('2019-09-09T04:22:17Z'),
|
97
|
+
hostname: 'localhost', tags: ['foo'], message: 'bar')
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_event_compatibility
|
102
|
+
assert_equal_datagrams { |client| client.event('foo', "bar\nbaz") }
|
103
|
+
assert_equal_datagrams { |client| client.event('foo', "bar\nbaz", no_prefix: true) }
|
104
|
+
assert_equal_datagrams do |client|
|
105
|
+
client.event('Something happend', "And it's not good", timestamp: Time.parse('2019-09-09T04:22:17Z'),
|
106
|
+
hostname: 'localhost', tags: ['foo'], alert_type: 'warning', priority: 'low',
|
107
|
+
aggregation_key: 'foo', source_type_name: 'logs')
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
private
|
112
|
+
|
113
|
+
MODES = [:normal, :with_prefix, :with_default_tags]
|
114
|
+
|
115
|
+
def assert_equal_datagrams(&block)
|
116
|
+
MODES.each do |mode|
|
117
|
+
legacy_datagram = with_legacy_client(mode) { |client| read_datagram(client, &block) }
|
118
|
+
new_datagram = with_new_client(mode) { |client| read_datagram(client, &block) }
|
119
|
+
|
120
|
+
assert_equal legacy_datagram, new_datagram, "The datagrams emitted were not the same in #{mode} mode"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def with_legacy_client(mode)
|
125
|
+
old_prefix = StatsD.prefix
|
126
|
+
StatsD.prefix = 'prefix' if mode == :with_prefix
|
127
|
+
|
128
|
+
old_default_tags = StatsD.default_tags
|
129
|
+
StatsD.default_tags = { key: 'value' } if mode == :with_default_tags
|
130
|
+
|
131
|
+
old_backend = StatsD.backend
|
132
|
+
new_backend = StatsD::Instrument::Backends::UDPBackend.new("#{@host}:#{@port}", :datadog)
|
133
|
+
StatsD.backend = new_backend
|
134
|
+
|
135
|
+
yield(StatsD)
|
136
|
+
ensure
|
137
|
+
new_backend.socket.close if new_backend&.socket
|
138
|
+
StatsD.backend = old_backend
|
139
|
+
StatsD.prefix = old_prefix
|
140
|
+
StatsD.default_tags = old_default_tags
|
141
|
+
end
|
142
|
+
|
143
|
+
def with_new_client(mode)
|
144
|
+
prefix = mode == :with_prefix ? 'prefix' : nil
|
145
|
+
default_tags = mode == :with_default_tags ? { key: 'value' } : nil
|
146
|
+
client = StatsD::Instrument::Client.new(
|
147
|
+
sink: StatsD::Instrument::UDPSink.new(@host, @port),
|
148
|
+
datagram_builder_class: StatsD::Instrument::DogStatsDDatagramBuilder,
|
149
|
+
prefix: prefix,
|
150
|
+
default_tags: default_tags
|
151
|
+
)
|
152
|
+
|
153
|
+
yield(client)
|
154
|
+
end
|
155
|
+
|
156
|
+
def read_datagram(client)
|
157
|
+
yield(client)
|
158
|
+
data, _origin = @server.recvfrom(100)
|
159
|
+
data
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
require 'statsd/instrument/client'
|
6
|
+
|
7
|
+
class DatagramBuilderTest < Minitest::Test
|
8
|
+
def setup
|
9
|
+
@datagram_builder = StatsD::Instrument::DatagramBuilder.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_normalize_name
|
13
|
+
assert_equal 'foo', @datagram_builder.send(:normalize_name, 'foo')
|
14
|
+
assert_equal 'fo_o', @datagram_builder.send(:normalize_name, 'fo|o')
|
15
|
+
assert_equal 'fo_o', @datagram_builder.send(:normalize_name, 'fo@o')
|
16
|
+
assert_equal 'fo_o', @datagram_builder.send(:normalize_name, 'fo:o')
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_normalize_unsupported_tag_names
|
20
|
+
assert_equal ['ignored'], @datagram_builder.send(:normalize_tags, ['igno|re,d'])
|
21
|
+
# Note: how this is interpreted by the backend is undefined.
|
22
|
+
# We rely on the user to not do stuff like this if they don't want to be surprised.
|
23
|
+
# We do not want to take the performance hit of normaling this.
|
24
|
+
assert_equal ['lol::class:omg::lol'], @datagram_builder.send(:normalize_tags, "lol::class" => "omg::lol")
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_normalize_tags_converts_hash_to_array
|
28
|
+
assert_equal ['tag:value'], @datagram_builder.send(:normalize_tags, tag: 'value')
|
29
|
+
assert_equal ['tag1:v1', 'tag2:v2'], @datagram_builder.send(:normalize_tags, tag1: 'v1', tag2: 'v2')
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_c
|
33
|
+
datagram = @datagram_builder.c('foo', 1, nil, nil)
|
34
|
+
assert_equal "foo:1|c", datagram
|
35
|
+
|
36
|
+
datagram = @datagram_builder.c('fo:o', 10, 0.1, nil)
|
37
|
+
assert_equal "fo_o:10|c|@0.1", datagram
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_ms
|
41
|
+
datagram = @datagram_builder.ms('foo', 1, nil, nil)
|
42
|
+
assert_equal "foo:1|ms", datagram
|
43
|
+
|
44
|
+
datagram = @datagram_builder.ms('fo:o', 10, 0.1, nil)
|
45
|
+
assert_equal "fo_o:10|ms|@0.1", datagram
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_g
|
49
|
+
datagram = @datagram_builder.g('foo', 1, nil, nil)
|
50
|
+
assert_equal "foo:1|g", datagram
|
51
|
+
|
52
|
+
datagram = @datagram_builder.g('fo|o', 10, 0.01, nil)
|
53
|
+
assert_equal "fo_o:10|g|@0.01", datagram
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_s
|
57
|
+
datagram = @datagram_builder.s('foo', 1, nil, nil)
|
58
|
+
assert_equal "foo:1|s", datagram
|
59
|
+
|
60
|
+
datagram = @datagram_builder.s('fo@o', 10, 0.01, nil)
|
61
|
+
assert_equal "fo_o:10|s|@0.01", datagram
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_h
|
65
|
+
datagram = @datagram_builder.h('foo', 1, nil, nil)
|
66
|
+
assert_equal "foo:1|h", datagram
|
67
|
+
|
68
|
+
datagram = @datagram_builder.h('fo@o', 10, 0.01, nil)
|
69
|
+
assert_equal "fo_o:10|h|@0.01", datagram
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_d
|
73
|
+
datagram = @datagram_builder.d('foo', 1, nil, nil)
|
74
|
+
assert_equal "foo:1|d", datagram
|
75
|
+
|
76
|
+
datagram = @datagram_builder.d('fo@o', 10, 0.01, nil)
|
77
|
+
assert_equal "fo_o:10|d|@0.01", datagram
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_tags
|
81
|
+
datagram = @datagram_builder.d('foo', 10, nil, ['foo', 'bar'])
|
82
|
+
assert_equal "foo:10|d|#foo,bar", datagram
|
83
|
+
|
84
|
+
datagram = @datagram_builder.d('foo', 10, 0.1, ['foo:bar'])
|
85
|
+
assert_equal "foo:10|d|@0.1|#foo:bar", datagram
|
86
|
+
|
87
|
+
datagram = @datagram_builder.d('foo', 10, 1, foo: 'bar', baz: 'quc')
|
88
|
+
assert_equal "foo:10|d|#foo:bar,baz:quc", datagram
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_prefix
|
92
|
+
datagram_builder = StatsD::Instrument::DatagramBuilder.new(prefix: 'foo')
|
93
|
+
datagram = datagram_builder.c('bar', 1, nil, nil)
|
94
|
+
assert_equal 'foo.bar:1|c', datagram
|
95
|
+
|
96
|
+
# The prefix should also be normalized
|
97
|
+
datagram_builder = StatsD::Instrument::DatagramBuilder.new(prefix: 'foo|bar')
|
98
|
+
datagram = datagram_builder.c('baz', 1, nil, nil)
|
99
|
+
assert_equal 'foo_bar.baz:1|c', datagram
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_default_tags
|
103
|
+
datagram_builder = StatsD::Instrument::DatagramBuilder.new(default_tags: ['foo'])
|
104
|
+
datagram = datagram_builder.c('bar', 1, nil, nil)
|
105
|
+
assert_equal 'bar:1|c|#foo', datagram
|
106
|
+
|
107
|
+
datagram = datagram_builder.c('bar', 1, nil, a: 'b')
|
108
|
+
assert_equal 'bar:1|c|#a:b,foo', datagram
|
109
|
+
|
110
|
+
# We do not filter out duplicates, because detecting dupes is too time consuming.
|
111
|
+
# We let the server deal with the situation
|
112
|
+
datagram = datagram_builder.c('bar', 1, nil, ['foo'])
|
113
|
+
assert_equal 'bar:1|c|#foo,foo', datagram
|
114
|
+
|
115
|
+
# Default tags are also normalized
|
116
|
+
datagram_builder = StatsD::Instrument::DatagramBuilder.new(default_tags: ['f,o|o'])
|
117
|
+
datagram = datagram_builder.c('bar', 1, nil, nil)
|
118
|
+
assert_equal 'bar:1|c|#foo', datagram
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
class DeprecationsTest < Minitest::Test
|
6
|
+
unless StatsD::Instrument.strict_mode_enabled?
|
7
|
+
class InstrumentedClass
|
8
|
+
extend StatsD::Instrument
|
9
|
+
def foo; end
|
10
|
+
statsd_count :foo, 'frequency', 0.5, ['tag'] # rubocop:disable StatsD/MetaprogrammingPositionalArguments
|
11
|
+
statsd_measure :foo, 'latency', as_dist: true # rubocop:disable StatsD/MeasureAsDistArgument
|
12
|
+
statsd_count_success :foo, 'frequency', prefix: 'foo' # rubocop:disable StatsD/MetricPrefixArgument
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
include StatsD::Instrument::Assertions
|
17
|
+
|
18
|
+
def setup
|
19
|
+
skip("Deprecation are not supported in strict mode") if StatsD::Instrument.strict_mode_enabled?
|
20
|
+
end
|
21
|
+
|
22
|
+
def test__deprecated__metaprogramming_method_with_positional_arguments
|
23
|
+
metrics = capture_statsd_calls { InstrumentedClass.new.foo }
|
24
|
+
metric = metrics[0]
|
25
|
+
assert_equal :c, metric.type
|
26
|
+
assert_equal 'frequency', metric.name
|
27
|
+
assert_equal 1, metric.value
|
28
|
+
assert_equal 0.5, metric.sample_rate
|
29
|
+
assert_equal ["tag"], metric.tags
|
30
|
+
end
|
31
|
+
|
32
|
+
def test__deprecated__metaprogramming_statsd_measure_with_as_dist
|
33
|
+
metrics = capture_statsd_calls { InstrumentedClass.new.foo }
|
34
|
+
metric = metrics[1]
|
35
|
+
assert_equal :d, metric.type
|
36
|
+
assert_equal 'latency', metric.name
|
37
|
+
end
|
38
|
+
|
39
|
+
def test__deprecated__metaprogramming_statsd_count_with_prefix
|
40
|
+
metrics = capture_statsd_calls { InstrumentedClass.new.foo }
|
41
|
+
metric = metrics[2]
|
42
|
+
assert_equal :c, metric.type
|
43
|
+
assert_equal 'foo.frequency.success', metric.name
|
44
|
+
end
|
45
|
+
|
46
|
+
# rubocop:disable StatsD/MetricValueKeywordArgument
|
47
|
+
def test__deprecated__statsd_measure_with_explicit_value_as_keyword_argument
|
48
|
+
metric = capture_statsd_call { StatsD.measure('values.foobar', value: 42) }
|
49
|
+
assert_equal 'values.foobar', metric.name
|
50
|
+
assert_equal 42, metric.value
|
51
|
+
assert_equal :ms, metric.type
|
52
|
+
end
|
53
|
+
|
54
|
+
# rubocop:disable StatsD/MeasureAsDistArgument
|
55
|
+
def test__deprecated__statsd_measure_with_explicit_value_keyword_and_distribution_override
|
56
|
+
metric = capture_statsd_call { StatsD.measure('values.foobar', value: 42, as_dist: true) }
|
57
|
+
assert_equal 42, metric.value
|
58
|
+
assert_equal :d, metric.type
|
59
|
+
end
|
60
|
+
# rubocop:enable StatsD/MeasureAsDistArgument
|
61
|
+
|
62
|
+
def test__deprecated__statsd_increment_with_value_as_keyword_argument
|
63
|
+
metric = capture_statsd_call { StatsD.increment('values.foobar', value: 2) }
|
64
|
+
assert_equal StatsD.default_sample_rate, metric.sample_rate
|
65
|
+
assert_equal 2, metric.value
|
66
|
+
end
|
67
|
+
|
68
|
+
def test__deprecated__statsd_gauge_with_keyword_argument
|
69
|
+
metric = capture_statsd_call { StatsD.gauge('values.foobar', value: 13) }
|
70
|
+
assert_equal :g, metric.type
|
71
|
+
assert_equal 'values.foobar', metric.name
|
72
|
+
assert_equal 13, metric.value
|
73
|
+
end
|
74
|
+
# rubocop:enable StatsD/MetricValueKeywordArgument
|
75
|
+
|
76
|
+
# rubocop:disable StatsD/MetricReturnValue
|
77
|
+
def test__deprecated__statsd_increment_retuns_metric_instance
|
78
|
+
metric = StatsD.increment('key')
|
79
|
+
assert_kind_of StatsD::Instrument::Metric, metric
|
80
|
+
assert_equal 'key', metric.name
|
81
|
+
assert_equal :c, metric.type
|
82
|
+
assert_equal 1, metric.value
|
83
|
+
end
|
84
|
+
# rubocop:enable StatsD/MetricReturnValue
|
85
|
+
|
86
|
+
# rubocop:disable StatsD/PositionalArguments
|
87
|
+
def test__deprecated__statsd_increment_with_positional_argument_for_tags
|
88
|
+
metric = capture_statsd_call { StatsD.increment('values.foobar', 12, nil, ['test']) }
|
89
|
+
assert_equal StatsD.default_sample_rate, metric.sample_rate
|
90
|
+
assert_equal ['test'], metric.tags
|
91
|
+
assert_equal 12, metric.value
|
92
|
+
assert_equal StatsD.default_sample_rate, metric.sample_rate
|
93
|
+
end
|
94
|
+
# rubocop:enable StatsD/PositionalArguments
|
95
|
+
|
96
|
+
# rubocop:disable StatsD/MeasureAsDistArgument
|
97
|
+
def test__deprecated__statsd_measure_with_explicit_value_and_distribution_override
|
98
|
+
metric = capture_statsd_call { StatsD.measure('values.foobar', 42, as_dist: true) }
|
99
|
+
assert_equal :d, metric.type
|
100
|
+
end
|
101
|
+
|
102
|
+
def test__deprecated__statsd_measure_use_distribution_override_for_a_block
|
103
|
+
metric = capture_statsd_call do
|
104
|
+
StatsD.measure('values.foobar', as_dist: true) { 'foo' }
|
105
|
+
end
|
106
|
+
assert_equal :d, metric.type
|
107
|
+
end
|
108
|
+
|
109
|
+
def test__deprecated__statsd_measure_as_distribution_returns_return_value_of_block_even_if_nil
|
110
|
+
return_value = StatsD.measure('values.foobar', as_dist: true) { nil }
|
111
|
+
assert_nil return_value
|
112
|
+
end
|
113
|
+
# rubocop:enable StatsD/MeasureAsDistArgument
|
114
|
+
|
115
|
+
# rubocop:disable StatsD/MetricPrefixArgument
|
116
|
+
def test__deprecated__override_name_prefix
|
117
|
+
m = capture_statsd_call { StatsD.increment('counter', prefix: "foobar") }
|
118
|
+
assert_equal 'foobar.counter', m.name
|
119
|
+
|
120
|
+
m = capture_statsd_call { StatsD.increment('counter', prefix: "foobar", no_prefix: true) }
|
121
|
+
assert_equal 'counter', m.name
|
122
|
+
end
|
123
|
+
# rubocop:enable StatsD/MetricPrefixArgument
|
124
|
+
|
125
|
+
protected
|
126
|
+
|
127
|
+
def capture_statsd_call(&block)
|
128
|
+
metrics = capture_statsd_calls(&block)
|
129
|
+
assert_equal 1, metrics.length
|
130
|
+
metrics.first
|
131
|
+
end
|
132
|
+
end
|