statsd-instrument 2.5.1 → 2.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop-https---shopify-github-io-ruby-style-guide-rubocop-yml +1 -1
  3. data/.rubocop.yml +11 -6
  4. data/.yardopts +5 -0
  5. data/CHANGELOG.md +75 -6
  6. data/README.md +54 -46
  7. data/benchmark/datagram-client +41 -0
  8. data/lib/statsd/instrument/assertions.rb +168 -57
  9. data/lib/statsd/instrument/backends/udp_backend.rb +20 -29
  10. data/lib/statsd/instrument/capture_sink.rb +27 -0
  11. data/lib/statsd/instrument/client.rb +313 -0
  12. data/lib/statsd/instrument/datagram.rb +75 -0
  13. data/lib/statsd/instrument/datagram_builder.rb +101 -0
  14. data/lib/statsd/instrument/dogstatsd_datagram_builder.rb +71 -0
  15. data/lib/statsd/instrument/environment.rb +106 -29
  16. data/lib/statsd/instrument/log_sink.rb +24 -0
  17. data/lib/statsd/instrument/null_sink.rb +13 -0
  18. data/lib/statsd/instrument/rubocop/measure_as_dist_argument.rb +39 -0
  19. data/lib/statsd/instrument/rubocop/metaprogramming_positional_arguments.rb +6 -10
  20. data/lib/statsd/instrument/rubocop/metric_prefix_argument.rb +37 -0
  21. data/lib/statsd/instrument/rubocop/metric_return_value.rb +7 -6
  22. data/lib/statsd/instrument/rubocop/metric_value_keyword_argument.rb +11 -20
  23. data/lib/statsd/instrument/rubocop/positional_arguments.rb +13 -13
  24. data/lib/statsd/instrument/rubocop/splat_arguments.rb +8 -14
  25. data/lib/statsd/instrument/rubocop.rb +64 -0
  26. data/lib/statsd/instrument/statsd_datagram_builder.rb +14 -0
  27. data/lib/statsd/instrument/strict.rb +112 -22
  28. data/lib/statsd/instrument/udp_sink.rb +62 -0
  29. data/lib/statsd/instrument/version.rb +1 -1
  30. data/lib/statsd/instrument.rb +191 -100
  31. data/test/assertions_test.rb +139 -176
  32. data/test/capture_sink_test.rb +44 -0
  33. data/test/client_test.rb +164 -0
  34. data/test/compatibility/dogstatsd_datagram_compatibility_test.rb +162 -0
  35. data/test/datagram_builder_test.rb +120 -0
  36. data/test/deprecations_test.rb +56 -10
  37. data/test/dogstatsd_datagram_builder_test.rb +32 -0
  38. data/test/environment_test.rb +73 -7
  39. data/test/log_sink_test.rb +37 -0
  40. data/test/null_sink_test.rb +13 -0
  41. data/test/rubocop/measure_as_dist_argument_test.rb +44 -0
  42. data/test/rubocop/metaprogramming_positional_arguments_test.rb +1 -1
  43. data/test/rubocop/metric_prefix_argument_test.rb +38 -0
  44. data/test/rubocop/metric_return_value_test.rb +1 -1
  45. data/test/rubocop/metric_value_keyword_argument_test.rb +1 -1
  46. data/test/rubocop/positional_arguments_test.rb +1 -1
  47. data/test/rubocop/splat_arguments_test.rb +1 -1
  48. data/test/statsd_datagram_builder_test.rb +22 -0
  49. data/test/statsd_instrumentation_test.rb +0 -24
  50. data/test/statsd_test.rb +0 -23
  51. data/test/test_helper.rb +0 -2
  52. data/test/udp_backend_test.rb +25 -8
  53. data/test/udp_sink_test.rb +85 -0
  54. metadata +38 -2
@@ -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
@@ -4,13 +4,13 @@ require 'test_helper'
4
4
 
5
5
  class DeprecationsTest < Minitest::Test
6
6
  unless StatsD::Instrument.strict_mode_enabled?
7
- # rubocop:disable StatsD/MetaprogrammingPositionalArguments
8
7
  class InstrumentedClass
9
8
  extend StatsD::Instrument
10
9
  def foo; end
11
- statsd_count :foo, 'metric', 0.5, ['tag']
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
12
13
  end
13
- # rubocop:enable StatsD/MetaprogrammingPositionalArguments
14
14
  end
15
15
 
16
16
  include StatsD::Instrument::Assertions
@@ -19,6 +19,30 @@ class DeprecationsTest < Minitest::Test
19
19
  skip("Deprecation are not supported in strict mode") if StatsD::Instrument.strict_mode_enabled?
20
20
  end
21
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
+
22
46
  # rubocop:disable StatsD/MetricValueKeywordArgument
23
47
  def test__deprecated__statsd_measure_with_explicit_value_as_keyword_argument
24
48
  metric = capture_statsd_call { StatsD.measure('values.foobar', value: 42) }
@@ -27,11 +51,13 @@ class DeprecationsTest < Minitest::Test
27
51
  assert_equal :ms, metric.type
28
52
  end
29
53
 
54
+ # rubocop:disable StatsD/MeasureAsDistArgument
30
55
  def test__deprecated__statsd_measure_with_explicit_value_keyword_and_distribution_override
31
56
  metric = capture_statsd_call { StatsD.measure('values.foobar', value: 42, as_dist: true) }
32
57
  assert_equal 42, metric.value
33
58
  assert_equal :d, metric.type
34
59
  end
60
+ # rubocop:enable StatsD/MeasureAsDistArgument
35
61
 
36
62
  def test__deprecated__statsd_increment_with_value_as_keyword_argument
37
63
  metric = capture_statsd_call { StatsD.increment('values.foobar', value: 2) }
@@ -67,14 +93,34 @@ class DeprecationsTest < Minitest::Test
67
93
  end
68
94
  # rubocop:enable StatsD/PositionalArguments
69
95
 
70
- def test__deprecated__metaprogramming_method_with_positional_arguments
71
- metric = capture_statsd_call { InstrumentedClass.new.foo }
72
- assert_equal :c, metric.type
73
- assert_equal 'metric', metric.name
74
- assert_equal 1, metric.value
75
- assert_equal 0.5, metric.sample_rate
76
- assert_equal ["tag"], metric.tags
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
77
122
  end
123
+ # rubocop:enable StatsD/MetricPrefixArgument
78
124
 
79
125
  protected
80
126
 
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ require 'statsd/instrument/client'
6
+
7
+ class DogStatsDDatagramBuilderTest < Minitest::Test
8
+ def setup
9
+ @datagram_builder = StatsD::Instrument::DogStatsDDatagramBuilder.new
10
+ end
11
+
12
+ def test_raises_on_unsupported_metrics
13
+ assert_raises(NotImplementedError) { @datagram_builder.kv('foo', 10, nil, nil) }
14
+ end
15
+
16
+ def test_service_check
17
+ assert_equal '_sc|service|0', @datagram_builder._sc('service', :ok)
18
+ datagram = @datagram_builder._sc('service', :warning, timestamp: Time.parse('2019-09-30T04:22:12Z'),
19
+ hostname: 'localhost', tags: { foo: 'bar|baz' }, message: 'blah')
20
+ assert_equal "_sc|service|1|h:localhost|d:1569817332|#foo:barbaz|m:blah", datagram
21
+ end
22
+
23
+ def test_event
24
+ assert_equal '_e{5,5}:hello|world', @datagram_builder._e('hello', "world")
25
+
26
+ datagram = @datagram_builder._e("testing", "with\nnewline", timestamp: Time.parse('2019-09-30T04:22:12Z'),
27
+ hostname: 'localhost', aggregation_key: 'my-key', priority: 'low', source_type_name: 'source',
28
+ alert_type: 'success', tags: { foo: 'bar|baz' })
29
+ assert_equal '_e{7,13}:testing|with\\nnewline|h:localhost|d:1569817332|k:my-key|' \
30
+ 'p:low|s:source|t:success|#foo:barbaz', datagram
31
+ end
32
+ end