statsd-instrument 2.3.2 → 2.6.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/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
|