statsd-ruby 1.0.0 → 1.1.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.
- data/README.rdoc +18 -1
- data/lib/statsd.rb +104 -10
- data/spec/helper.rb +1 -1
- data/spec/statsd_spec.rb +68 -5
- data/statsd-ruby.gemspec +2 -2
- metadata +18 -18
data/README.rdoc
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
= statsd-ruby {<img src="https://secure.travis-ci.org/reinh/statsd
|
1
|
+
= statsd-ruby {<img src="https://secure.travis-ci.org/reinh/statsd.png" />}[http://travis-ci.org/reinh/statsd]
|
2
2
|
|
3
3
|
A Ruby client for {StatsD}[https://github.com/etsy/statsd]
|
4
4
|
|
@@ -7,6 +7,23 @@ A Ruby client for {StatsD}[https://github.com/etsy/statsd]
|
|
7
7
|
Bundler:
|
8
8
|
gem "statsd-ruby", :require => "statsd"
|
9
9
|
|
10
|
+
= Basic Usage
|
11
|
+
|
12
|
+
# Set up a global Statsd client for a server on localhost:9125
|
13
|
+
$statsd = Statsd.new 'localhost', 9125
|
14
|
+
|
15
|
+
# Send some stats
|
16
|
+
$statsd.increment 'garets'
|
17
|
+
$statsd.timing 'glork', 320
|
18
|
+
$statsd.gauge 'bork', 100
|
19
|
+
|
20
|
+
# Use {#time} to time the execution of a block
|
21
|
+
$statsd.time('account.activate') { @account.activate! }
|
22
|
+
|
23
|
+
# Create a namespaced statsd client and increment 'account.activate'
|
24
|
+
statsd = Statsd.new('localhost').tap{|sd| sd.namespace = 'account'}
|
25
|
+
statsd.increment 'activate'
|
26
|
+
|
10
27
|
= Testing
|
11
28
|
|
12
29
|
Run the specs with <tt>rake spec</tt>
|
data/lib/statsd.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'socket'
|
2
|
+
require 'forwardable'
|
2
3
|
|
3
4
|
# = Statsd: A Statsd client (https://github.com/etsy/statsd)
|
4
5
|
#
|
@@ -21,6 +22,68 @@ require 'socket'
|
|
21
22
|
# users either mutex around their Statsd object, or create separate objects for
|
22
23
|
# each namespace / host+port combination.
|
23
24
|
class Statsd
|
25
|
+
|
26
|
+
# = Batch: A batching statsd proxy
|
27
|
+
#
|
28
|
+
# @example Batch a set of instruments using Batch and manual flush:
|
29
|
+
# $statsd = Statsd.new 'localhost', 8125
|
30
|
+
# batch = Statsd::Batch.new($statsd)
|
31
|
+
# batch.increment 'garets'
|
32
|
+
# batch.timing 'glork', 320
|
33
|
+
# batch.gauge 'bork', 100
|
34
|
+
# batch.flush
|
35
|
+
#
|
36
|
+
# Batch is a subclass of Statsd, but with a constructor that proxies to a
|
37
|
+
# normal Statsd instance. It has it's own batch_size and namespace parameters
|
38
|
+
# (that inherit defaults from the supplied Statsd instance). It is recommended
|
39
|
+
# that some care is taken if setting very large batch sizes. If the batch size
|
40
|
+
# exceeds the allowed packet size for UDP on your network, communication
|
41
|
+
# troubles may occur and data will be lost.
|
42
|
+
class Batch < Statsd
|
43
|
+
|
44
|
+
extend Forwardable
|
45
|
+
def_delegators :@statsd,
|
46
|
+
:namespace, :namespace=, :host, :port, :prefix, :postfix
|
47
|
+
|
48
|
+
attr_accessor :batch_size
|
49
|
+
|
50
|
+
# @param [Statsd] requires a configured Statsd instance
|
51
|
+
def initialize(statsd)
|
52
|
+
@statsd = statsd
|
53
|
+
@batch_size = statsd.batch_size
|
54
|
+
@backlog = []
|
55
|
+
end
|
56
|
+
|
57
|
+
# @yields [Batch] yields itself
|
58
|
+
#
|
59
|
+
# A convenience method to ensure that data is not lost in the event of an
|
60
|
+
# exception being thrown. Batches will be transmitted on the parent socket
|
61
|
+
# as soon as the batch is full, and when the block finishes.
|
62
|
+
def easy
|
63
|
+
yield self
|
64
|
+
ensure
|
65
|
+
flush
|
66
|
+
end
|
67
|
+
|
68
|
+
def flush
|
69
|
+
unless @backlog.empty?
|
70
|
+
@statsd.send_to_socket @backlog.join("\n")
|
71
|
+
@backlog.clear
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
protected
|
76
|
+
|
77
|
+
def send_to_socket(message)
|
78
|
+
@backlog << message
|
79
|
+
if @backlog.size >= @batch_size
|
80
|
+
flush
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
|
24
87
|
# A namespace to prepend to all statsd calls.
|
25
88
|
attr_reader :namespace
|
26
89
|
|
@@ -30,6 +93,15 @@ class Statsd
|
|
30
93
|
# StatsD port. Defaults to 8125.
|
31
94
|
attr_reader :port
|
32
95
|
|
96
|
+
# StatsD namespace prefix, generated from #namespace
|
97
|
+
attr_reader :prefix
|
98
|
+
|
99
|
+
# The default batch size for new batches (default: 10)
|
100
|
+
attr_accessor :batch_size
|
101
|
+
|
102
|
+
# a postfix to append to all metrics
|
103
|
+
attr_reader :postfix
|
104
|
+
|
33
105
|
class << self
|
34
106
|
# Set to a standard logger instance to enable debug logging.
|
35
107
|
attr_accessor :logger
|
@@ -40,6 +112,8 @@ class Statsd
|
|
40
112
|
def initialize(host = '127.0.0.1', port = 8125)
|
41
113
|
self.host, self.port = host, port
|
42
114
|
@prefix = nil
|
115
|
+
@batch_size = 10
|
116
|
+
@postfix = nil
|
43
117
|
end
|
44
118
|
|
45
119
|
# @attribute [w] namespace
|
@@ -49,6 +123,10 @@ class Statsd
|
|
49
123
|
@prefix = "#{namespace}."
|
50
124
|
end
|
51
125
|
|
126
|
+
def postfix=(pf)
|
127
|
+
@postfix = ".#{pf}"
|
128
|
+
end
|
129
|
+
|
52
130
|
# @attribute [w] host
|
53
131
|
# Writes are not thread safe.
|
54
132
|
def host=(host)
|
@@ -95,7 +173,7 @@ class Statsd
|
|
95
173
|
# counters.
|
96
174
|
#
|
97
175
|
# @param [String] stat stat name.
|
98
|
-
# @param [Numeric] gauge value.
|
176
|
+
# @param [Numeric] value gauge value.
|
99
177
|
# @param [Numeric] sample_rate sample rate, 1 for always
|
100
178
|
# @example Report the current user count:
|
101
179
|
# $statsd.gauge('user.count', User.count)
|
@@ -130,17 +208,22 @@ class Statsd
|
|
130
208
|
result
|
131
209
|
end
|
132
210
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
211
|
+
# Creates and yields a Batch that can be used to batch instrument reports into
|
212
|
+
# larger packets. Batches are sent either when the packet is "full" (defined
|
213
|
+
# by batch_size), or when the block completes, whichever is the sooner.
|
214
|
+
#
|
215
|
+
# @yield [Batch] a statsd subclass that collects and batches instruments
|
216
|
+
# @example Batch two instument operations:
|
217
|
+
# $statsd.batch do |batch|
|
218
|
+
# batch.increment 'sys.requests'
|
219
|
+
# batch.gauge('user.count', User.count)
|
220
|
+
# end
|
221
|
+
def batch(&block)
|
222
|
+
Batch.new(self).easy &block
|
142
223
|
end
|
143
224
|
|
225
|
+
protected
|
226
|
+
|
144
227
|
def send_to_socket(message)
|
145
228
|
self.class.logger.debug { "Statsd: #{message}" } if self.class.logger
|
146
229
|
socket.send(message, 0, @host, @port)
|
@@ -149,6 +232,17 @@ class Statsd
|
|
149
232
|
nil
|
150
233
|
end
|
151
234
|
|
235
|
+
private
|
236
|
+
|
237
|
+
def send_stats(stat, delta, type, sample_rate=1)
|
238
|
+
if sample_rate == 1 or rand < sample_rate
|
239
|
+
# Replace Ruby module scoping with '.' and reserved chars (: | @) with underscores.
|
240
|
+
stat = stat.to_s.gsub('::', '.').tr(':|@', '_')
|
241
|
+
rate = "|@#{sample_rate}" unless sample_rate == 1
|
242
|
+
send_to_socket "#{prefix}#{stat}#{postfix}:#{delta}|#{type}#{rate}"
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
152
246
|
def socket
|
153
247
|
Thread.current[:statsd_socket] ||= UDPSocket.new
|
154
248
|
end
|
data/spec/helper.rb
CHANGED
data/spec/statsd_spec.rb
CHANGED
@@ -113,12 +113,12 @@ describe Statsd do
|
|
113
113
|
|
114
114
|
describe "#time" do
|
115
115
|
it "should format the message according to the statsd spec" do
|
116
|
-
@statsd.time('foobar') {
|
117
|
-
@socket.recv.must_equal ['foobar:
|
116
|
+
@statsd.time('foobar') { 'test' }
|
117
|
+
@socket.recv.must_equal ['foobar:0|ms']
|
118
118
|
end
|
119
119
|
|
120
120
|
it "should return the result of the block" do
|
121
|
-
result = @statsd.time('foobar') {
|
121
|
+
result = @statsd.time('foobar') { 'test' }
|
122
122
|
result.must_equal 'test'
|
123
123
|
end
|
124
124
|
|
@@ -126,8 +126,8 @@ describe Statsd do
|
|
126
126
|
before { class << @statsd; def rand; 0; end; end } # ensure delivery
|
127
127
|
|
128
128
|
it "should format the message according to the statsd spec" do
|
129
|
-
|
130
|
-
@socket.recv.must_equal ['foobar:
|
129
|
+
@statsd.time('foobar', 0.5) { 'test' }
|
130
|
+
@socket.recv.must_equal ['foobar:0|ms|@0.5']
|
131
131
|
end
|
132
132
|
end
|
133
133
|
end
|
@@ -189,6 +189,30 @@ describe Statsd do
|
|
189
189
|
end
|
190
190
|
end
|
191
191
|
|
192
|
+
describe "with postfix" do
|
193
|
+
before { @statsd.postfix = 'ip-23-45-56-78' }
|
194
|
+
|
195
|
+
it "should add postfix to increment" do
|
196
|
+
@statsd.increment('foobar')
|
197
|
+
@socket.recv.must_equal ['foobar.ip-23-45-56-78:1|c']
|
198
|
+
end
|
199
|
+
|
200
|
+
it "should add postfix to decrement" do
|
201
|
+
@statsd.decrement('foobar')
|
202
|
+
@socket.recv.must_equal ['foobar.ip-23-45-56-78:-1|c']
|
203
|
+
end
|
204
|
+
|
205
|
+
it "should add namespace to timing" do
|
206
|
+
@statsd.timing('foobar', 500)
|
207
|
+
@socket.recv.must_equal ['foobar.ip-23-45-56-78:500|ms']
|
208
|
+
end
|
209
|
+
|
210
|
+
it "should add namespace to gauge" do
|
211
|
+
@statsd.gauge('foobar', 500)
|
212
|
+
@socket.recv.must_equal ['foobar.ip-23-45-56-78:500|g']
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
192
216
|
describe "with logging" do
|
193
217
|
require 'stringio'
|
194
218
|
before { Statsd.logger = Logger.new(@log = StringIO.new)}
|
@@ -245,6 +269,45 @@ describe Statsd do
|
|
245
269
|
end
|
246
270
|
end
|
247
271
|
|
272
|
+
describe "batching" do
|
273
|
+
it "should have a default batch size of 10" do
|
274
|
+
@statsd.batch_size.must_equal 10
|
275
|
+
end
|
276
|
+
|
277
|
+
it "should have a modifiable batch size" do
|
278
|
+
@statsd.batch_size = 7
|
279
|
+
@statsd.batch_size.must_equal 7
|
280
|
+
@statsd.batch do |b|
|
281
|
+
b.batch_size.must_equal 7
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
it "should flush the batch at the batch size or at the end of the block" do
|
286
|
+
@statsd.batch do |b|
|
287
|
+
b.batch_size = 3
|
288
|
+
|
289
|
+
# The first three should flush, the next two will be flushed when the
|
290
|
+
# block is done.
|
291
|
+
5.times { b.increment('foobar') }
|
292
|
+
|
293
|
+
@socket.recv.must_equal [(["foobar:1|c"] * 3).join("\n")]
|
294
|
+
end
|
295
|
+
|
296
|
+
@socket.recv.must_equal [(["foobar:1|c"] * 2).join("\n")]
|
297
|
+
end
|
298
|
+
|
299
|
+
it "should not flush to the socket if the backlog is empty" do
|
300
|
+
batch = Statsd::Batch.new(@statsd)
|
301
|
+
batch.flush
|
302
|
+
@socket.recv.must_be :nil?
|
303
|
+
|
304
|
+
batch.increment 'foobar'
|
305
|
+
batch.flush
|
306
|
+
@socket.recv.must_equal %w[foobar:1|c]
|
307
|
+
end
|
308
|
+
|
309
|
+
end
|
310
|
+
|
248
311
|
describe "thread safety" do
|
249
312
|
|
250
313
|
it "should use a thread local socket" do
|
data/statsd-ruby.gemspec
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
|
3
|
-
Gem::Specification.new("statsd-ruby", "1.
|
3
|
+
Gem::Specification.new("statsd-ruby", "1.1.0") do |s|
|
4
4
|
s.authors = ["Rein Henrichs"]
|
5
5
|
s.email = "rein@phpfog.com"
|
6
6
|
|
7
7
|
s.summary = "A Ruby StatsD client"
|
8
8
|
s.description = "A Ruby StatsD client (https://github.com/etsy/statsd)"
|
9
9
|
|
10
|
-
s.homepage = "https://github.com/reinh/statsd
|
10
|
+
s.homepage = "https://github.com/reinh/statsd"
|
11
11
|
s.licenses = %w[MIT]
|
12
12
|
|
13
13
|
s.extra_rdoc_files = %w[LICENSE.txt README.rdoc]
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: statsd-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 19
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
+
- 1
|
8
9
|
- 0
|
9
|
-
|
10
|
-
version: 1.0.0
|
10
|
+
version: 1.1.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Rein Henrichs
|
@@ -15,11 +15,12 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-
|
18
|
+
date: 2012-12-05 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
|
+
name: minitest
|
21
22
|
prerelease: false
|
22
|
-
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
23
24
|
none: false
|
24
25
|
requirements:
|
25
26
|
- - ">="
|
@@ -30,12 +31,12 @@ dependencies:
|
|
30
31
|
- 2
|
31
32
|
- 0
|
32
33
|
version: 3.2.0
|
33
|
-
requirement: *id001
|
34
|
-
name: minitest
|
35
34
|
type: :development
|
35
|
+
version_requirements: *id001
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
|
+
name: yard
|
37
38
|
prerelease: false
|
38
|
-
|
39
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
40
|
none: false
|
40
41
|
requirements:
|
41
42
|
- - ">="
|
@@ -44,12 +45,12 @@ dependencies:
|
|
44
45
|
segments:
|
45
46
|
- 0
|
46
47
|
version: "0"
|
47
|
-
requirement: *id002
|
48
|
-
name: yard
|
49
48
|
type: :development
|
49
|
+
version_requirements: *id002
|
50
50
|
- !ruby/object:Gem::Dependency
|
51
|
+
name: simplecov
|
51
52
|
prerelease: false
|
52
|
-
|
53
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
53
54
|
none: false
|
54
55
|
requirements:
|
55
56
|
- - ">="
|
@@ -60,12 +61,12 @@ dependencies:
|
|
60
61
|
- 6
|
61
62
|
- 4
|
62
63
|
version: 0.6.4
|
63
|
-
requirement: *id003
|
64
|
-
name: simplecov
|
65
64
|
type: :development
|
65
|
+
version_requirements: *id003
|
66
66
|
- !ruby/object:Gem::Dependency
|
67
|
+
name: rake
|
67
68
|
prerelease: false
|
68
|
-
|
69
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
69
70
|
none: false
|
70
71
|
requirements:
|
71
72
|
- - ">="
|
@@ -74,9 +75,8 @@ dependencies:
|
|
74
75
|
segments:
|
75
76
|
- 0
|
76
77
|
version: "0"
|
77
|
-
requirement: *id004
|
78
|
-
name: rake
|
79
78
|
type: :development
|
79
|
+
version_requirements: *id004
|
80
80
|
description: A Ruby StatsD client (https://github.com/etsy/statsd)
|
81
81
|
email: rein@phpfog.com
|
82
82
|
executables: []
|
@@ -98,7 +98,7 @@ files:
|
|
98
98
|
- spec/helper.rb
|
99
99
|
- spec/statsd_spec.rb
|
100
100
|
- statsd-ruby.gemspec
|
101
|
-
homepage: https://github.com/reinh/statsd
|
101
|
+
homepage: https://github.com/reinh/statsd
|
102
102
|
licenses:
|
103
103
|
- MIT
|
104
104
|
post_install_message:
|
@@ -127,7 +127,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
127
127
|
requirements: []
|
128
128
|
|
129
129
|
rubyforge_project:
|
130
|
-
rubygems_version: 1.8.
|
130
|
+
rubygems_version: 1.8.24
|
131
131
|
signing_key:
|
132
132
|
specification_version: 3
|
133
133
|
summary: A Ruby StatsD client
|