statsd-instrument 2.5.1 → 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/.rubocop-https---shopify-github-io-ruby-style-guide-rubocop-yml +1 -1
- data/.rubocop.yml +11 -6
- data/.yardopts +5 -0
- data/CHANGELOG.md +75 -6
- data/README.md +54 -46
- data/benchmark/datagram-client +41 -0
- data/lib/statsd/instrument/assertions.rb +168 -57
- data/lib/statsd/instrument/backends/udp_backend.rb +20 -29
- 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 +106 -29
- data/lib/statsd/instrument/log_sink.rb +24 -0
- data/lib/statsd/instrument/null_sink.rb +13 -0
- data/lib/statsd/instrument/rubocop/measure_as_dist_argument.rb +39 -0
- data/lib/statsd/instrument/rubocop/metaprogramming_positional_arguments.rb +6 -10
- data/lib/statsd/instrument/rubocop/metric_prefix_argument.rb +37 -0
- data/lib/statsd/instrument/rubocop/metric_return_value.rb +7 -6
- data/lib/statsd/instrument/rubocop/metric_value_keyword_argument.rb +11 -20
- data/lib/statsd/instrument/rubocop/positional_arguments.rb +13 -13
- data/lib/statsd/instrument/rubocop/splat_arguments.rb +8 -14
- data/lib/statsd/instrument/rubocop.rb +64 -0
- data/lib/statsd/instrument/statsd_datagram_builder.rb +14 -0
- data/lib/statsd/instrument/strict.rb +112 -22
- data/lib/statsd/instrument/udp_sink.rb +62 -0
- data/lib/statsd/instrument/version.rb +1 -1
- data/lib/statsd/instrument.rb +191 -100
- data/test/assertions_test.rb +139 -176
- 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 +56 -10
- data/test/dogstatsd_datagram_builder_test.rb +32 -0
- data/test/environment_test.rb +73 -7
- data/test/log_sink_test.rb +37 -0
- 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 +1 -1
- data/test/rubocop/metric_prefix_argument_test.rb +38 -0
- data/test/rubocop/metric_return_value_test.rb +1 -1
- data/test/rubocop/metric_value_keyword_argument_test.rb +1 -1
- data/test/rubocop/positional_arguments_test.rb +1 -1
- data/test/rubocop/splat_arguments_test.rb +1 -1
- data/test/statsd_datagram_builder_test.rb +22 -0
- data/test/statsd_instrumentation_test.rb +0 -24
- data/test/statsd_test.rb +0 -23
- data/test/test_helper.rb +0 -2
- data/test/udp_backend_test.rb +25 -8
- data/test/udp_sink_test.rb +85 -0
- metadata +38 -2
@@ -24,15 +24,15 @@ module StatsD
|
|
24
24
|
#
|
25
25
|
# This monkeypatch is not meant to be used in production.
|
26
26
|
module Strict
|
27
|
-
def increment(key, value = 1, sample_rate: nil, tags: nil,
|
27
|
+
def increment(key, value = 1, sample_rate: nil, tags: nil, no_prefix: false)
|
28
28
|
raise ArgumentError, "StatsD.increment does not accept a block" if block_given?
|
29
|
-
raise ArgumentError, "The value argument should be an integer, got #{value.inspect}" unless value.is_a?(
|
29
|
+
raise ArgumentError, "The value argument should be an integer, got #{value.inspect}" unless value.is_a?(Integer)
|
30
30
|
check_tags_and_sample_rate(sample_rate, tags)
|
31
31
|
|
32
32
|
super
|
33
33
|
end
|
34
34
|
|
35
|
-
def gauge(key, value, sample_rate: nil, tags: nil,
|
35
|
+
def gauge(key, value, sample_rate: nil, tags: nil, no_prefix: false)
|
36
36
|
raise ArgumentError, "StatsD.increment does not accept a block" if block_given?
|
37
37
|
raise ArgumentError, "The value argument should be an integer, got #{value.inspect}" unless value.is_a?(Numeric)
|
38
38
|
check_tags_and_sample_rate(sample_rate, tags)
|
@@ -40,7 +40,7 @@ module StatsD
|
|
40
40
|
super
|
41
41
|
end
|
42
42
|
|
43
|
-
def histogram(key, value, sample_rate: nil, tags: nil,
|
43
|
+
def histogram(key, value, sample_rate: nil, tags: nil, no_prefix: false)
|
44
44
|
raise ArgumentError, "StatsD.increment does not accept a block" if block_given?
|
45
45
|
raise ArgumentError, "The value argument should be an integer, got #{value.inspect}" unless value.is_a?(Numeric)
|
46
46
|
check_tags_and_sample_rate(sample_rate, tags)
|
@@ -48,25 +48,33 @@ module StatsD
|
|
48
48
|
super
|
49
49
|
end
|
50
50
|
|
51
|
-
def set(key, value, sample_rate: nil, tags: nil,
|
51
|
+
def set(key, value, sample_rate: nil, tags: nil, no_prefix: false)
|
52
52
|
raise ArgumentError, "StatsD.set does not accept a block" if block_given?
|
53
53
|
check_tags_and_sample_rate(sample_rate, tags)
|
54
54
|
|
55
55
|
super
|
56
56
|
end
|
57
57
|
|
58
|
-
def
|
59
|
-
|
58
|
+
def service_check(name, status, tags: nil, no_prefix: false,
|
59
|
+
hostname: nil, timestamp: nil, message: nil)
|
60
|
+
|
61
|
+
super
|
62
|
+
end
|
63
|
+
|
64
|
+
def event(title, text, tags: nil, no_prefix: false,
|
65
|
+
hostname: nil, timestamp: nil, aggregation_key: nil, priority: nil, source_type_name: nil, alert_type: nil)
|
66
|
+
|
67
|
+
super
|
68
|
+
end
|
60
69
|
|
70
|
+
def measure(key, value = UNSPECIFIED, sample_rate: nil, tags: nil, no_prefix: false, &block)
|
61
71
|
check_block_or_numeric_value(value, &block)
|
62
72
|
check_tags_and_sample_rate(sample_rate, tags)
|
63
73
|
|
64
74
|
super
|
65
75
|
end
|
66
76
|
|
67
|
-
def distribution(key, value = UNSPECIFIED, sample_rate: nil, tags: nil,
|
68
|
-
prefix: StatsD.prefix, no_prefix: false, &block)
|
69
|
-
|
77
|
+
def distribution(key, value = UNSPECIFIED, sample_rate: nil, tags: nil, no_prefix: false, &block)
|
70
78
|
check_block_or_numeric_value(value, &block)
|
71
79
|
check_tags_and_sample_rate(sample_rate, tags)
|
72
80
|
|
@@ -99,31 +107,113 @@ module StatsD
|
|
99
107
|
end
|
100
108
|
|
101
109
|
module StrictMetaprogramming
|
102
|
-
def statsd_measure(method, name, sample_rate: nil, tags: nil,
|
103
|
-
prefix: StatsD.prefix, no_prefix: false, as_dist: false)
|
104
|
-
|
110
|
+
def statsd_measure(method, name, sample_rate: nil, tags: nil, no_prefix: false)
|
105
111
|
check_method_and_metric_name(method, name)
|
106
|
-
|
112
|
+
|
113
|
+
# Unfortunately, we have to inline the new method implementation ebcause we have to fix the
|
114
|
+
# Stats.measure call to not use the `as_dist` and `prefix` arguments.
|
115
|
+
add_to_method(method, name, :measure) do
|
116
|
+
define_method(method) do |*args, &block|
|
117
|
+
key = StatsD::Instrument.generate_metric_name(name, self, *args)
|
118
|
+
StatsD.measure(key, sample_rate: sample_rate, tags: tags, no_prefix: no_prefix) do
|
119
|
+
super(*args, &block)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
107
123
|
end
|
108
124
|
|
109
|
-
def statsd_distribution(method, name, sample_rate: nil, tags: nil,
|
125
|
+
def statsd_distribution(method, name, sample_rate: nil, tags: nil, no_prefix: false)
|
110
126
|
check_method_and_metric_name(method, name)
|
111
|
-
|
127
|
+
|
128
|
+
# Unfortunately, we have to inline the new method implementation ebcause we have to fix the
|
129
|
+
# Stats.distribution call to not use the `prefix` argument.
|
130
|
+
|
131
|
+
add_to_method(method, name, :distribution) do
|
132
|
+
define_method(method) do |*args, &block|
|
133
|
+
key = StatsD::Instrument.generate_metric_name(name, self, *args)
|
134
|
+
StatsD.distribution(key, sample_rate: sample_rate, tags: tags, no_prefix: no_prefix) do
|
135
|
+
super(*args, &block)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
112
139
|
end
|
113
140
|
|
114
|
-
def statsd_count_success(method, name, sample_rate: nil, tags: nil,
|
141
|
+
def statsd_count_success(method, name, sample_rate: nil, tags: nil, no_prefix: false)
|
115
142
|
check_method_and_metric_name(method, name)
|
116
|
-
|
143
|
+
|
144
|
+
# Unfortunately, we have to inline the new method implementation ebcause we have to fix the
|
145
|
+
# Stats.increment call to not use the `prefix` argument.
|
146
|
+
|
147
|
+
add_to_method(method, name, :count_success) do
|
148
|
+
define_method(method) do |*args, &block|
|
149
|
+
begin
|
150
|
+
truthiness = result = super(*args, &block)
|
151
|
+
rescue
|
152
|
+
truthiness = false
|
153
|
+
raise
|
154
|
+
else
|
155
|
+
if block_given?
|
156
|
+
begin
|
157
|
+
truthiness = yield(result)
|
158
|
+
rescue
|
159
|
+
truthiness = false
|
160
|
+
end
|
161
|
+
end
|
162
|
+
result
|
163
|
+
ensure
|
164
|
+
suffix = truthiness == false ? 'failure' : 'success'
|
165
|
+
key = "#{StatsD::Instrument.generate_metric_name(name, self, *args)}.#{suffix}"
|
166
|
+
StatsD.increment(key, sample_rate: sample_rate, tags: tags, no_prefix: no_prefix)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
117
170
|
end
|
118
171
|
|
119
|
-
def statsd_count_if(method, name, sample_rate: nil, tags: nil,
|
172
|
+
def statsd_count_if(method, name, sample_rate: nil, tags: nil, no_prefix: false)
|
120
173
|
check_method_and_metric_name(method, name)
|
121
|
-
|
174
|
+
|
175
|
+
# Unfortunately, we have to inline the new method implementation ebcause we have to fix the
|
176
|
+
# Stats.increment call to not use the `prefix` argument.
|
177
|
+
|
178
|
+
add_to_method(method, name, :count_if) do
|
179
|
+
define_method(method) do |*args, &block|
|
180
|
+
begin
|
181
|
+
truthiness = result = super(*args, &block)
|
182
|
+
rescue
|
183
|
+
truthiness = false
|
184
|
+
raise
|
185
|
+
else
|
186
|
+
if block_given?
|
187
|
+
begin
|
188
|
+
truthiness = yield(result)
|
189
|
+
rescue
|
190
|
+
truthiness = false
|
191
|
+
end
|
192
|
+
end
|
193
|
+
result
|
194
|
+
ensure
|
195
|
+
if truthiness
|
196
|
+
key = StatsD::Instrument.generate_metric_name(name, self, *args)
|
197
|
+
StatsD.increment(key, sample_rate: sample_rate, tags: tags, no_prefix: no_prefix)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
122
202
|
end
|
123
203
|
|
124
|
-
def statsd_count(method, name, sample_rate: nil, tags: nil,
|
204
|
+
def statsd_count(method, name, sample_rate: nil, tags: nil, no_prefix: false)
|
125
205
|
check_method_and_metric_name(method, name)
|
126
|
-
|
206
|
+
|
207
|
+
# Unfortunately, we have to inline the new method implementation ebcause we have to fix the
|
208
|
+
# Stats.increment call to not use the `prefix` argument.
|
209
|
+
|
210
|
+
add_to_method(method, name, :count) do
|
211
|
+
define_method(method) do |*args, &block|
|
212
|
+
key = StatsD::Instrument.generate_metric_name(name, self, *args)
|
213
|
+
StatsD.increment(key, sample_rate: sample_rate, tags: tags, no_prefix: no_prefix)
|
214
|
+
super(*args, &block)
|
215
|
+
end
|
216
|
+
end
|
127
217
|
end
|
128
218
|
|
129
219
|
private
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @note This class is part of the new Client implementation that is intended
|
4
|
+
# to become the new default in the next major release of this library.
|
5
|
+
class StatsD::Instrument::UDPSink
|
6
|
+
def self.for_addr(addr)
|
7
|
+
host, port_as_string = addr.split(':', 2)
|
8
|
+
new(host, Integer(port_as_string))
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :host, :port
|
12
|
+
|
13
|
+
def initialize(host, port)
|
14
|
+
@host = host
|
15
|
+
@port = port
|
16
|
+
@mutex = Mutex.new
|
17
|
+
@socket = nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def sample?(sample_rate)
|
21
|
+
sample_rate == 1 || rand < sample_rate
|
22
|
+
end
|
23
|
+
|
24
|
+
def <<(datagram)
|
25
|
+
with_socket { |socket| socket.send(datagram, 0) > 0 }
|
26
|
+
self
|
27
|
+
|
28
|
+
rescue ThreadError
|
29
|
+
# In cases where a TERM or KILL signal has been sent, and we send stats as
|
30
|
+
# part of a signal handler, locks cannot be acquired, so we do our best
|
31
|
+
# to try and send the datagram without a lock.
|
32
|
+
socket.send(datagram, 0) > 0
|
33
|
+
|
34
|
+
rescue SocketError, IOError, SystemCallError
|
35
|
+
# TODO: log?
|
36
|
+
invalidate_socket
|
37
|
+
end
|
38
|
+
|
39
|
+
def addr
|
40
|
+
"#{host}:#{port}"
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def with_socket
|
46
|
+
@mutex.synchronize { yield(socket) }
|
47
|
+
end
|
48
|
+
|
49
|
+
def socket
|
50
|
+
if @socket.nil?
|
51
|
+
@socket = UDPSocket.new
|
52
|
+
@socket.connect(@host, @port)
|
53
|
+
end
|
54
|
+
@socket
|
55
|
+
end
|
56
|
+
|
57
|
+
def invalidate_socket
|
58
|
+
@mutex.synchronize do
|
59
|
+
@socket = nil
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|