afstatsd 0.0.1 → 0.0.2

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/example/example.rb CHANGED
@@ -1,69 +1,69 @@
1
- require 'afstatsd'
2
-
3
- #$statsd = Statsd.new 'statsd_server.my_company.com', 8125, 20
4
-
5
- $statsd = Statsd.new # use defaults
6
- $statsd.namespace = 'test.ruby'
7
-
8
-
9
- $statsd.increment 'counter1'
10
- $statsd.increment 'counter1'
11
- $statsd.decrement 'counter1' #counters accumulate
12
-
13
- $statsd.gauge 'gauge1', 1024
14
- $statsd.gauge 'gauge1', 1025
15
- $statsd.gauge 'gauge1', 1026
16
- $statsd.gauge 'gauge1', 1027
17
- $statsd.gauge 'gauge1', 1028 # gauges get averaged when aggregated
18
-
19
- $statsd.time('timing1' ){sleep 0.01}
20
- $statsd.time('timing1' ){sleep 0.02}
21
- $statsd.time('timing1' ){sleep 0.03}
22
- $statsd.time('timing1' ){sleep 0.04} # timings get averaged when aggregated
23
-
24
-
25
- =begin
26
-
27
- 100.times do
28
- #$statsd.increment 'sampled', 0.1, 'sampled'
29
- $statsd.increment 'sampled'
30
- end
31
-
32
- $statsd.set 'set1', 1099, "ez"
33
-
34
- for i in 10..19 do
35
- $statsd.increment "counter#{i}" # create a group of counters
36
- end
37
-
38
- 1000.times do
39
- $statsd.increment 'fast' # don't do this if aggregation is off
40
- end
41
-
42
- # In this test program, this will give the aggregator time to run.
43
- 15.times do
44
- sleep 2
45
- $statsd.increment 'slow'
46
- end
47
-
48
- =end
49
-
50
- =begin
51
- # test for thread safety
52
- threads = []
53
- start = Time.now
54
- for i in 0..9 do
55
- threads << Thread.new(i) do |j|
56
- start = Time.now
57
- 1000000.times do
58
- $statsd.increment 'inthethread'
59
- # sleep(0.01)
60
- end
61
- puts "thread #{j} says: I took #{((Time.now - start)*1000).round} ms"
62
- end
63
- end
64
- threads.each { |t| t.join }
65
-
66
- puts "total time: #{((Time.now - start)*1000).round} ms"
67
- =end
68
-
69
- puts "#{$statsd.dropped} messages dropped"
1
+ require 'afstatsd'
2
+
3
+ #$statsd = Statsd.new 'statsd_server.my_company.com', 8125, 20
4
+
5
+ $statsd = Statsd.new # use defaults
6
+ $statsd.namespace = 'test.ruby'
7
+
8
+
9
+ $statsd.increment 'counter1'
10
+ $statsd.increment 'counter1'
11
+ $statsd.decrement 'counter1' #counters accumulate
12
+
13
+ $statsd.gauge 'gauge1', 1024
14
+ $statsd.gauge 'gauge1', 1025
15
+ $statsd.gauge 'gauge1', 1026
16
+ $statsd.gauge 'gauge1', 1027
17
+ $statsd.gauge 'gauge1', 1028 # gauges get averaged when aggregated
18
+
19
+ $statsd.time('timing1' ){sleep 0.01}
20
+ $statsd.time('timing1' ){sleep 0.02}
21
+ $statsd.time('timing1' ){sleep 0.03}
22
+ $statsd.time('timing1' ){sleep 0.04} # timings get averaged when aggregated
23
+
24
+
25
+ =begin
26
+
27
+ 100.times do
28
+ #$statsd.increment 'sampled', 0.1, 'sampled'
29
+ $statsd.increment 'sampled'
30
+ end
31
+
32
+ $statsd.set 'set1', 1099, "ez"
33
+
34
+ for i in 10..19 do
35
+ $statsd.increment "counter#{i}" # create a group of counters
36
+ end
37
+
38
+ 1000.times do
39
+ $statsd.increment 'fast' # don't do this if aggregation is off
40
+ end
41
+
42
+ # In this test program, this will give the aggregator time to run.
43
+ 15.times do
44
+ sleep 2
45
+ $statsd.increment 'slow'
46
+ end
47
+
48
+ =end
49
+
50
+ =begin
51
+ # test for thread safety
52
+ threads = []
53
+ start = Time.now
54
+ for i in 0..9 do
55
+ threads << Thread.new(i) do |j|
56
+ start = Time.now
57
+ 1000000.times do
58
+ $statsd.increment 'inthethread'
59
+ # sleep(0.01)
60
+ end
61
+ puts "thread #{j} says: I took #{((Time.now - start)*1000).round} ms"
62
+ end
63
+ end
64
+ threads.each { |t| t.join }
65
+
66
+ puts "total time: #{((Time.now - start)*1000).round} ms"
67
+ =end
68
+
69
+ puts "#{$statsd.dropped} messages dropped"
@@ -44,18 +44,15 @@ class GMetric < Metric
44
44
  @name = name
45
45
  @value = value
46
46
  @message = msg
47
- @count = 1
48
47
  end
49
48
 
50
49
  def aggregate(value)
51
- @value += value #average
52
- @count += 1
50
+ @value = value #overwrite
53
51
  end
54
52
 
55
53
  def to_s
56
- avg = @value / @count
57
54
  if @message == "" then m = "" else m = "|#{@message}" end
58
- "#{name}:#{avg}|g#{m}"
55
+ "#{name}:#{@value}|g#{m}"
59
56
  end
60
57
 
61
58
  end
data/lib/afstatsd.rb CHANGED
@@ -1,281 +1,281 @@
1
- require 'socket'
2
- require 'forwardable'
3
- require 'rubygems'
4
- require 'posix_mq'
5
- require 'afstatsd/statsd_metrics'
6
- require 'afstatsd/statsd_aggregator'
7
- require 'monitor'
8
- require 'fcntl'
9
-
10
- # = Statsd: A Statsd client (https://github.com/etsy/statsd)
11
- #
12
- # @example Set up a global Statsd client for a server on localhost:9125,
13
- # aggregate 20 seconds worth of metrics
14
- # $statsd = Statsd.new 'localhost', 8125, 20
15
- # @example Send some stats
16
- # $statsd.increment 'garets'
17
- # $statsd.timing 'glork', 320
18
- # $statsd.gauge 'bork', 100
19
- # @example Use {#time} to time the execution of a block
20
- # $statsd.time('account.activate') { @account.activate! }
21
- # @example Create a namespaced statsd client and increment 'account.activate'
22
- # statsd = Statsd.new('localhost').tap{|sd| sd.namespace = 'account'}
23
- # statsd.increment 'activate'
24
- #
25
- # Statsd instances are thread safe for general usage, by using a thread local
26
- # UDPSocket and carrying no state. The attributes are stateful, and are not
27
- # mutexed, it is expected that users will not change these at runtime in
28
- # threaded environments. If users require such use cases, it is recommend that
29
- # users either mutex around their Statsd object, or create separate objects for
30
- # each namespace / host+port combination.
31
- class Statsd
32
-
33
- # A namespace to prepend to all statsd calls.
34
- attr_reader :namespace
35
-
36
- # StatsD host. Defaults to 127.0.0.1. Only used with UDP transport
37
- attr_reader :host
38
-
39
- # StatsD port. Defaults to 8125. Only used with UDP transport
40
- attr_reader :port
41
-
42
- # StatsD namespace prefix, generated from #namespace
43
- attr_reader :prefix
44
-
45
- # a postfix to append to all metrics
46
- attr_reader :postfix
47
-
48
- # count of messages that were dropped due to transmit error
49
- attr_reader :dropped
50
-
51
- class << self
52
- # Set to a standard logger instance to enable debug logging.
53
- attr_accessor :logger
54
- end
55
-
56
- # @param [String] host your statsd host
57
- # @param [Integer] port your statsd port
58
- # @param [Integer] interval for aggregatore
59
- def initialize(host = '127.0.0.1', port = 8125, interval = 20)
60
- self.host, self.port = host, port
61
- @prefix = nil
62
- @postfix = nil
63
- @aggregator = StatsdAggregator.new(interval)
64
- set_transport :mq_transport
65
- self.aggregating = true unless interval == 0
66
- @dropped = 0
67
- end
68
-
69
- # @param [method] The ruby symbol for the method that gets called to send
70
- # one metric to the server. eg: set_transport :udp_transport
71
- def set_transport(transport)
72
- @transport = method(transport)
73
- @aggregator.transport = @transport # aggregator needs to know
74
- end
75
-
76
- # @param [Boolean] Turn aggregation on or off
77
- def aggregating= (should_aggregate)
78
- if should_aggregate
79
- @aggregator.start(@transport)
80
- else
81
- @aggregator.stop
82
- end
83
- end
84
-
85
- # is the aggregator running?
86
- def aggregating
87
- @aggregator.running
88
- end
89
-
90
- # @attribute [w] namespace
91
- # Writes are not thread safe.
92
- def namespace=(namespace)
93
- @namespace = namespace
94
- @prefix = "#{namespace}."
95
- end
96
-
97
- # @attribute [w] postfix
98
- # A value to be appended to the stat name after a '.'. If the value is
99
- # blank then the postfix will be reset to nil (rather than to '.').
100
- def postfix=(pf)
101
- case pf
102
- when nil, false, '' then @postfix = nil
103
- else @postfix = ".#{pf}"
104
- end
105
- end
106
-
107
- # @attribute [w] host
108
- # Writes are not thread safe.
109
- def host=(host)
110
- @host = host || '127.0.0.1'
111
- end
112
-
113
- # @attribute [w] port
114
- # Writes are not thread safe.
115
- def port=(port)
116
- @port = port || 8125
117
- end
118
-
119
- # Sends an increment (count = 1) for the given stat to the statsd server.
120
- #
121
- # @param [String] stat stat name
122
- # @param [Numeric] sample_rate sample rate, 1 for always
123
- # @param [String] optional note (AppFirst extension to StatsD)
124
- # @see #count
125
- def increment(stat, sample_rate=1, note="")
126
- count stat, 1, sample_rate, note
127
- end
128
-
129
- # Sends a decrement (count = -1) for the given stat to the statsd server.
130
- #
131
- # @param [String] stat stat name
132
- # @param [Numeric] sample_rate sample rate, 1 for always
133
- # @param [String] optional note (AppFirst extension to StatsD)
134
- # @see #count
135
- def decrement(stat, sample_rate=1, note="")
136
- count stat, -1, sample_rate, note
137
- end
138
-
139
- # Sends an arbitrary count for the given stat to the statsd server.
140
- #
141
- # @param [String] stat stat name
142
- # @param [Integer] count count
143
- # @param [Numeric] sample_rate sample rate, 1 for always
144
- # @param [String] optional note (AppFirst extension to StatsD)
145
- def count(stat, count, sample_rate=1, note="")
146
- if sample_rate == 1 or rand < sample_rate
147
- send_metric StatsdMetrics::CMetric.new(expand_name(stat), count, sample_rate, note)
148
- end
149
- end
150
-
151
- # Sends an arbitary gauge value for the given stat to the statsd server.
152
- #
153
- # This is useful for recording things like available disk space,
154
- # memory usage, and the like, which have different semantics than
155
- # counters.
156
- #
157
- # @param [String] stat stat name.
158
- # @param [Numeric] value gauge value.
159
- # @param [String] optional note (AppFirst extension to StatsD)
160
- # @example Report the current user count:
161
- # $statsd.gauge('user.count', User.count)
162
- def gauge(stat, value, note="")
163
- send_metric StatsdMetrics::GMetric.new(expand_name(stat), value, note)
164
- end
165
-
166
- # Sends an arbitary set value for the given stat to the statsd server.
167
- #
168
- # This is for recording counts of unique events, which are useful to
169
- # see on graphs to correlate to other values. For example, a deployment
170
- # might get recorded as a set, and be drawn as annotations on a CPU history
171
- # graph.
172
- #
173
- # @param [String] stat stat name.
174
- # @param [Numeric] value event value.
175
- # @param [String] optional note (AppFirst extension to StatsD)
176
- # @example Report a deployment happening:
177
- # $statsd.set('deployment', DEPLOYMENT_EVENT_CODE)
178
- def set(stat, value, note="")
179
- send_metric StatsdMetrics::SMetric.new(expand_name(stat), value, note)
180
- end
181
-
182
- # Sends a timing (in ms) for the given stat to the statsd server. The
183
- # sample_rate determines what percentage of the time this report is sent. The
184
- # statsd server then uses the sample_rate to correctly track the average
185
- # timing for the stat.
186
- #
187
- # @param [String] stat stat name
188
- # @param [Integer] ms timing in milliseconds
189
- # @param [Numeric] sample_rate sample rate, 1 for always
190
- # @param [String] optional note (AppFirst extension to StatsD)
191
- def timing(stat, ms, sample_rate=1, note="")
192
- if sample_rate == 1 or rand < sample_rate
193
- send_metric StatsdMetrics::TMetric.new(expand_name(stat), ms, sample_rate, note)
194
- end
195
- end
196
-
197
- # Reports execution time of the provided block using {#timing}.
198
- #
199
- # @param [String] stat stat name
200
- # @param [Numeric] sample_rate sample rate, 1 for always
201
- # @param [String] optional note (AppFirst extension to StatsD)
202
- # @yield The operation to be timed
203
- # @see #timing
204
- # @example Report the time (in ms) taken to activate an account
205
- # $statsd.time('account.activate') { @account.activate! }
206
- def time(stat, sample_rate=1, note="")
207
- start = Time.now
208
- result = yield
209
- timing(stat, ((Time.now - start) * 1000).round, sample_rate, note)
210
- result
211
- end
212
-
213
- protected
214
-
215
- def send_metric(metric)
216
- # All the metric types above funnel to here. We will send or aggregate.
217
- if aggregating
218
- @aggregator.add metric
219
- else
220
- @transport.call(metric)
221
- end
222
- end
223
-
224
- def expand_name(name)
225
- # Replace Ruby module scoping with '.' and reserved chars (: | @) with underscores.
226
- name = name.to_s.gsub('::', '.').tr(':|@', '_')
227
- "#{prefix}#{name}#{postfix}"
228
- end
229
-
230
- def udp_transport(metric)
231
- #puts "socket < #{metric}\n"
232
- self.class.logger.debug { "Statsd: #{metric}" } if self.class.logger
233
- socket.send(metric.to_s, 0, @host, @port)
234
- rescue => boom
235
- #puts "socket send error"
236
- @dropped +=1
237
- self.class.logger.error { "Statsd: #{boom.class} #{boom}" } if self.class.logger
238
- nil
239
- end
240
-
241
- STATSD_SEVERITY = 3
242
- def mq_transport(metric)
243
- #puts "MQ < #{metric}\n" #debug
244
- self.class.logger.debug { "Statsd: #{metric}" } if self.class.logger
245
- if not @mq
246
- begin
247
- @mq = POSIX_MQ.new("/afcollectorapi", Fcntl::O_WRONLY | Fcntl::O_NONBLOCK)
248
- rescue => boom
249
- self.class.logger.debug { "Statsd: MQ open error #{boom.class} #{boom}" } if self.class.logger
250
- # failed to open MQ. Fall back to UPD transport. Note: Current message will be lost.
251
- @dropped += 1
252
- # puts "fallback to udp"
253
- set_transport :udp_transport
254
- return nil
255
- end
256
- end
257
- begin
258
- @mq.send(metric.to_s, STATSD_SEVERITY)
259
- rescue => boom
260
- # just drop it on the floor
261
- @dropped += 1
262
- #puts "MQ send error: #{boom.class} #{boom}"
263
- self.class.logger.error { "Statsd: MQ Send Error#{boom.class} #{boom}" } if self.class.logger
264
- nil
265
- end
266
- end
267
-
268
- def both_transport(metric)
269
- mq_transport(metric)
270
- udp_transport(metric)
271
- end
272
-
273
- private
274
-
275
- def socket
276
- Thread.current[:statsd_socket] ||= UDPSocket.new
277
- end
278
-
279
- end # class Statsd
280
-
281
-
1
+ require 'socket'
2
+ require 'forwardable'
3
+ require 'rubygems'
4
+ require 'posix_mq'
5
+ require 'afstatsd/statsd_metrics'
6
+ require 'afstatsd/statsd_aggregator'
7
+ require 'monitor'
8
+ require 'fcntl'
9
+
10
+ # = Statsd: A Statsd client (https://github.com/etsy/statsd)
11
+ #
12
+ # @example Set up a global Statsd client for a server on localhost:9125,
13
+ # aggregate 20 seconds worth of metrics
14
+ # $statsd = Statsd.new 'localhost', 8125, 20
15
+ # @example Send some stats
16
+ # $statsd.increment 'garets'
17
+ # $statsd.timing 'glork', 320
18
+ # $statsd.gauge 'bork', 100
19
+ # @example Use {#time} to time the execution of a block
20
+ # $statsd.time('account.activate') { @account.activate! }
21
+ # @example Create a namespaced statsd client and increment 'account.activate'
22
+ # statsd = Statsd.new('localhost').tap{|sd| sd.namespace = 'account'}
23
+ # statsd.increment 'activate'
24
+ #
25
+ # Statsd instances are thread safe for general usage, by using a thread local
26
+ # UDPSocket and carrying no state. The attributes are stateful, and are not
27
+ # mutexed, it is expected that users will not change these at runtime in
28
+ # threaded environments. If users require such use cases, it is recommend that
29
+ # users either mutex around their Statsd object, or create separate objects for
30
+ # each namespace / host+port combination.
31
+ class Statsd
32
+
33
+ # A namespace to prepend to all statsd calls.
34
+ attr_reader :namespace
35
+
36
+ # StatsD host. Defaults to 127.0.0.1. Only used with UDP transport
37
+ attr_reader :host
38
+
39
+ # StatsD port. Defaults to 8125. Only used with UDP transport
40
+ attr_reader :port
41
+
42
+ # StatsD namespace prefix, generated from #namespace
43
+ attr_reader :prefix
44
+
45
+ # a postfix to append to all metrics
46
+ attr_reader :postfix
47
+
48
+ # count of messages that were dropped due to transmit error
49
+ attr_reader :dropped
50
+
51
+ class << self
52
+ # Set to a standard logger instance to enable debug logging.
53
+ attr_accessor :logger
54
+ end
55
+
56
+ # @param [String] host your statsd host
57
+ # @param [Integer] port your statsd port
58
+ # @param [Integer] interval for aggregatore
59
+ def initialize(host = '127.0.0.1', port = 8125, interval = 20)
60
+ self.host, self.port = host, port
61
+ @prefix = nil
62
+ @postfix = nil
63
+ @aggregator = StatsdAggregator.new(interval)
64
+ set_transport :mq_transport
65
+ self.aggregating = true unless interval == 0
66
+ @dropped = 0
67
+ end
68
+
69
+ # @param [method] The ruby symbol for the method that gets called to send
70
+ # one metric to the server. eg: set_transport :udp_transport
71
+ def set_transport(transport)
72
+ @transport = method(transport)
73
+ @aggregator.transport = @transport # aggregator needs to know
74
+ end
75
+
76
+ # @param [Boolean] Turn aggregation on or off
77
+ def aggregating= (should_aggregate)
78
+ if should_aggregate
79
+ @aggregator.start(@transport)
80
+ else
81
+ @aggregator.stop
82
+ end
83
+ end
84
+
85
+ # is the aggregator running?
86
+ def aggregating
87
+ @aggregator.running
88
+ end
89
+
90
+ # @attribute [w] namespace
91
+ # Writes are not thread safe.
92
+ def namespace=(namespace)
93
+ @namespace = namespace
94
+ @prefix = "#{namespace}."
95
+ end
96
+
97
+ # @attribute [w] postfix
98
+ # A value to be appended to the stat name after a '.'. If the value is
99
+ # blank then the postfix will be reset to nil (rather than to '.').
100
+ def postfix=(pf)
101
+ case pf
102
+ when nil, false, '' then @postfix = nil
103
+ else @postfix = ".#{pf}"
104
+ end
105
+ end
106
+
107
+ # @attribute [w] host
108
+ # Writes are not thread safe.
109
+ def host=(host)
110
+ @host = host || '127.0.0.1'
111
+ end
112
+
113
+ # @attribute [w] port
114
+ # Writes are not thread safe.
115
+ def port=(port)
116
+ @port = port || 8125
117
+ end
118
+
119
+ # Sends an increment (count = 1) for the given stat to the statsd server.
120
+ #
121
+ # @param [String] stat stat name
122
+ # @param [Numeric] sample_rate sample rate, 1 for always
123
+ # @param [String] optional note (AppFirst extension to StatsD)
124
+ # @see #count
125
+ def increment(stat, sample_rate=1, note="")
126
+ count stat, 1, sample_rate, note
127
+ end
128
+
129
+ # Sends a decrement (count = -1) for the given stat to the statsd server.
130
+ #
131
+ # @param [String] stat stat name
132
+ # @param [Numeric] sample_rate sample rate, 1 for always
133
+ # @param [String] optional note (AppFirst extension to StatsD)
134
+ # @see #count
135
+ def decrement(stat, sample_rate=1, note="")
136
+ count stat, -1, sample_rate, note
137
+ end
138
+
139
+ # Sends an arbitrary count for the given stat to the statsd server.
140
+ #
141
+ # @param [String] stat stat name
142
+ # @param [Integer] count count
143
+ # @param [Numeric] sample_rate sample rate, 1 for always
144
+ # @param [String] optional note (AppFirst extension to StatsD)
145
+ def count(stat, count, sample_rate=1, note="")
146
+ if sample_rate == 1 or rand < sample_rate
147
+ send_metric StatsdMetrics::CMetric.new(expand_name(stat), count, sample_rate, note)
148
+ end
149
+ end
150
+
151
+ # Sends an arbitary gauge value for the given stat to the statsd server.
152
+ #
153
+ # This is useful for recording things like available disk space,
154
+ # memory usage, and the like, which have different semantics than
155
+ # counters.
156
+ #
157
+ # @param [String] stat stat name.
158
+ # @param [Numeric] value gauge value.
159
+ # @param [String] optional note (AppFirst extension to StatsD)
160
+ # @example Report the current user count:
161
+ # $statsd.gauge('user.count', User.count)
162
+ def gauge(stat, value, note="")
163
+ send_metric StatsdMetrics::GMetric.new(expand_name(stat), value, note)
164
+ end
165
+
166
+ # Sends an arbitary set value for the given stat to the statsd server.
167
+ #
168
+ # This is for recording counts of unique events, which are useful to
169
+ # see on graphs to correlate to other values. For example, a deployment
170
+ # might get recorded as a set, and be drawn as annotations on a CPU history
171
+ # graph.
172
+ #
173
+ # @param [String] stat stat name.
174
+ # @param [Numeric] value event value.
175
+ # @param [String] optional note (AppFirst extension to StatsD)
176
+ # @example Report a deployment happening:
177
+ # $statsd.set('deployment', DEPLOYMENT_EVENT_CODE)
178
+ def set(stat, value, note="")
179
+ send_metric StatsdMetrics::SMetric.new(expand_name(stat), value, note)
180
+ end
181
+
182
+ # Sends a timing (in ms) for the given stat to the statsd server. The
183
+ # sample_rate determines what percentage of the time this report is sent. The
184
+ # statsd server then uses the sample_rate to correctly track the average
185
+ # timing for the stat.
186
+ #
187
+ # @param [String] stat stat name
188
+ # @param [Integer] ms timing in milliseconds
189
+ # @param [Numeric] sample_rate sample rate, 1 for always
190
+ # @param [String] optional note (AppFirst extension to StatsD)
191
+ def timing(stat, ms, sample_rate=1, note="")
192
+ if sample_rate == 1 or rand < sample_rate
193
+ send_metric StatsdMetrics::TMetric.new(expand_name(stat), ms, sample_rate, note)
194
+ end
195
+ end
196
+
197
+ # Reports execution time of the provided block using {#timing}.
198
+ #
199
+ # @param [String] stat stat name
200
+ # @param [Numeric] sample_rate sample rate, 1 for always
201
+ # @param [String] optional note (AppFirst extension to StatsD)
202
+ # @yield The operation to be timed
203
+ # @see #timing
204
+ # @example Report the time (in ms) taken to activate an account
205
+ # $statsd.time('account.activate') { @account.activate! }
206
+ def time(stat, sample_rate=1, note="")
207
+ start = Time.now
208
+ result = yield
209
+ timing(stat, ((Time.now - start) * 1000).round, sample_rate, note)
210
+ result
211
+ end
212
+
213
+ protected
214
+
215
+ def send_metric(metric)
216
+ # All the metric types above funnel to here. We will send or aggregate.
217
+ if aggregating
218
+ @aggregator.add metric
219
+ else
220
+ @transport.call(metric)
221
+ end
222
+ end
223
+
224
+ def expand_name(name)
225
+ # Replace Ruby module scoping with '.' and reserved chars (: | @) with underscores.
226
+ name = name.to_s.gsub('::', '.').tr(':|@', '_')
227
+ "#{prefix}#{name}#{postfix}"
228
+ end
229
+
230
+ def udp_transport(metric)
231
+ #puts "socket < #{metric}\n"
232
+ self.class.logger.debug { "Statsd: #{metric}" } if self.class.logger
233
+ socket.send(metric.to_s, 0, @host, @port)
234
+ rescue => boom
235
+ #puts "socket send error"
236
+ @dropped +=1
237
+ self.class.logger.error { "Statsd: #{boom.class} #{boom}" } if self.class.logger
238
+ nil
239
+ end
240
+
241
+ STATSD_SEVERITY = 3
242
+ def mq_transport(metric)
243
+ #puts "MQ < #{metric}\n" #debug
244
+ self.class.logger.debug { "Statsd: #{metric}" } if self.class.logger
245
+ if not @mq
246
+ begin
247
+ @mq = POSIX_MQ.new("/afcollectorapi", Fcntl::O_WRONLY | Fcntl::O_NONBLOCK)
248
+ rescue => boom
249
+ self.class.logger.debug { "Statsd: MQ open error #{boom.class} #{boom}" } if self.class.logger
250
+ # failed to open MQ. Fall back to UPD transport. Note: Current message will be lost.
251
+ @dropped += 1
252
+ # puts "fallback to udp"
253
+ set_transport :udp_transport
254
+ return nil
255
+ end
256
+ end
257
+ begin
258
+ @mq.send(metric.to_s, STATSD_SEVERITY)
259
+ rescue => boom
260
+ # just drop it on the floor
261
+ @dropped += 1
262
+ #puts "MQ send error: #{boom.class} #{boom}"
263
+ self.class.logger.error { "Statsd: MQ Send Error#{boom.class} #{boom}" } if self.class.logger
264
+ nil
265
+ end
266
+ end
267
+
268
+ def both_transport(metric)
269
+ mq_transport(metric)
270
+ udp_transport(metric)
271
+ end
272
+
273
+ private
274
+
275
+ def socket
276
+ Thread.current[:statsd_socket] ||= UDPSocket.new
277
+ end
278
+
279
+ end # class Statsd
280
+
281
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: afstatsd
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-02-18 00:00:00.000000000 Z
12
+ date: 2013-03-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: posix_mq