statsd-ruby 1.1.1 → 1.5.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 +7 -0
- data/.github/workflows/ci.yml +34 -0
- data/LICENSE.txt +1 -1
- data/README.rdoc +37 -12
- data/lib/statsd-ruby.rb +1 -0
- data/lib/statsd.rb +273 -17
- data/lib/statsd/monotonic_time.rb +35 -0
- data/spec/helper.rb +12 -3
- data/spec/statsd_admin_spec.rb +117 -0
- data/spec/statsd_spec.rb +321 -71
- data/statsd-ruby.gemspec +4 -4
- metadata +106 -93
- data/.travis.yml +0 -6
@@ -0,0 +1,35 @@
|
|
1
|
+
class Statsd
|
2
|
+
# = MonotonicTime: a helper for getting monotonic time
|
3
|
+
#
|
4
|
+
# @example
|
5
|
+
# MonotonicTime.time_in_ms #=> 287138801.144576
|
6
|
+
|
7
|
+
# MonotonicTime guarantees that the time is strictly linearly
|
8
|
+
# increasing (unlike realtime).
|
9
|
+
# @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html
|
10
|
+
module MonotonicTime
|
11
|
+
class << self
|
12
|
+
# @return [Integer] current monotonic time in milliseconds
|
13
|
+
def time_in_ms
|
14
|
+
time_in_nanoseconds / (10.0 ** 6)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
if defined?(Process::CLOCK_MONOTONIC)
|
20
|
+
def time_in_nanoseconds
|
21
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC, :nanosecond)
|
22
|
+
end
|
23
|
+
elsif RUBY_ENGINE == 'jruby'
|
24
|
+
def time_in_nanoseconds
|
25
|
+
java.lang.System.nanoTime
|
26
|
+
end
|
27
|
+
else
|
28
|
+
def time_in_nanoseconds
|
29
|
+
t = Time.now
|
30
|
+
t.to_i * (10 ** 9) + t.nsec
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/spec/helper.rb
CHANGED
@@ -1,19 +1,21 @@
|
|
1
1
|
require 'bundler/setup'
|
2
|
-
require 'minitest/autorun'
|
3
2
|
|
4
3
|
require 'simplecov'
|
5
4
|
SimpleCov.start
|
6
5
|
|
6
|
+
require 'minitest/autorun'
|
7
7
|
require 'statsd'
|
8
8
|
require 'logger'
|
9
|
+
require 'timeout'
|
9
10
|
|
10
11
|
class FakeUDPSocket
|
11
12
|
def initialize
|
12
13
|
@buffer = []
|
13
14
|
end
|
14
15
|
|
15
|
-
def
|
16
|
+
def write(message)
|
16
17
|
@buffer.push [message]
|
18
|
+
message.length
|
17
19
|
end
|
18
20
|
|
19
21
|
def recv
|
@@ -29,6 +31,13 @@ class FakeUDPSocket
|
|
29
31
|
end
|
30
32
|
|
31
33
|
def inspect
|
32
|
-
"
|
34
|
+
"<#{self.class.name}: #{@buffer.inspect}>"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class FakeTCPSocket < FakeUDPSocket
|
39
|
+
alias_method :readline, :recv
|
40
|
+
def write(message)
|
41
|
+
@buffer.push message
|
33
42
|
end
|
34
43
|
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe Statsd::Admin do
|
4
|
+
|
5
|
+
before do
|
6
|
+
class Statsd::Admin
|
7
|
+
o, $VERBOSE = $VERBOSE, nil
|
8
|
+
alias connect_old connect
|
9
|
+
def connect
|
10
|
+
$connect_count ||= 0
|
11
|
+
$connect_count += 1
|
12
|
+
end
|
13
|
+
$VERBOSE = o
|
14
|
+
end
|
15
|
+
@admin = Statsd::Admin.new('localhost', 1234)
|
16
|
+
@socket = @admin.instance_variable_set(:@socket, FakeTCPSocket.new)
|
17
|
+
end
|
18
|
+
|
19
|
+
after do
|
20
|
+
class Statsd::Admin
|
21
|
+
o, $VERBOSE = $VERBOSE, nil
|
22
|
+
alias connect connect_old
|
23
|
+
$VERBOSE = o
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "#initialize" do
|
28
|
+
it "should set the host and port" do
|
29
|
+
_(@admin.host).must_equal 'localhost'
|
30
|
+
_(@admin.port).must_equal 1234
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should default the host to 127.0.0.1 and port to 8126" do
|
34
|
+
statsd = Statsd::Admin.new
|
35
|
+
_(statsd.host).must_equal '127.0.0.1'
|
36
|
+
_(statsd.port).must_equal 8126
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "#host and #port" do
|
41
|
+
it "should set host and port" do
|
42
|
+
@admin.host = '1.2.3.4'
|
43
|
+
@admin.port = 5678
|
44
|
+
_(@admin.host).must_equal '1.2.3.4'
|
45
|
+
_(@admin.port).must_equal 5678
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should not resolve hostnames to IPs" do
|
49
|
+
@admin.host = 'localhost'
|
50
|
+
_(@admin.host).must_equal 'localhost'
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should set nil host to default" do
|
54
|
+
@admin.host = nil
|
55
|
+
_(@admin.host).must_equal '127.0.0.1'
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should set nil port to default" do
|
59
|
+
@admin.port = nil
|
60
|
+
_(@admin.port).must_equal 8126
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
%w(gauges counters timers).each do |action|
|
65
|
+
describe "##{action}" do
|
66
|
+
it "should send a command and return a Hash" do
|
67
|
+
["{'foo.bar': 0,\n",
|
68
|
+
"'foo.baz': 1,\n",
|
69
|
+
"'foo.quux': 2 }\n",
|
70
|
+
"END\n","\n"].each do |line|
|
71
|
+
@socket.write line
|
72
|
+
end
|
73
|
+
result = @admin.send action.to_sym
|
74
|
+
_(result).must_be_kind_of Hash
|
75
|
+
_(result.size).must_equal 3
|
76
|
+
_(@socket.readline).must_equal "#{action}\n"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "#del#{action}" do
|
81
|
+
it "should send a command and return an Array" do
|
82
|
+
["deleted: foo.bar\n",
|
83
|
+
"deleted: foo.baz\n",
|
84
|
+
"deleted: foo.quux\n",
|
85
|
+
"END\n", "\n"].each do |line|
|
86
|
+
@socket.write line
|
87
|
+
end
|
88
|
+
result = @admin.send "del#{action}", "foo.*"
|
89
|
+
_(result).must_be_kind_of Array
|
90
|
+
_(result.size).must_equal 3
|
91
|
+
_(@socket.readline).must_equal "del#{action} foo.*\n"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe "#stats" do
|
97
|
+
it "should send a command and return a Hash" do
|
98
|
+
["whatever: 0\n", "END\n", "\n"].each do |line|
|
99
|
+
@socket.write line
|
100
|
+
end
|
101
|
+
result = @admin.stats
|
102
|
+
_(result).must_be_kind_of Hash
|
103
|
+
_(result["whatever"]).must_equal 0
|
104
|
+
_(@socket.readline).must_equal "stats\n"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe "#connect" do
|
109
|
+
it "should reconnect" do
|
110
|
+
c = $connect_count
|
111
|
+
@admin.connect
|
112
|
+
_(($connect_count - c)).must_equal 1
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
|
data/spec/statsd_spec.rb
CHANGED
@@ -1,27 +1,43 @@
|
|
1
1
|
require 'helper'
|
2
2
|
|
3
3
|
describe Statsd do
|
4
|
-
class Statsd
|
5
|
-
public :socket
|
6
|
-
end
|
7
|
-
|
8
4
|
before do
|
5
|
+
class Statsd
|
6
|
+
o, $VERBOSE = $VERBOSE, nil
|
7
|
+
alias connect_old connect
|
8
|
+
def connect
|
9
|
+
$connect_count ||= 1
|
10
|
+
$connect_count += 1
|
11
|
+
end
|
12
|
+
$VERBOSE = o
|
13
|
+
end
|
14
|
+
|
9
15
|
@statsd = Statsd.new('localhost', 1234)
|
10
|
-
@socket =
|
16
|
+
@socket = @statsd.instance_variable_set(:@socket, FakeUDPSocket.new)
|
11
17
|
end
|
12
18
|
|
13
|
-
after
|
19
|
+
after do
|
20
|
+
class Statsd
|
21
|
+
o, $VERBOSE = $VERBOSE, nil
|
22
|
+
alias connect connect_old
|
23
|
+
$VERBOSE = o
|
24
|
+
end
|
25
|
+
end
|
14
26
|
|
15
27
|
describe "#initialize" do
|
16
28
|
it "should set the host and port" do
|
17
|
-
@statsd.host.must_equal 'localhost'
|
18
|
-
@statsd.port.must_equal 1234
|
29
|
+
_(@statsd.host).must_equal 'localhost'
|
30
|
+
_(@statsd.port).must_equal 1234
|
19
31
|
end
|
20
32
|
|
21
33
|
it "should default the host to 127.0.0.1 and port to 8125" do
|
22
34
|
statsd = Statsd.new
|
23
|
-
statsd.host.must_equal '127.0.0.1'
|
24
|
-
statsd.port.must_equal 8125
|
35
|
+
_(statsd.host).must_equal '127.0.0.1'
|
36
|
+
_(statsd.port).must_equal 8125
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should set delimiter to period by default" do
|
40
|
+
_(@statsd.delimiter).must_equal "."
|
25
41
|
end
|
26
42
|
end
|
27
43
|
|
@@ -29,37 +45,54 @@ describe Statsd do
|
|
29
45
|
it "should set host and port" do
|
30
46
|
@statsd.host = '1.2.3.4'
|
31
47
|
@statsd.port = 5678
|
32
|
-
@statsd.host.must_equal '1.2.3.4'
|
33
|
-
@statsd.port.must_equal 5678
|
48
|
+
_(@statsd.host).must_equal '1.2.3.4'
|
49
|
+
_(@statsd.port).must_equal 5678
|
34
50
|
end
|
35
51
|
|
36
52
|
it "should not resolve hostnames to IPs" do
|
37
53
|
@statsd.host = 'localhost'
|
38
|
-
@statsd.host.must_equal 'localhost'
|
54
|
+
_(@statsd.host).must_equal 'localhost'
|
39
55
|
end
|
40
56
|
|
41
57
|
it "should set nil host to default" do
|
42
58
|
@statsd.host = nil
|
43
|
-
@statsd.host.must_equal '127.0.0.1'
|
59
|
+
_(@statsd.host).must_equal '127.0.0.1'
|
44
60
|
end
|
45
61
|
|
46
62
|
it "should set nil port to default" do
|
47
63
|
@statsd.port = nil
|
48
|
-
@statsd.port.must_equal 8125
|
64
|
+
_(@statsd.port).must_equal 8125
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should allow an IPv6 address" do
|
68
|
+
@statsd.host = '::1'
|
69
|
+
_(@statsd.host).must_equal '::1'
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "#delimiter" do
|
74
|
+
it "should set delimiter" do
|
75
|
+
@statsd.delimiter = "-"
|
76
|
+
_(@statsd.delimiter).must_equal "-"
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should set default to period if not given a value" do
|
80
|
+
@statsd.delimiter = nil
|
81
|
+
_(@statsd.delimiter).must_equal "."
|
49
82
|
end
|
50
83
|
end
|
51
84
|
|
52
85
|
describe "#increment" do
|
53
86
|
it "should format the message according to the statsd spec" do
|
54
87
|
@statsd.increment('foobar')
|
55
|
-
@socket.recv.must_equal ['foobar:1|c']
|
88
|
+
_(@socket.recv).must_equal ['foobar:1|c']
|
56
89
|
end
|
57
90
|
|
58
91
|
describe "with a sample rate" do
|
59
92
|
before { class << @statsd; def rand; 0; end; end } # ensure delivery
|
60
93
|
it "should format the message according to the statsd spec" do
|
61
94
|
@statsd.increment('foobar', 0.5)
|
62
|
-
@socket.recv.must_equal ['foobar:1|c|@0.5']
|
95
|
+
_(@socket.recv).must_equal ['foobar:1|c|@0.5']
|
63
96
|
end
|
64
97
|
end
|
65
98
|
end
|
@@ -67,14 +100,14 @@ describe Statsd do
|
|
67
100
|
describe "#decrement" do
|
68
101
|
it "should format the message according to the statsd spec" do
|
69
102
|
@statsd.decrement('foobar')
|
70
|
-
@socket.recv.must_equal ['foobar:-1|c']
|
103
|
+
_(@socket.recv).must_equal ['foobar:-1|c']
|
71
104
|
end
|
72
105
|
|
73
106
|
describe "with a sample rate" do
|
74
107
|
before { class << @statsd; def rand; 0; end; end } # ensure delivery
|
75
108
|
it "should format the message according to the statsd spec" do
|
76
109
|
@statsd.decrement('foobar', 0.5)
|
77
|
-
@socket.recv.must_equal ['foobar:-1|c|@0.5']
|
110
|
+
_(@socket.recv).must_equal ['foobar:-1|c|@0.5']
|
78
111
|
end
|
79
112
|
end
|
80
113
|
end
|
@@ -82,16 +115,16 @@ describe Statsd do
|
|
82
115
|
describe "#gauge" do
|
83
116
|
it "should send a message with a 'g' type, per the nearbuy fork" do
|
84
117
|
@statsd.gauge('begrutten-suffusion', 536)
|
85
|
-
@socket.recv.must_equal ['begrutten-suffusion:536|g']
|
118
|
+
_(@socket.recv).must_equal ['begrutten-suffusion:536|g']
|
86
119
|
@statsd.gauge('begrutten-suffusion', -107.3)
|
87
|
-
@socket.recv.must_equal ['begrutten-suffusion:-107.3|g']
|
120
|
+
_(@socket.recv).must_equal ['begrutten-suffusion:-107.3|g']
|
88
121
|
end
|
89
122
|
|
90
123
|
describe "with a sample rate" do
|
91
124
|
before { class << @statsd; def rand; 0; end; end } # ensure delivery
|
92
125
|
it "should format the message according to the statsd spec" do
|
93
126
|
@statsd.gauge('begrutten-suffusion', 536, 0.1)
|
94
|
-
@socket.recv.must_equal ['begrutten-suffusion:536|g|@0.1']
|
127
|
+
_(@socket.recv).must_equal ['begrutten-suffusion:536|g|@0.1']
|
95
128
|
end
|
96
129
|
end
|
97
130
|
end
|
@@ -99,14 +132,29 @@ describe Statsd do
|
|
99
132
|
describe "#timing" do
|
100
133
|
it "should format the message according to the statsd spec" do
|
101
134
|
@statsd.timing('foobar', 500)
|
102
|
-
@socket.recv.must_equal ['foobar:500|ms']
|
135
|
+
_(@socket.recv).must_equal ['foobar:500|ms']
|
103
136
|
end
|
104
137
|
|
105
138
|
describe "with a sample rate" do
|
106
139
|
before { class << @statsd; def rand; 0; end; end } # ensure delivery
|
107
140
|
it "should format the message according to the statsd spec" do
|
108
141
|
@statsd.timing('foobar', 500, 0.5)
|
109
|
-
@socket.recv.must_equal ['foobar:500|ms|@0.5']
|
142
|
+
_(@socket.recv).must_equal ['foobar:500|ms|@0.5']
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
describe "#set" do
|
148
|
+
it "should format the message according to the statsd spec" do
|
149
|
+
@statsd.set('foobar', 765)
|
150
|
+
_(@socket.recv).must_equal ['foobar:765|s']
|
151
|
+
end
|
152
|
+
|
153
|
+
describe "with a sample rate" do
|
154
|
+
before { class << @statsd; def rand; 0; end; end } # ensure delivery
|
155
|
+
it "should format the message according to the statsd spec" do
|
156
|
+
@statsd.set('foobar', 500, 0.5)
|
157
|
+
_(@socket.recv).must_equal ['foobar:500|s|@0.5']
|
110
158
|
end
|
111
159
|
end
|
112
160
|
end
|
@@ -114,12 +162,24 @@ describe Statsd do
|
|
114
162
|
describe "#time" do
|
115
163
|
it "should format the message according to the statsd spec" do
|
116
164
|
@statsd.time('foobar') { 'test' }
|
117
|
-
@socket.recv.must_equal ['foobar:0|ms']
|
165
|
+
_(@socket.recv).must_equal ['foobar:0|ms']
|
118
166
|
end
|
119
167
|
|
120
168
|
it "should return the result of the block" do
|
121
169
|
result = @statsd.time('foobar') { 'test' }
|
122
|
-
result.must_equal 'test'
|
170
|
+
_(result).must_equal 'test'
|
171
|
+
end
|
172
|
+
|
173
|
+
describe "when given a block with an explicit return" do
|
174
|
+
it "should format the message according to the statsd spec" do
|
175
|
+
lambda { @statsd.time('foobar') { return 'test' } }.call
|
176
|
+
_(@socket.recv).must_equal ['foobar:0|ms']
|
177
|
+
end
|
178
|
+
|
179
|
+
it "should return the result of the block" do
|
180
|
+
result = lambda { @statsd.time('foobar') { return 'test' } }.call
|
181
|
+
_(result).must_equal 'test'
|
182
|
+
end
|
123
183
|
end
|
124
184
|
|
125
185
|
describe "with a sample rate" do
|
@@ -127,7 +187,7 @@ describe Statsd do
|
|
127
187
|
|
128
188
|
it "should format the message according to the statsd spec" do
|
129
189
|
@statsd.time('foobar', 0.5) { 'test' }
|
130
|
-
@socket.recv.must_equal ['foobar:0|ms|@0.5']
|
190
|
+
_(@socket.recv).must_equal ['foobar:0|ms|@0.5']
|
131
191
|
end
|
132
192
|
end
|
133
193
|
end
|
@@ -137,7 +197,7 @@ describe Statsd do
|
|
137
197
|
before { class << @statsd; def rand; raise end; end }
|
138
198
|
it "should send" do
|
139
199
|
@statsd.timing('foobar', 500, 1)
|
140
|
-
@socket.recv.must_equal ['foobar:500|ms']
|
200
|
+
_(@socket.recv).must_equal ['foobar:500|ms']
|
141
201
|
end
|
142
202
|
end
|
143
203
|
|
@@ -145,14 +205,14 @@ describe Statsd do
|
|
145
205
|
before { class << @statsd; def rand; 0; end; end } # ensure delivery
|
146
206
|
it "should send" do
|
147
207
|
@statsd.timing('foobar', 500, 0.5)
|
148
|
-
@socket.recv.must_equal ['foobar:500|ms|@0.5']
|
208
|
+
_(@socket.recv).must_equal ['foobar:500|ms|@0.5']
|
149
209
|
end
|
150
210
|
end
|
151
211
|
|
152
212
|
describe "when the sample rate is less than a random value [0,1]" do
|
153
213
|
before { class << @statsd; def rand; 1; end; end } # ensure no delivery
|
154
214
|
it "should not send" do
|
155
|
-
@statsd.timing('foobar', 500, 0.5)
|
215
|
+
assert_nil @statsd.timing('foobar', 500, 0.5)
|
156
216
|
end
|
157
217
|
end
|
158
218
|
|
@@ -160,7 +220,7 @@ describe Statsd do
|
|
160
220
|
before { class << @statsd; def rand; 0; end; end } # ensure delivery
|
161
221
|
it "should send" do
|
162
222
|
@statsd.timing('foobar', 500, 0.5)
|
163
|
-
@socket.recv.must_equal ['foobar:500|ms|@0.5']
|
223
|
+
_(@socket.recv).must_equal ['foobar:500|ms|@0.5']
|
164
224
|
end
|
165
225
|
end
|
166
226
|
end
|
@@ -170,22 +230,22 @@ describe Statsd do
|
|
170
230
|
|
171
231
|
it "should add namespace to increment" do
|
172
232
|
@statsd.increment('foobar')
|
173
|
-
@socket.recv.must_equal ['service.foobar:1|c']
|
233
|
+
_(@socket.recv).must_equal ['service.foobar:1|c']
|
174
234
|
end
|
175
235
|
|
176
236
|
it "should add namespace to decrement" do
|
177
237
|
@statsd.decrement('foobar')
|
178
|
-
@socket.recv.must_equal ['service.foobar:-1|c']
|
238
|
+
_(@socket.recv).must_equal ['service.foobar:-1|c']
|
179
239
|
end
|
180
240
|
|
181
241
|
it "should add namespace to timing" do
|
182
242
|
@statsd.timing('foobar', 500)
|
183
|
-
@socket.recv.must_equal ['service.foobar:500|ms']
|
243
|
+
_(@socket.recv).must_equal ['service.foobar:500|ms']
|
184
244
|
end
|
185
245
|
|
186
246
|
it "should add namespace to gauge" do
|
187
247
|
@statsd.gauge('foobar', 500)
|
188
|
-
@socket.recv.must_equal ['service.foobar:500|g']
|
248
|
+
_(@socket.recv).must_equal ['service.foobar:500|g']
|
189
249
|
end
|
190
250
|
end
|
191
251
|
|
@@ -194,22 +254,22 @@ describe Statsd do
|
|
194
254
|
|
195
255
|
it "should add postfix to increment" do
|
196
256
|
@statsd.increment('foobar')
|
197
|
-
@socket.recv.must_equal ['foobar.ip-23-45-56-78:1|c']
|
257
|
+
_(@socket.recv).must_equal ['foobar.ip-23-45-56-78:1|c']
|
198
258
|
end
|
199
259
|
|
200
260
|
it "should add postfix to decrement" do
|
201
261
|
@statsd.decrement('foobar')
|
202
|
-
@socket.recv.must_equal ['foobar.ip-23-45-56-78:-1|c']
|
262
|
+
_(@socket.recv).must_equal ['foobar.ip-23-45-56-78:-1|c']
|
203
263
|
end
|
204
264
|
|
205
265
|
it "should add namespace to timing" do
|
206
266
|
@statsd.timing('foobar', 500)
|
207
|
-
@socket.recv.must_equal ['foobar.ip-23-45-56-78:500|ms']
|
267
|
+
_(@socket.recv).must_equal ['foobar.ip-23-45-56-78:500|ms']
|
208
268
|
end
|
209
269
|
|
210
270
|
it "should add namespace to gauge" do
|
211
271
|
@statsd.gauge('foobar', 500)
|
212
|
-
@socket.recv.must_equal ['foobar.ip-23-45-56-78:500|g']
|
272
|
+
_(@socket.recv).must_equal ['foobar.ip-23-45-56-78:500|g']
|
213
273
|
end
|
214
274
|
end
|
215
275
|
|
@@ -219,7 +279,7 @@ describe Statsd do
|
|
219
279
|
[nil, false, ''].each do |value|
|
220
280
|
@statsd.postfix = 'a postfix'
|
221
281
|
@statsd.postfix = value
|
222
|
-
@statsd.postfix
|
282
|
+
assert_nil @statsd.postfix
|
223
283
|
end
|
224
284
|
end
|
225
285
|
end
|
@@ -234,7 +294,7 @@ describe Statsd do
|
|
234
294
|
|
235
295
|
@statsd.increment('foobar')
|
236
296
|
|
237
|
-
@log.string.must_match "Statsd: foobar:1|c"
|
297
|
+
_(@log.string).must_match "Statsd: foobar:1|c"
|
238
298
|
end
|
239
299
|
|
240
300
|
it "should not write to the log unless debug" do
|
@@ -242,7 +302,7 @@ describe Statsd do
|
|
242
302
|
|
243
303
|
@statsd.increment('foobar')
|
244
304
|
|
245
|
-
@log.string.must_be_empty
|
305
|
+
_(@log.string).must_be_empty
|
246
306
|
end
|
247
307
|
end
|
248
308
|
|
@@ -255,12 +315,25 @@ describe Statsd do
|
|
255
315
|
class Statsd::SomeClass; end
|
256
316
|
@statsd.increment(Statsd::SomeClass, 1)
|
257
317
|
|
258
|
-
@socket.recv.must_equal ['Statsd.SomeClass:1|c']
|
318
|
+
_(@socket.recv).must_equal ['Statsd.SomeClass:1|c']
|
319
|
+
end
|
320
|
+
|
321
|
+
describe "custom delimiter" do
|
322
|
+
before do
|
323
|
+
@statsd.delimiter = "-"
|
324
|
+
end
|
325
|
+
|
326
|
+
it "should replace ruby constant delimiter with custom delimiter" do
|
327
|
+
class Statsd::SomeOtherClass; end
|
328
|
+
@statsd.increment(Statsd::SomeOtherClass, 1)
|
329
|
+
|
330
|
+
_(@socket.recv).must_equal ['Statsd-SomeOtherClass:1|c']
|
331
|
+
end
|
259
332
|
end
|
260
333
|
|
261
334
|
it "should replace statsd reserved chars in the stat name" do
|
262
335
|
@statsd.increment('ray@hostname.blah|blah.blah:blah', 1)
|
263
|
-
@socket.recv.must_equal ['ray_hostname.blah_blah.blah_blah:1|c']
|
336
|
+
_(@socket.recv).must_equal ['ray_hostname.blah_blah.blah_blah:1|c']
|
264
337
|
end
|
265
338
|
end
|
266
339
|
|
@@ -268,29 +341,61 @@ describe Statsd do
|
|
268
341
|
before do
|
269
342
|
require 'stringio'
|
270
343
|
Statsd.logger = Logger.new(@log = StringIO.new)
|
271
|
-
@socket.
|
344
|
+
@socket.instance_variable_set(:@err_count, 0)
|
345
|
+
@socket.instance_eval { def write(*) @err_count+=1; raise SocketError end }
|
272
346
|
end
|
273
347
|
|
274
348
|
it "should ignore socket errors" do
|
275
|
-
@statsd.increment('foobar')
|
349
|
+
assert_nil @statsd.increment('foobar')
|
276
350
|
end
|
277
351
|
|
278
352
|
it "should log socket errors" do
|
279
353
|
@statsd.increment('foobar')
|
280
|
-
@log.string.must_match 'Statsd: SocketError'
|
354
|
+
_(@log.string).must_match 'Statsd: SocketError'
|
355
|
+
end
|
356
|
+
|
357
|
+
it "should retry and reconnect on socket errors" do
|
358
|
+
$connect_count = 0
|
359
|
+
@statsd.increment('foobar')
|
360
|
+
_(@socket.instance_variable_get(:@err_count)).must_equal 5
|
361
|
+
_($connect_count).must_equal 5
|
281
362
|
end
|
282
363
|
end
|
283
364
|
|
284
365
|
describe "batching" do
|
285
366
|
it "should have a default batch size of 10" do
|
286
|
-
@statsd.batch_size.must_equal 10
|
367
|
+
_(@statsd.batch_size).must_equal 10
|
368
|
+
end
|
369
|
+
|
370
|
+
it "should have a default batch byte size of nil" do
|
371
|
+
assert_nil @statsd.batch_byte_size
|
372
|
+
end
|
373
|
+
|
374
|
+
it "should have a default flush interval of nil" do
|
375
|
+
assert_nil @statsd.flush_interval
|
287
376
|
end
|
288
377
|
|
289
378
|
it "should have a modifiable batch size" do
|
290
379
|
@statsd.batch_size = 7
|
291
|
-
@statsd.batch_size.must_equal 7
|
380
|
+
_(@statsd.batch_size).must_equal 7
|
381
|
+
@statsd.batch do |b|
|
382
|
+
_(b.batch_size).must_equal 7
|
383
|
+
end
|
384
|
+
|
385
|
+
@statsd.batch_size = nil
|
386
|
+
@statsd.batch_byte_size = 1472
|
387
|
+
@statsd.batch do |b|
|
388
|
+
assert_nil b.batch_size
|
389
|
+
_(b.batch_byte_size).must_equal 1472
|
390
|
+
end
|
391
|
+
|
392
|
+
end
|
393
|
+
|
394
|
+
it 'should have a modifiable flush interval' do
|
395
|
+
@statsd.flush_interval = 1
|
396
|
+
_(@statsd.flush_interval).must_equal 1
|
292
397
|
@statsd.batch do |b|
|
293
|
-
b.
|
398
|
+
_(b.flush_interval).must_equal 1
|
294
399
|
end
|
295
400
|
end
|
296
401
|
|
@@ -302,50 +407,195 @@ describe Statsd do
|
|
302
407
|
# block is done.
|
303
408
|
5.times { b.increment('foobar') }
|
304
409
|
|
305
|
-
@socket.recv.must_equal [(["foobar:1|c"] * 3).join("\n")]
|
410
|
+
_(@socket.recv).must_equal [(["foobar:1|c"] * 3).join("\n")]
|
306
411
|
end
|
307
412
|
|
308
|
-
@socket.recv.must_equal [(["foobar:1|c"] * 2).join("\n")]
|
413
|
+
_(@socket.recv).must_equal [(["foobar:1|c"] * 2).join("\n")]
|
414
|
+
end
|
415
|
+
|
416
|
+
it "should flush based on batch byte size" do
|
417
|
+
@statsd.batch do |b|
|
418
|
+
b.batch_size = nil
|
419
|
+
b.batch_byte_size = 22
|
420
|
+
|
421
|
+
# The first two should flush, the last will be flushed when the
|
422
|
+
# block is done.
|
423
|
+
3.times { b.increment('foobar') }
|
424
|
+
|
425
|
+
_(@socket.recv).must_equal [(["foobar:1|c"] * 2).join("\n")]
|
426
|
+
end
|
427
|
+
|
428
|
+
_(@socket.recv).must_equal ["foobar:1|c"]
|
429
|
+
end
|
430
|
+
|
431
|
+
it "should flush immediately when the queue is exactly a batch size" do
|
432
|
+
@statsd.batch do |b|
|
433
|
+
b.batch_size = nil
|
434
|
+
b.batch_byte_size = 21
|
435
|
+
|
436
|
+
# The first two should flush together
|
437
|
+
2.times { b.increment('foobar') }
|
438
|
+
|
439
|
+
_(@socket.recv).must_equal [(["foobar:1|c"] * 2).join("\n")]
|
440
|
+
end
|
441
|
+
end
|
442
|
+
|
443
|
+
it "should flush when the interval has passed" do
|
444
|
+
@statsd.batch do |b|
|
445
|
+
b.batch_size = nil
|
446
|
+
b.flush_interval = 0.01
|
447
|
+
|
448
|
+
# The first two should flush, the last will be flushed when the
|
449
|
+
# block is done.
|
450
|
+
2.times { b.increment('foobar') }
|
451
|
+
sleep(0.03)
|
452
|
+
b.increment('foobar')
|
453
|
+
|
454
|
+
_(@socket.recv).must_equal [(["foobar:1|c"] * 2).join("\n")]
|
455
|
+
end
|
456
|
+
|
457
|
+
_(@socket.recv).must_equal ["foobar:1|c"]
|
309
458
|
end
|
310
459
|
|
311
460
|
it "should not flush to the socket if the backlog is empty" do
|
312
461
|
batch = Statsd::Batch.new(@statsd)
|
313
462
|
batch.flush
|
314
|
-
@socket.recv.must_be :nil?
|
463
|
+
_(@socket.recv).must_be :nil?
|
315
464
|
|
316
465
|
batch.increment 'foobar'
|
317
466
|
batch.flush
|
318
|
-
@socket.recv.must_equal %w[foobar:1|c]
|
467
|
+
_(@socket.recv).must_equal %w[foobar:1|c]
|
319
468
|
end
|
320
469
|
|
321
|
-
|
322
|
-
|
323
|
-
|
470
|
+
it "should support setting namespace for the underlying instance" do
|
471
|
+
batch = Statsd::Batch.new(@statsd)
|
472
|
+
batch.namespace = 'ns'
|
473
|
+
_(@statsd.namespace).must_equal 'ns'
|
474
|
+
end
|
324
475
|
|
325
|
-
it "should
|
326
|
-
|
327
|
-
|
476
|
+
it "should support setting host for the underlying instance" do
|
477
|
+
batch = Statsd::Batch.new(@statsd)
|
478
|
+
batch.host = '1.2.3.4'
|
479
|
+
_(@statsd.host).must_equal '1.2.3.4'
|
328
480
|
end
|
329
481
|
|
330
|
-
it "should
|
331
|
-
|
332
|
-
|
482
|
+
it "should support setting port for the underlying instance" do
|
483
|
+
batch = Statsd::Batch.new(@statsd)
|
484
|
+
batch.port = 42
|
485
|
+
_(@statsd.port).must_equal 42
|
333
486
|
end
|
334
487
|
|
335
488
|
end
|
489
|
+
|
490
|
+
describe "#connect" do
|
491
|
+
it "should reconnect" do
|
492
|
+
c = $connect_count
|
493
|
+
@statsd.connect
|
494
|
+
_(($connect_count - c)).must_equal 1
|
495
|
+
end
|
496
|
+
end
|
497
|
+
|
336
498
|
end
|
337
499
|
|
338
500
|
describe Statsd do
|
339
501
|
describe "with a real UDP socket" do
|
340
502
|
it "should actually send stuff over the socket" do
|
341
|
-
|
342
|
-
|
343
|
-
|
503
|
+
family = Addrinfo.udp(UDPSocket.getaddress('localhost'), 0).afamily
|
504
|
+
begin
|
505
|
+
socket = UDPSocket.new family
|
506
|
+
host, port = 'localhost', 0
|
507
|
+
socket.bind(host, port)
|
508
|
+
port = socket.addr[1]
|
509
|
+
|
510
|
+
statsd = Statsd.new(host, port)
|
511
|
+
statsd.increment('foobar')
|
512
|
+
message = socket.recvfrom(16).first
|
513
|
+
_(message).must_equal 'foobar:1|c'
|
514
|
+
ensure
|
515
|
+
socket.close
|
516
|
+
end
|
517
|
+
end
|
518
|
+
|
519
|
+
it "should send stuff over an IPv4 socket" do
|
520
|
+
begin
|
521
|
+
socket = UDPSocket.new Socket::AF_INET
|
522
|
+
host, port = '127.0.0.1', 0
|
523
|
+
socket.bind(host, port)
|
524
|
+
port = socket.addr[1]
|
525
|
+
|
526
|
+
statsd = Statsd.new(host, port)
|
527
|
+
statsd.increment('foobar')
|
528
|
+
message = socket.recvfrom(16).first
|
529
|
+
_(message).must_equal 'foobar:1|c'
|
530
|
+
ensure
|
531
|
+
socket.close
|
532
|
+
end
|
533
|
+
end
|
344
534
|
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
535
|
+
it "should send stuff over an IPv6 socket" do
|
536
|
+
begin
|
537
|
+
socket = UDPSocket.new Socket::AF_INET6
|
538
|
+
host, port = '::1', 0
|
539
|
+
socket.bind(host, port)
|
540
|
+
port = socket.addr[1]
|
541
|
+
|
542
|
+
statsd = Statsd.new(host, port)
|
543
|
+
statsd.increment('foobar')
|
544
|
+
message = socket.recvfrom(16).first
|
545
|
+
_(message).must_equal 'foobar:1|c'
|
546
|
+
ensure
|
547
|
+
socket.close
|
548
|
+
end
|
349
549
|
end
|
350
550
|
end
|
351
|
-
|
551
|
+
|
552
|
+
describe "supports TCP sockets" do
|
553
|
+
it "should connect to and send stats over TCPv4" do
|
554
|
+
begin
|
555
|
+
host, port = '127.0.0.1', 0
|
556
|
+
server = TCPServer.new host, port
|
557
|
+
port = server.addr[1]
|
558
|
+
|
559
|
+
socket = nil
|
560
|
+
Thread.new { socket = server.accept }
|
561
|
+
|
562
|
+
statsd = Statsd.new(host, port, :tcp)
|
563
|
+
statsd.increment('foobar')
|
564
|
+
|
565
|
+
Timeout.timeout(5) do
|
566
|
+
Thread.pass while socket == nil
|
567
|
+
end
|
568
|
+
|
569
|
+
message = socket.recvfrom(16).first
|
570
|
+
_(message).must_equal "foobar:1|c\n"
|
571
|
+
ensure
|
572
|
+
socket.close if socket
|
573
|
+
server.close
|
574
|
+
end
|
575
|
+
end
|
576
|
+
|
577
|
+
it "should connect to and send stats over TCPv6" do
|
578
|
+
begin
|
579
|
+
host, port = '::1', 0
|
580
|
+
server = TCPServer.new host, port
|
581
|
+
port = server.addr[1]
|
582
|
+
|
583
|
+
socket = nil
|
584
|
+
Thread.new { socket = server.accept }
|
585
|
+
|
586
|
+
statsd = Statsd.new(host, port, :tcp)
|
587
|
+
statsd.increment('foobar')
|
588
|
+
|
589
|
+
Timeout.timeout(5) do
|
590
|
+
Thread.pass while socket == nil
|
591
|
+
end
|
592
|
+
|
593
|
+
message = socket.recvfrom(16).first
|
594
|
+
_(message).must_equal "foobar:1|c\n"
|
595
|
+
ensure
|
596
|
+
socket.close if socket
|
597
|
+
server.close
|
598
|
+
end
|
599
|
+
end
|
600
|
+
end
|
601
|
+
end
|