statsd-instrument 1.5.0 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b9bc489157242e310ea28c0a1680fb34c608a8e6
4
+ data.tar.gz: 64ca871cc2a93f2fed3c5690fa6b53a1cd864925
5
+ SHA512:
6
+ metadata.gz: 7eb191b76130aef5e14cc7e9b74d22936809713339b5accfa25c995507fb8ebf2ba9d879cba31ed64c6773ec97b82c38e1ccbc9a0352597c3f972dc46afdc9c2
7
+ data.tar.gz: 3390177c19dfa7c9bca20f9d9a26fe36ead251bf8142132d0b866c2a09e435211c74cad4897156a4c914aa6b285d415896153a8ebd5447cda6076ae06a451cb4
@@ -4,3 +4,4 @@ rvm:
4
4
  - ree
5
5
  - 1.9.2
6
6
  - 1.9.3
7
+ - 2.0.0
data/README.md CHANGED
@@ -28,6 +28,13 @@ StatsD.default_sample_rate = 0.1 # Sample 10% of events. By default all events a
28
28
 
29
29
  If you set the mode to anything besides production then the library will print its calls to the logger, rather than sending them over the wire.
30
30
 
31
+ There are several implementations of StatsD out there, all with slight protocol variations. You can this library to use the proper protocol by informing it about what implementation you use. By default, it will use the protocol of the original Etsy implementation.
32
+
33
+ ```
34
+ StatsD.implementation = :datadog # Enable datadog extensions: tags and histograms
35
+ StatsD.implementation = :statsite # Enable keyvalue-style gauges
36
+ ```
37
+
31
38
  ## StatsD keys
32
39
 
33
40
  StatsD keys look like 'admin.logins.api.success'. Each dot in the key represents a 'folder' in the graphite interface. You can include any data you want in the keys.
@@ -148,20 +155,23 @@ GoogleBase.statsd_count :insert, lamdba{|object, args| object.class.to_s.downcas
148
155
  ```
149
156
 
150
157
  ## Reliance on DNS
158
+
151
159
  Out of the box StatsD is set up to be unidirectional fire-and-forget over UDP. Configuring the StatsD host to be a non-ip will trigger a DNS lookup (ie synchronous round trip network call) for each metric sent. This can be particularly problematic in clouds that have a shared DNS infrastructure such as AWS.
152
160
 
153
161
  ### Common Workarounds
162
+
154
163
  1. Using an IP avoids the DNS lookup but generally requires an application deploy to change.
155
164
  2. Hardcoding the DNS/IP pair in /etc/hosts allows the IP to change without redeploying your application but fails to scale as the number of servers increases.
156
165
  3. Installing caching software such as nscd that uses the DNS TTL avoids most DNS lookups but makes the exact moment of change indeterminate.
157
166
 
158
167
  ## Compatibility
159
168
 
160
- Tested on:
169
+ Tested on several Ruby versions using Travis CI:
161
170
 
162
171
  * Ruby 1.8.7
163
172
  * Ruby Enterprise Edition 1.8.7
164
173
  * Ruby 1.9.2
165
174
  * Ruby 1.9.3
175
+ * Ruby 2.0.0
166
176
 
167
- Ruby 1.9 compatibility is planned for the long term. Your mileage may vary with other Ruby environments.
177
+ Ruby 2.0 compatibility is planned for the long term. Your mileage may vary with other Ruby environments.
data/Rakefile CHANGED
@@ -3,7 +3,7 @@ require 'rake/testtask'
3
3
 
4
4
  Rake::TestTask.new('test') do |t|
5
5
  t.ruby_opts << '-rubygems'
6
- t.libs << 'lib'
6
+ t.libs << 'lib' << 'test'
7
7
  t.test_files = FileList['test/*.rb']
8
8
  end
9
9
 
@@ -1,13 +1,7 @@
1
1
  require 'socket'
2
2
  require 'benchmark'
3
- require 'timeout'
4
-
5
- class << Benchmark
6
- def ms
7
- 1000 * realtime { yield }
8
- end
9
- end
10
3
 
4
+ require 'statsd/instrument/version'
11
5
 
12
6
  module StatsD
13
7
  class << self
@@ -18,19 +12,33 @@ module StatsD
18
12
  self.default_sample_rate = 1.0
19
13
  self.implementation = :statsd
20
14
 
21
- TimeoutClass = defined?(::SystemTimer) ? ::SystemTimer : ::Timeout
22
-
23
15
  # StatsD.server = 'localhost:1234'
24
16
  def self.server=(conn)
25
17
  self.host, port = conn.split(':')
26
18
  self.port = port.to_i
19
+ invalidate_socket
20
+ end
21
+
22
+ def self.host=(host)
23
+ @host = host
24
+ invalidate_socket
25
+ end
26
+
27
+ def self.port=(port)
28
+ @port = port
29
+ invalidate_socket
27
30
  end
28
31
 
29
32
  module Instrument
33
+
34
+ def self.generate_metric_name(metric_name, callee, *args)
35
+ metric_name.respond_to?(:call) ? metric_name.call(callee, args).gsub('::', '.') : metric_name.gsub('::', '.')
36
+ end
37
+
30
38
  def statsd_measure(method, name, sample_rate = StatsD.default_sample_rate)
31
39
  add_to_method(method, name, :measure) do |old_method, new_method, metric_name, *args|
32
40
  define_method(new_method) do |*args, &block|
33
- StatsD.measure(metric_name.respond_to?(:call) ? metric_name.call(self, args) : metric_name, nil, sample_rate) { send(old_method, *args, &block) }
41
+ StatsD.measure(StatsD::Instrument.generate_metric_name(metric_name, self, *args), nil, sample_rate) { send(old_method, *args, &block) }
34
42
  end
35
43
  end
36
44
  end
@@ -47,10 +55,8 @@ module StatsD
47
55
  truthiness = (yield(result) rescue false) if block_given?
48
56
  result
49
57
  ensure
50
- result = truthiness == false ? 'failure' : 'success'
51
- key = metric_name.respond_to?(:call) ? metric_name.call(self, args) : metric_name
52
-
53
- StatsD.increment("#{key}.#{result}", sample_rate)
58
+ suffix = truthiness == false ? 'failure' : 'success'
59
+ StatsD.increment("#{StatsD::Instrument.generate_metric_name(metric_name, self, *args)}.#{suffix}", 1, sample_rate)
54
60
  end
55
61
  end
56
62
  end
@@ -68,7 +74,7 @@ module StatsD
68
74
  truthiness = (yield(result) rescue false) if block_given?
69
75
  result
70
76
  ensure
71
- StatsD.increment(metric_name.respond_to?(:call) ? metric_name.call(self, args) : metric_name, sample_rate) if truthiness
77
+ StatsD.increment(StatsD::Instrument.generate_metric_name(metric_name, self, *args), sample_rate) if truthiness
72
78
  end
73
79
  end
74
80
  end
@@ -77,13 +83,30 @@ module StatsD
77
83
  def statsd_count(method, name, sample_rate = StatsD.default_sample_rate)
78
84
  add_to_method(method, name, :count) do |old_method, new_method, metric_name|
79
85
  define_method(new_method) do |*args, &block|
80
- StatsD.increment(metric_name.respond_to?(:call) ? metric_name.call(self, args) : metric_name, sample_rate)
86
+ StatsD.increment(StatsD::Instrument.generate_metric_name(metric_name, self, *args), 1, sample_rate)
81
87
  send(old_method, *args, &block)
82
88
  end
83
89
  end
84
90
  end
85
91
 
92
+ def statsd_remove_count(method, name)
93
+ remove_from_method(method, name, :count)
94
+ end
95
+
96
+ def statsd_remove_count_if(method, name)
97
+ remove_from_method(method, name, :count_if)
98
+ end
99
+
100
+ def statsd_remove_count_success(method, name)
101
+ remove_from_method(method, name, :count_success)
102
+ end
103
+
104
+ def statsd_remove_measure(method, name)
105
+ remove_from_method(method, name, :measure)
106
+ end
107
+
86
108
  private
109
+
87
110
  def add_to_method(method, name, action, &block)
88
111
  metric_name = name
89
112
 
@@ -100,42 +123,85 @@ module StatsD
100
123
  yield method_name_without_statsd, method_name_with_statsd, metric_name
101
124
  alias_method method, method_name_with_statsd
102
125
  end
126
+
127
+ def remove_from_method(method, name, action)
128
+ method_name_without_statsd = :"#{method}_for_#{action}_on_#{self.name}_without_#{name}"
129
+ method_name_with_statsd = :"#{method}_for_#{action}_on_#{self.name}_with_#{name}"
130
+ send(:remove_method, method_name_with_statsd)
131
+ alias_method method, method_name_without_statsd
132
+ send(:remove_method, method_name_without_statsd)
133
+ end
103
134
  end
104
135
 
105
136
  # glork:320|ms
106
- def self.measure(key, milli = nil, sample_rate = default_sample_rate)
137
+ def self.measure(key, milli = nil, sample_rate = default_sample_rate, tags = nil)
107
138
  result = nil
108
- ms = milli || Benchmark.ms do
139
+ ms = milli || 1000 * Benchmark.realtime do
109
140
  result = yield
110
141
  end
111
142
 
112
- write(key, ms, :ms, sample_rate)
143
+ collect(key, ms, :ms, sample_rate, tags)
113
144
  result
114
145
  end
115
146
 
116
147
  # gorets:1|c
117
- def self.increment(key, delta = 1, sample_rate = default_sample_rate)
118
- write(key, delta, :incr, sample_rate)
148
+ def self.increment(key, delta = 1, sample_rate = default_sample_rate, tags = nil)
149
+ collect(key, delta, :incr, sample_rate, tags)
119
150
  end
120
151
 
121
152
  # gaugor:333|g
122
153
  # guagor:1234|kv|@1339864935 (statsite)
123
- def self.gauge(key, value, sample_rate_or_epoch = default_sample_rate)
124
- write(key, value, :g, sample_rate_or_epoch)
154
+ def self.gauge(key, value, sample_rate_or_epoch = default_sample_rate, tags = nil)
155
+ collect(key, value, :g, sample_rate_or_epoch, tags)
125
156
  end
126
157
 
158
+ # histogram:123.45|h
159
+ def self.histogram(key, value, sample_rate_or_epoch = default_sample_rate, tags = nil)
160
+ collect(key, value, :h, sample_rate_or_epoch, tags)
161
+ end
162
+
127
163
  private
128
164
 
165
+ def self.invalidate_socket
166
+ @socket = nil
167
+ end
168
+
129
169
  def self.socket
130
- @socket ||= UDPSocket.new
170
+ if @socket.nil?
171
+ @socket = UDPSocket.new
172
+ @socket.connect(host, port)
173
+ end
174
+ @socket
131
175
  end
132
176
 
133
- def self.write(k,v,op, sample_rate = default_sample_rate)
177
+ def self.collect(k, v, op, sample_rate = default_sample_rate, tags = nil)
134
178
  return unless enabled
135
179
  return if sample_rate < 1 && rand > sample_rate
136
180
 
137
- k = k.gsub('::', '.')
181
+ command = generate_packet(k, v, op, sample_rate, tags)
182
+ write_packet(command)
183
+ end
184
+
185
+ def self.write_packet(command)
186
+ if mode.to_s == 'production'
187
+ begin
188
+ socket.send(command, 0)
189
+ rescue SocketError, IOError, SystemCallError => e
190
+ logger.error e
191
+ end
192
+ else
193
+ logger.info "[StatsD] #{command}"
194
+ end
195
+ end
138
196
 
197
+ def self.clean_tags(tags)
198
+ tags.map do |tag|
199
+ components = tag.split(':', 2)
200
+ components.map { |c| c.gsub(/[^\w\.-]+/, '_') }.join(':')
201
+ end
202
+ end
203
+
204
+ def self.generate_packet(k, v, op, sample_rate = default_sample_rate, tags = nil)
139
205
  command = "#{self.prefix + '.' if self.prefix}#{k}:#{v}"
140
206
  case op
141
207
  when :incr
@@ -144,22 +210,18 @@ module StatsD
144
210
  command << '|ms'
145
211
  when :g
146
212
  command << (self.implementation == :statsite ? '|kv' : '|g')
213
+ when :h
214
+ raise NotImplementedError, "Histograms only supported on DataDog implementation." unless self.implementation == :datadog
215
+ command << '|h'
147
216
  end
148
217
 
149
218
  command << "|@#{sample_rate}" if sample_rate < 1 || (self.implementation == :statsite && sample_rate > 1)
150
- command << "\n" if self.implementation == :statsite
151
-
152
- if mode.to_s == 'production'
153
- socket_wrapper { socket.send(command, 0, host, port) }
154
- else
155
- logger.info "[StatsD] #{command}"
219
+ if tags
220
+ raise ArgumentError, "Tags are only supported on Datadog" unless self.implementation == :datadog
221
+ command << "|##{clean_tags(tags).join(',')}"
156
222
  end
157
- end
158
223
 
159
- def self.socket_wrapper(options = {})
160
- TimeoutClass.timeout(options.fetch(:timeout, 0.1)) { yield }
161
- rescue Timeout::Error, SocketError, IOError, SystemCallError => e
162
- logger.error e
224
+ command << "\n" if self.implementation == :statsite
225
+ return command
163
226
  end
164
227
  end
165
-
@@ -0,0 +1,5 @@
1
+ module StatsD
2
+ module Instrument
3
+ VERSION = "1.6.0"
4
+ end
5
+ end
@@ -1,15 +1,23 @@
1
- Gem::Specification.new do |s|
2
- s.name = "statsd-instrument"
3
- s.version = '1.5.0'
4
- s.authors = ["Jesse Storimer", "Tobias Lutke"]
5
- s.email = ["jesse@shopify.com"]
6
- s.homepage = "http://github.com/shopify/statsd-instrument"
1
+ # encoding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'statsd/instrument/version'
7
5
 
8
- s.summary = %q{A StatsD client for Ruby apps}
9
- s.description = %q{A StatsD client for Ruby apps. Provides metaprogramming methods to inject StatsD instrumentation into your code.}
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "statsd-instrument"
8
+ spec.version = StatsD::Instrument::VERSION
9
+ spec.authors = ["Jesse Storimer", "Tobias Lutke"]
10
+ spec.email = ["jesse@shopify.com"]
11
+ spec.homepage = "https://github.com/Shopify/statsd-instrument"
12
+ spec.summary = %q{A StatsD client for Ruby apps}
13
+ spec.description = %q{A StatsD client for Ruby appspec. Provides metaprogramming methods to inject StatsD instrumentation into your code.}
14
+ spec.license = "MIT"
10
15
 
11
- s.files = `git ls-files`.split("\n")
12
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
13
20
 
14
- s.add_development_dependency 'mocha'
21
+ spec.add_development_dependency 'rake'
22
+ spec.add_development_dependency 'mocha'
15
23
  end
@@ -0,0 +1,189 @@
1
+ require 'test_helper'
2
+
3
+ module ActiveMerchant; end
4
+ class ActiveMerchant::Base
5
+ def ssl_post(arg)
6
+ if arg
7
+ 'OK'
8
+ else
9
+ raise 'Not OK'
10
+ end
11
+ end
12
+
13
+ def post_with_block(&block)
14
+ yield if block_given?
15
+ end
16
+ end
17
+
18
+ class ActiveMerchant::Gateway < ActiveMerchant::Base
19
+ def purchase(arg)
20
+ ssl_post(arg)
21
+ true
22
+ rescue
23
+ false
24
+ end
25
+
26
+ def self.sync
27
+ true
28
+ end
29
+
30
+ def self.singleton_class
31
+ class << self; self; end
32
+ end
33
+ end
34
+
35
+ class ActiveMerchant::UniqueGateway < ActiveMerchant::Base
36
+ def ssl_post(arg)
37
+ {:success => arg}
38
+ end
39
+
40
+ def purchase(arg)
41
+ ssl_post(arg)
42
+ end
43
+ end
44
+
45
+ class GatewaySubClass < ActiveMerchant::Gateway
46
+ end
47
+
48
+ ActiveMerchant::Base.extend StatsD::Instrument
49
+
50
+ class StatsDInstrumentationTest < Test::Unit::TestCase
51
+ def test_statsd_count_if
52
+ ActiveMerchant::Gateway.statsd_count_if :ssl_post, 'ActiveMerchant.Gateway.if'
53
+
54
+ StatsD.expects(:increment).with('ActiveMerchant.Gateway.if', 1).once
55
+ ActiveMerchant::Gateway.new.purchase(true)
56
+ ActiveMerchant::Gateway.new.purchase(false)
57
+
58
+ ActiveMerchant::Gateway.statsd_remove_count_if :ssl_post, 'ActiveMerchant.Gateway.if'
59
+ end
60
+
61
+ def test_statsd_count_if_with_method_receiving_block
62
+ ActiveMerchant::Base.statsd_count_if :post_with_block, 'ActiveMerchant.Base.post_with_block' do |result|
63
+ result == 'true'
64
+ end
65
+
66
+ StatsD.expects(:collect).with('ActiveMerchant.Base.post_with_block', 1, :incr, 1.0, nil).once
67
+ assert_equal 'true', ActiveMerchant::Base.new.post_with_block { 'true' }
68
+ assert_equal 'false', ActiveMerchant::Base.new.post_with_block { 'false' }
69
+
70
+ ActiveMerchant::Base.statsd_remove_count_if :post_with_block, 'ActiveMerchant.Base.post_with_block'
71
+ end
72
+
73
+ def test_statsd_count_if_with_block
74
+ ActiveMerchant::UniqueGateway.statsd_count_if :ssl_post, 'ActiveMerchant.Gateway.block' do |result|
75
+ result[:success]
76
+ end
77
+
78
+ StatsD.expects(:increment).with('ActiveMerchant.Gateway.block', 1).once
79
+ ActiveMerchant::UniqueGateway.new.purchase(true)
80
+ ActiveMerchant::UniqueGateway.new.purchase(false)
81
+
82
+ ActiveMerchant::UniqueGateway.statsd_remove_count_if :ssl_post, 'ActiveMerchant.Gateway.block'
83
+ end
84
+
85
+ def test_statsd_count_success
86
+ ActiveMerchant::Gateway.statsd_count_success :ssl_post, 'ActiveMerchant.Gateway', 0.5
87
+
88
+ StatsD.expects(:increment).with('ActiveMerchant.Gateway.success', 1, 0.5).once
89
+ StatsD.expects(:increment).with('ActiveMerchant.Gateway.failure', 1, 0.5).once
90
+
91
+ ActiveMerchant::Gateway.new.purchase(true)
92
+ ActiveMerchant::Gateway.new.purchase(false)
93
+
94
+ ActiveMerchant::Gateway.statsd_remove_count_success :ssl_post, 'ActiveMerchant.Gateway'
95
+ end
96
+
97
+ def test_statsd_count_success_with_method_receiving_block
98
+ ActiveMerchant::Base.statsd_count_success :post_with_block, 'ActiveMerchant.Base.post_with_block' do |result|
99
+ result == 'successful'
100
+ end
101
+
102
+ StatsD.expects(:collect).with('ActiveMerchant.Base.post_with_block.success', 1, :incr, 1.0, nil).once
103
+ StatsD.expects(:collect).with('ActiveMerchant.Base.post_with_block.failure', 1, :incr, 1.0, nil).once
104
+
105
+ assert_equal 'successful', ActiveMerchant::Base.new.post_with_block { 'successful' }
106
+ assert_equal 'not so successful', ActiveMerchant::Base.new.post_with_block { 'not so successful' }
107
+
108
+ ActiveMerchant::Base.statsd_remove_count_success :post_with_block, 'ActiveMerchant.Base.post_with_block'
109
+ end
110
+
111
+ def test_statsd_count_success_with_block
112
+ ActiveMerchant::UniqueGateway.statsd_count_success :ssl_post, 'ActiveMerchant.Gateway' do |result|
113
+ result[:success]
114
+ end
115
+
116
+ StatsD.expects(:increment).with('ActiveMerchant.Gateway.success', 1, StatsD.default_sample_rate)
117
+ ActiveMerchant::UniqueGateway.new.purchase(true)
118
+
119
+ StatsD.expects(:increment).with('ActiveMerchant.Gateway.failure', 1, StatsD.default_sample_rate)
120
+ ActiveMerchant::UniqueGateway.new.purchase(false)
121
+
122
+ ActiveMerchant::UniqueGateway.statsd_remove_count_success :ssl_post, 'ActiveMerchant.Gateway'
123
+ end
124
+
125
+ def test_statsd_count
126
+ ActiveMerchant::Gateway.statsd_count :ssl_post, 'ActiveMerchant.Gateway.ssl_post'
127
+
128
+ StatsD.expects(:increment).with('ActiveMerchant.Gateway.ssl_post', 1, StatsD.default_sample_rate)
129
+ ActiveMerchant::Gateway.new.purchase(true)
130
+
131
+ ActiveMerchant::Gateway.statsd_remove_count :ssl_post, 'ActiveMerchant.Gateway.ssl_post'
132
+ end
133
+
134
+ def test_statsd_count_with_name_as_lambda
135
+ metric_namer = lambda { |object, args| object.class.to_s.downcase + ".insert." + args.first.to_s }
136
+ ActiveMerchant::Gateway.statsd_count(:ssl_post, metric_namer)
137
+
138
+ StatsD.expects(:increment).with('gatewaysubclass.insert.true', 1, StatsD.default_sample_rate)
139
+ GatewaySubClass.new.purchase(true)
140
+
141
+ ActiveMerchant::Gateway.statsd_remove_count(:ssl_post, metric_namer)
142
+ end
143
+
144
+ def test_statsd_count_with_method_receiving_block
145
+ ActiveMerchant::Base.statsd_count :post_with_block, 'ActiveMerchant.Base.post_with_block'
146
+
147
+ StatsD.expects(:collect).with('ActiveMerchant.Base.post_with_block', 1, :incr, 1.0, nil)
148
+ assert_equal 'block called', ActiveMerchant::Base.new.post_with_block { 'block called' }
149
+
150
+ ActiveMerchant::Base.statsd_remove_count :post_with_block, 'ActiveMerchant.Base.post_with_block'
151
+ end
152
+
153
+ def test_statsd_measure_with_nested_modules
154
+ ActiveMerchant::UniqueGateway.statsd_measure :ssl_post, 'ActiveMerchant::Gateway.ssl_post'
155
+
156
+ StatsD.expects(:measure).with('ActiveMerchant.Gateway.ssl_post', nil, StatsD.default_sample_rate)
157
+ ActiveMerchant::UniqueGateway.new.purchase(true)
158
+
159
+ ActiveMerchant::UniqueGateway.statsd_remove_measure :ssl_post, 'ActiveMerchant::Gateway.ssl_post'
160
+ end
161
+
162
+ def test_statsd_measure
163
+ ActiveMerchant::UniqueGateway.statsd_measure :ssl_post, 'ActiveMerchant.Gateway.ssl_post', 0.3
164
+
165
+ StatsD.expects(:measure).with('ActiveMerchant.Gateway.ssl_post', nil, 0.3)
166
+ ActiveMerchant::UniqueGateway.new.purchase(true)
167
+
168
+ ActiveMerchant::UniqueGateway.statsd_remove_measure :ssl_post, 'ActiveMerchant.Gateway.ssl_post'
169
+ end
170
+
171
+ def test_statsd_measure_with_method_receiving_block
172
+ ActiveMerchant::Base.statsd_measure :post_with_block, 'ActiveMerchant.Base.post_with_block'
173
+
174
+ StatsD.expects(:collect).with('ActiveMerchant.Base.post_with_block', is_a(Float), :ms, 1.0, nil)
175
+ assert_equal 'block called', ActiveMerchant::Base.new.post_with_block { 'block called' }
176
+
177
+ ActiveMerchant::Base.statsd_remove_measure :post_with_block, 'ActiveMerchant.Base.post_with_block'
178
+ end
179
+
180
+ def test_instrumenting_class_method
181
+ ActiveMerchant::Gateway.singleton_class.extend StatsD::Instrument
182
+ ActiveMerchant::Gateway.singleton_class.statsd_count :sync, 'ActiveMerchant.Gateway.sync'
183
+
184
+ StatsD.expects(:increment).with('ActiveMerchant.Gateway.sync', 1, StatsD.default_sample_rate)
185
+ ActiveMerchant::Gateway.sync
186
+
187
+ ActiveMerchant::Gateway.singleton_class.statsd_remove_count :sync, 'ActiveMerchant.Gateway.sync'
188
+ end
189
+ end
@@ -0,0 +1,209 @@
1
+ require 'test_helper'
2
+
3
+ class StatsDTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ StatsD.stubs(:rand).returns(0.0)
7
+
8
+ UDPSocket.stubs(:new).returns(@socket = mock('socket'))
9
+ @socket.stubs(:connect)
10
+ @socket.stubs(:send)
11
+ StatsD.invalidate_socket
12
+
13
+ StatsD.stubs(:logger).returns(@logger = mock('logger'))
14
+ @logger.stubs(:info)
15
+ @logger.stubs(:error)
16
+ end
17
+
18
+ def test_statsd_measure_with_explicit_value
19
+ StatsD.expects(:collect).with('values.foobar', 42, :ms, 1.0, nil)
20
+ StatsD.measure('values.foobar', 42)
21
+ end
22
+
23
+ def test_statsd_measure_with_explicit_value_and_sample_rate
24
+ StatsD.expects(:collect).with('values.foobar', 42, :ms, 0.1, nil)
25
+ StatsD.measure('values.foobar', 42, 0.1)
26
+ end
27
+
28
+ def test_statsd_measure_with_benchmarked_value
29
+ Benchmark.stubs(:realtime).returns(1.12)
30
+ StatsD.expects(:collect).with('values.foobar', 1120.0, :ms, 1.0, nil)
31
+ StatsD.measure('values.foobar', nil) do
32
+ #noop
33
+ end
34
+ end
35
+
36
+ def test_statsd_gauge
37
+ StatsD.expects(:collect).with('values.foobar', 12, :g, 1.0, nil)
38
+ StatsD.gauge('values.foobar', 12)
39
+ end
40
+
41
+ def test_statsd_histogram_on_datadog
42
+ StatsD.stubs(:implementation).returns(:datadog)
43
+ StatsD.expects(:collect).with('values.hg', 12.33, :h, 0.2, ['tag_123', 'key-name:value123'])
44
+ StatsD.histogram('values.hg', 12.33, 0.2, ['tag_123', 'key-name:value123'])
45
+ end
46
+
47
+ def test_collect_respects_enabled
48
+ StatsD.stubs(:enabled).returns(false)
49
+ StatsD.expects(:write_packet).never
50
+ StatsD.increment('counter')
51
+ end
52
+
53
+ def test_collect_respects_sampling_rate
54
+ StatsD.expects(:write_packet).once
55
+
56
+ StatsD.stubs(:rand).returns(0.6)
57
+ StatsD.increment('counter', 1, 0.5)
58
+
59
+ StatsD.stubs(:rand).returns(0.4)
60
+ StatsD.increment('counter', 1, 0.5)
61
+ end
62
+
63
+ def test_support_counter_syntax
64
+ StatsD.expects(:write_packet).with('counter:1|c')
65
+ StatsD.increment('counter')
66
+
67
+ StatsD.expects(:write_packet).with('counter:10|c|@0.5')
68
+ StatsD.increment('counter', 10, 0.5)
69
+ end
70
+
71
+ def test_supports_gauge_syntax
72
+ StatsD.expects(:write_packet).with('fooy:1.23|g')
73
+ StatsD.gauge('fooy', 1.23)
74
+
75
+ StatsD.expects(:write_packet).with('fooy:42|g|@0.01')
76
+ StatsD.gauge('fooy', 42, 0.01)
77
+ end
78
+
79
+ def test_support_timing_syntax
80
+ StatsD.expects(:write_packet).with('duration:1.23|ms')
81
+ StatsD.measure('duration', 1.23)
82
+
83
+ StatsD.expects(:write_packet).with('duration:0.42|ms|@0.01')
84
+ StatsD.measure('duration', 0.42, 0.01)
85
+ end
86
+
87
+ def test_histogram_syntax_on_datadog
88
+ StatsD.stubs(:implementation).returns(:datadog)
89
+
90
+ StatsD.expects(:write_packet).with('fooh:42.4|h')
91
+ StatsD.histogram('fooh', 42.4)
92
+ end
93
+
94
+ def test_support_tags_syntax_on_datadog
95
+ StatsD.stubs(:implementation).returns(:datadog)
96
+
97
+ StatsD.expects(:write_packet).with("fooc:3|c|#topic:foo,bar")
98
+ StatsD.increment('fooc', 3, 1.0, ['topic:foo', 'bar'])
99
+ end
100
+
101
+ def test_raise_when_using_tags_and_not_on_datadog
102
+ StatsD.stubs(:implementation).returns(:other)
103
+ assert_raises(ArgumentError) { StatsD.increment('fooc', 3, 1.0, ['nonempty']) }
104
+ end
105
+
106
+ def test_rewrite_shitty_tags
107
+ StatsD.stubs(:implementation).returns(:datadog)
108
+
109
+ assert_equal ['igno_red'], StatsD.clean_tags(['igno,red'])
110
+ assert_equal ['igno_red'], StatsD.clean_tags(['igno red'])
111
+ assert_equal ['test:test_test'], StatsD.clean_tags(['test:test:test'])
112
+
113
+ StatsD.expects(:write_packet).with("fooc:3|c|#topic:foo_foo,bar_")
114
+ StatsD.increment('fooc', 3, 1.0, ['topic:foo : foo', 'bar '])
115
+ end
116
+
117
+ def test_supports_gauge_syntax_on_statsite
118
+ StatsD.stubs(:implementation).returns(:statsite)
119
+
120
+ StatsD.expects(:write_packet).with("fooy:42|kv\n")
121
+ StatsD.gauge('fooy', 42)
122
+ end
123
+
124
+ def test_supports_gauge_timestamp_on_statsite
125
+ StatsD.stubs(:implementation).returns(:statsite)
126
+
127
+ StatsD.expects(:write_packet).with("fooy:42|kv|@123456\n")
128
+ StatsD.gauge('fooy', 42, 123456)
129
+ end
130
+
131
+ def test_support_key_prefix
132
+ StatsD.expects(:write_packet).with('prefix.counter:1|c').once
133
+ StatsD.expects(:write_packet).with('counter:1|c').once
134
+
135
+ StatsD.stubs(:prefix).returns('prefix')
136
+ StatsD.increment('counter')
137
+ StatsD.stubs(:prefix).returns(nil)
138
+ StatsD.increment('counter')
139
+ end
140
+
141
+ def test_development_mode_uses_logger
142
+ StatsD.stubs(:mode).returns(:development)
143
+
144
+ @logger.expects(:info).with(regexp_matches(/\A\[StatsD\] /))
145
+ StatsD.increment('counter')
146
+ end
147
+
148
+ def test_production_mode_uses_udp_socket
149
+ StatsD.stubs(:mode).returns(:production)
150
+ StatsD.server = "localhost:9815"
151
+
152
+ @socket.expects(:connect).with('localhost', 9815).once
153
+ @socket.expects(:send).with(is_a(String), 0).twice
154
+ StatsD.increment('counter')
155
+ StatsD.increment('counter')
156
+ end
157
+
158
+ def test_changing_host_or_port_should_create_new_socket
159
+ @socket.expects(:connect).with('localhost', 1234).once
160
+ @socket.expects(:connect).with('localhost', 2345).once
161
+ @socket.expects(:connect).with('127.0.0.1', 2345).once
162
+
163
+ StatsD.server = "localhost:1234"
164
+ StatsD.send(:socket)
165
+
166
+ StatsD.port = 2345
167
+ StatsD.send(:socket)
168
+
169
+ StatsD.host = '127.0.0.1'
170
+ StatsD.send(:socket)
171
+ end
172
+
173
+ def test_socket_error_should_not_raise_but_log
174
+ StatsD.stubs(:mode).returns(:production)
175
+ @socket.stubs(:connect).raises(SocketError)
176
+
177
+ @logger.expects(:error).with(instance_of(SocketError))
178
+ StatsD.measure('values.foobar', 42)
179
+ end
180
+
181
+ def test_system_call_error_should_not_raise_but_log
182
+ StatsD.stubs(:mode).returns(:production)
183
+ @socket.stubs(:send).raises(Errno::ETIMEDOUT)
184
+
185
+ @logger.expects(:error).with(instance_of(Errno::ETIMEDOUT))
186
+ StatsD.measure('values.foobar', 42)
187
+ end
188
+
189
+ def test_io_error_should_not_raise_but_log
190
+ StatsD.stubs(:mode).returns(:production)
191
+ @socket.stubs(:send).raises(IOError)
192
+
193
+ @logger.expects(:error).with(instance_of(IOError))
194
+ StatsD.measure('values.foobar', 42)
195
+ end
196
+
197
+ def test_live_local_udp_socket
198
+ UDPSocket.unstub(:new)
199
+
200
+ StatsD.stubs(:mode).returns(:production)
201
+ StatsD.server = "localhost:31798"
202
+
203
+ server = UDPSocket.new
204
+ server.bind('localhost', 31798)
205
+
206
+ StatsD.increment('counter')
207
+ assert_equal "counter:1|c", server.recvfrom(100).first
208
+ end
209
+ end
@@ -0,0 +1,7 @@
1
+ require 'rubygems'
2
+ require 'statsd-instrument'
3
+ require 'test/unit'
4
+ require 'mocha/setup'
5
+
6
+ require 'logger'
7
+ StatsD.logger = Logger.new('/dev/null')
metadata CHANGED
@@ -1,8 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: statsd-instrument
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.0
5
- prerelease:
4
+ version: 1.6.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Jesse Storimer
@@ -10,26 +9,38 @@ authors:
10
9
  autorequire:
11
10
  bindir: bin
12
11
  cert_chain: []
13
- date: 2013-01-25 00:00:00.000000000 Z
12
+ date: 2014-01-21 00:00:00.000000000 Z
14
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - '>='
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - '>='
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
15
28
  - !ruby/object:Gem::Dependency
16
29
  name: mocha
17
30
  requirement: !ruby/object:Gem::Requirement
18
- none: false
19
31
  requirements:
20
- - - ! '>='
32
+ - - '>='
21
33
  - !ruby/object:Gem::Version
22
34
  version: '0'
23
35
  type: :development
24
36
  prerelease: false
25
37
  version_requirements: !ruby/object:Gem::Requirement
26
- none: false
27
38
  requirements:
28
- - - ! '>='
39
+ - - '>='
29
40
  - !ruby/object:Gem::Version
30
41
  version: '0'
31
- description: A StatsD client for Ruby apps. Provides metaprogramming methods to inject
32
- StatsD instrumentation into your code.
42
+ description: A StatsD client for Ruby appspec. Provides metaprogramming methods to
43
+ inject StatsD instrumentation into your code.
33
44
  email:
34
45
  - jesse@shopify.com
35
46
  executables: []
@@ -44,31 +55,36 @@ files:
44
55
  - Rakefile
45
56
  - lib/statsd-instrument.rb
46
57
  - lib/statsd/instrument.rb
58
+ - lib/statsd/instrument/version.rb
47
59
  - statsd-instrument.gemspec
48
- - test/statsd-instrument_test.rb
49
- homepage: http://github.com/shopify/statsd-instrument
50
- licenses: []
60
+ - test/statsd_instrumentation_test.rb
61
+ - test/statsd_test.rb
62
+ - test/test_helper.rb
63
+ homepage: https://github.com/Shopify/statsd-instrument
64
+ licenses:
65
+ - MIT
66
+ metadata: {}
51
67
  post_install_message:
52
68
  rdoc_options: []
53
69
  require_paths:
54
70
  - lib
55
71
  required_ruby_version: !ruby/object:Gem::Requirement
56
- none: false
57
72
  requirements:
58
- - - ! '>='
73
+ - - '>='
59
74
  - !ruby/object:Gem::Version
60
75
  version: '0'
61
76
  required_rubygems_version: !ruby/object:Gem::Requirement
62
- none: false
63
77
  requirements:
64
- - - ! '>='
78
+ - - '>='
65
79
  - !ruby/object:Gem::Version
66
80
  version: '0'
67
81
  requirements: []
68
82
  rubyforge_project:
69
- rubygems_version: 1.8.23
83
+ rubygems_version: 2.0.14
70
84
  signing_key:
71
- specification_version: 3
85
+ specification_version: 4
72
86
  summary: A StatsD client for Ruby apps
73
87
  test_files:
74
- - test/statsd-instrument_test.rb
88
+ - test/statsd_instrumentation_test.rb
89
+ - test/statsd_test.rb
90
+ - test/test_helper.rb
@@ -1,339 +0,0 @@
1
- # Allow testing with the SystemTimer gem on 1.8
2
- if RUBY_VERSION =~ /^1.8/
3
- puts "Loading SystemTimer gem"
4
- require 'system_timer'
5
- end
6
-
7
- require 'statsd-instrument'
8
- require 'test/unit'
9
- require 'mocha'
10
- require 'logger'
11
-
12
- StatsD.logger = Logger.new('/dev/null')
13
-
14
- module ActiveMerchant; end
15
- class ActiveMerchant::Base
16
- def ssl_post(arg)
17
- if arg
18
- 'OK'
19
- else
20
- raise 'Not OK'
21
- end
22
- end
23
-
24
- def post_with_block(&block)
25
- yield if block_given?
26
- end
27
- end
28
-
29
- class ActiveMerchant::Gateway < ActiveMerchant::Base
30
- def purchase(arg)
31
- ssl_post(arg)
32
- true
33
- rescue
34
- false
35
- end
36
-
37
- def self.sync
38
- true
39
- end
40
-
41
- def self.singleton_class
42
- class << self; self; end
43
- end
44
- end
45
-
46
- class ActiveMerchant::UniqueGateway < ActiveMerchant::Base
47
- def ssl_post(arg)
48
- {:success => arg}
49
- end
50
-
51
- def purchase(arg)
52
- ssl_post(arg)
53
- end
54
- end
55
-
56
- class GatewaySubClass < ActiveMerchant::Gateway
57
- end
58
-
59
- ActiveMerchant::Base.extend StatsD::Instrument
60
-
61
- class StatsDTest < Test::Unit::TestCase
62
- def setup
63
- StatsD.mode = nil
64
- StatsD.stubs(:increment)
65
- end
66
-
67
- def test_statsd_count_if
68
- ActiveMerchant::Gateway.statsd_count_if :ssl_post, 'ActiveMerchant.Gateway.if'
69
-
70
- StatsD.expects(:increment).with(includes('if'), 1).once
71
- ActiveMerchant::Gateway.new.purchase(true)
72
- ActiveMerchant::Gateway.new.purchase(false)
73
- end
74
-
75
- def test_statsd_count_if_with_method_receiving_block
76
- ActiveMerchant::Base.statsd_count_if :post_with_block, 'ActiveMerchant.Base.post_with_block' do |result|
77
- result[:success]
78
- end
79
-
80
- return_value = ActiveMerchant::Base.new.post_with_block {'block called'}
81
-
82
- assert_equal 'block called', return_value
83
- end
84
-
85
- def test_statsd_count_if_with_block
86
- ActiveMerchant::UniqueGateway.statsd_count_if :ssl_post, 'ActiveMerchant.Gateway.block' do |result|
87
- result[:success]
88
- end
89
-
90
- StatsD.expects(:increment).with(includes('block'), 1).once
91
- ActiveMerchant::UniqueGateway.new.purchase(true)
92
- ActiveMerchant::UniqueGateway.new.purchase(false)
93
- end
94
-
95
- def test_statsd_count_success
96
- ActiveMerchant::Gateway.statsd_count_success :ssl_post, 'ActiveMerchant.Gateway', 0.5
97
-
98
- StatsD.expects(:increment).with(includes('success'), 0.5)
99
- ActiveMerchant::Gateway.new.purchase(true)
100
-
101
- StatsD.expects(:increment).with(includes('failure'), 0.5)
102
- ActiveMerchant::Gateway.new.purchase(false)
103
- end
104
-
105
- def test_statsd_count_success_with_method_receiving_block
106
- ActiveMerchant::Base.statsd_count_success :post_with_block, 'ActiveMerchant.Base.post_with_block' do |result|
107
- result[:success]
108
- end
109
-
110
- return_value = ActiveMerchant::Base.new.post_with_block {'block called'}
111
-
112
- assert_equal 'block called', return_value
113
- end
114
-
115
- def test_statsd_count_success_with_block
116
- ActiveMerchant::UniqueGateway.statsd_count_success :ssl_post, 'ActiveMerchant.Gateway' do |result|
117
- result[:success]
118
- end
119
-
120
- StatsD.expects(:increment).with(includes('success'), StatsD.default_sample_rate)
121
- ActiveMerchant::UniqueGateway.new.purchase(true)
122
-
123
- StatsD.expects(:increment).with(includes('failure'), StatsD.default_sample_rate)
124
- ActiveMerchant::UniqueGateway.new.purchase(false)
125
- end
126
-
127
- def test_statsd_count
128
- ActiveMerchant::Gateway.statsd_count :ssl_post, 'ActiveMerchant.Gateway.ssl_post'
129
-
130
- StatsD.expects(:increment).with(includes('ssl_post'), 1)
131
- ActiveMerchant::Gateway.new.purchase(true)
132
- end
133
-
134
- def test_statsd_count_with_name_as_lambda
135
- ActiveMerchant::Gateway.statsd_count(:ssl_post, lambda {|object, args| object.class.to_s.downcase + ".insert." + args.first.to_s})
136
-
137
- StatsD.expects(:increment).with('gatewaysubclass.insert.true', 1)
138
- GatewaySubClass.new.purchase(true)
139
- end
140
-
141
- def test_statsd_count_with_method_receiving_block
142
- ActiveMerchant::Base.statsd_count :post_with_block, 'ActiveMerchant.Base.post_with_block'
143
-
144
- return_value = ActiveMerchant::Base.new.post_with_block {'block called'}
145
-
146
- assert_equal 'block called', return_value
147
- end
148
-
149
- def test_statsd_measure_with_nested_modules
150
- ActiveMerchant::UniqueGateway.statsd_measure :ssl_post, 'ActiveMerchant::Gateway.ssl_post'
151
-
152
- StatsD.stubs(:mode).returns(:production)
153
- UDPSocket.any_instance.expects(:send).with(regexp_matches(/ActiveMerchant\.Gateway\.ssl_post:\d\.\d{2,}\|ms/), 0, 'localhost', 123).at_least(1)
154
-
155
- ActiveMerchant::UniqueGateway.new.purchase(true)
156
- end
157
-
158
- def test_statsd_measure
159
- ActiveMerchant::UniqueGateway.statsd_measure :ssl_post, 'ActiveMerchant.Gateway.ssl_post', 0.3
160
-
161
- StatsD.expects(:write).with('ActiveMerchant.Gateway.ssl_post', is_a(Float), :ms, 0.3).returns({:success => true})
162
- ActiveMerchant::UniqueGateway.new.purchase(true)
163
- end
164
-
165
-
166
- def test_statsd_measure_with_method_receiving_block
167
- ActiveMerchant::Base.statsd_measure :post_with_block, 'ActiveMerchant.Base.post_with_block'
168
-
169
- return_value = ActiveMerchant::Base.new.post_with_block {'block called'}
170
-
171
- assert_equal 'block called', return_value
172
- end
173
-
174
- def test_instrumenting_class_method
175
- ActiveMerchant::Gateway.singleton_class.extend StatsD::Instrument
176
- ActiveMerchant::Gateway.singleton_class.statsd_count :sync, 'ActiveMerchant.Gateway.sync'
177
-
178
- StatsD.expects(:increment).with(includes('sync'), 1)
179
- ActiveMerchant::Gateway.sync
180
- end
181
-
182
- def test_count_with_sampling
183
- StatsD.unstub(:increment)
184
- StatsD.stubs(:rand).returns(0.6)
185
- StatsD.logger.expects(:info).never
186
-
187
- StatsD.increment('sampling.foo.bar', 1, 0.1)
188
- end
189
-
190
- def test_count_with_successful_sample
191
- StatsD.unstub(:increment)
192
- StatsD.stubs(:rand).returns(0.01)
193
- StatsD.logger.expects(:info).once.with do |string|
194
- string.include?('@0.1')
195
- end
196
-
197
- StatsD.increment('sampling.foo.bar', 1, 0.1)
198
- end
199
-
200
- def test_production_mode_should_use_udp_socket
201
- StatsD.unstub(:increment)
202
-
203
- StatsD.mode = :production
204
- StatsD.server = 'localhost:123'
205
- UDPSocket.any_instance.expects(:send)
206
-
207
- StatsD.increment('fooz')
208
- StatsD.mode = :test
209
- end
210
-
211
- def test_write_supports_gauge_syntax
212
- StatsD.unstub(:gauge)
213
-
214
- StatsD.mode = :production
215
- StatsD.server = 'localhost:123'
216
-
217
- UDPSocket.any_instance.expects(:send).with('fooy:42|g', 0, 'localhost', 123)
218
-
219
- StatsD.gauge('fooy', 42)
220
- end
221
-
222
- def test_write_supports_statsite_gauge_syntax
223
- StatsD.unstub(:gauge)
224
-
225
- StatsD.mode = :production
226
- StatsD.server = 'localhost:123'
227
- StatsD.implementation = :statsite
228
-
229
- UDPSocket.any_instance.expects(:send).with("fooy:42|kv\n", 0, 'localhost', 123)
230
-
231
- StatsD.gauge('fooy', 42)
232
- end
233
-
234
- def test_write_supports_statsite_gauge_timestamp
235
- StatsD.unstub(:gauge)
236
-
237
- StatsD.mode = :production
238
- StatsD.server = 'localhost:123'
239
- StatsD.implementation = :statsite
240
-
241
- UDPSocket.any_instance.expects(:send).with("fooy:42|kv|@123456\n", 0, 'localhost', 123)
242
-
243
- StatsD.gauge('fooy', 42, 123456)
244
- end
245
-
246
- def test_should_not_write_when_disabled
247
- StatsD.enabled = false
248
- StatsD.expects(:logger).never
249
- StatsD.increment('fooz')
250
- StatsD.enabled = true
251
- end
252
-
253
- def test_statsd_mode
254
- StatsD.unstub(:increment)
255
- StatsD.logger.expects(:info).once
256
- StatsD.expects(:socket_wrapper).twice
257
- StatsD.mode = :foo
258
- StatsD.increment('foo')
259
- StatsD.mode = :production
260
- StatsD.increment('foo')
261
- StatsD.mode = 'production'
262
- StatsD.increment('foo')
263
- end
264
-
265
- def test_statsd_prefix
266
- StatsD.unstub(:increment)
267
- StatsD.prefix = 'my_app'
268
- StatsD.logger.expects(:info).once.with do |string|
269
- string.include?('my_app.foo')
270
- end
271
- StatsD.logger.expects(:info).once.with do |string|
272
- string.include?('food')
273
- end
274
- StatsD.increment('foo')
275
- StatsD.prefix = nil
276
- StatsD.increment('food')
277
- end
278
-
279
- def test_statsd_measure_with_explicit_value
280
- StatsD.expects(:write).with('values.foobar', 42, :ms, is_a(Numeric))
281
-
282
- StatsD.measure('values.foobar', 42)
283
- end
284
-
285
- def test_statsd_measure_with_explicit_value_and_sample_rate
286
- StatsD.expects(:write).with('values.foobar', 42, :ms, 0.1)
287
-
288
- StatsD.measure('values.foobar', 42, 0.1)
289
- end
290
-
291
- def test_statsd_gauge
292
- StatsD.expects(:write).with('values.foobar', 12, :g, 1)
293
-
294
- StatsD.default_sample_rate = 1
295
-
296
- StatsD.gauge('values.foobar', 12)
297
- end
298
-
299
- def test_socket_error_should_not_raise
300
- StatsD.mode = :production
301
- UDPSocket.any_instance.expects(:send).raises(SocketError)
302
- StatsD.measure('values.foobar', 42)
303
- StatsD.mode = :test
304
- end
305
-
306
- def test_timeout_error_should_not_raise
307
- StatsD.mode = :production
308
- UDPSocket.any_instance.expects(:send).raises(Timeout::Error)
309
- StatsD.measure('values.foobar', 42)
310
- StatsD.mode = :test
311
- end
312
-
313
- def test_system_call_error_should_not_raise
314
- StatsD.mode = :production
315
- UDPSocket.any_instance.expects(:send).raises(Errno::ETIMEDOUT)
316
- StatsD.measure('values.foobar', 42)
317
- StatsD.mode = :test
318
- end
319
-
320
- def test_io_error_should_not_raise
321
- StatsD.mode = :production
322
- UDPSocket.any_instance.expects(:send).raises(IOError)
323
- StatsD.measure('values.foobar', 42)
324
- StatsD.mode = :test
325
- end
326
-
327
- def test_long_request_should_timeout
328
- StatsD.mode = :production
329
- UDPSocket.any_instance.expects(:send).yields do
330
- begin
331
- Timeout.timeout(0.5) { sleep 1 }
332
- rescue Timeout::Error
333
- raise "Allowed long running request"
334
- end
335
- end
336
- StatsD.measure('values.foobar', 42)
337
- StatsD.mode = :test
338
- end
339
- end