statsd-instrument 1.1.2 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.8.7
4
+ - ree
5
+ - 1.9.2
6
+ - 1.9.3
data/Gemfile CHANGED
@@ -1,4 +1,10 @@
1
1
  source "http://rubygems.org"
2
2
 
3
+ group :test do
4
+ gem 'rake'
5
+ end
6
+
3
7
  # Specify your gem's dependencies in statsd-instrument.gemspec
4
8
  gemspec
9
+
10
+ gem 'SystemTimer', :platform => :mri_18, :require => ''
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # StatsD client for Ruby apps
2
2
 
3
+ ![Built on Travis](https://secure.travis-ci.org/Shopify/statsd-instrument.png?branch=master)
4
+
3
5
  This is a ruby client for statsd (http://github.com/etsy/statsd). It provides a lightweight way to track and measure metrics in your application.
4
6
 
5
7
  We call out to statsd by sending data over a UDP socket. UDP sockets are fast, but unreliable, there is no guarantee that your data will ever arrive at it's location. In other words, fire and forget. This is perfect for this use case because it means your code doesn't get bogged down trying to log statistics. We send data to statsd several times per request and haven't noticed a performance hit.
@@ -20,6 +22,7 @@ This is the same as what Etsy uses (mentioned in the README for http://github.co
20
22
  StatsD.server = 'statsd.myservice.com:8125'
21
23
  StatsD.logger = Rails.logger
22
24
  StatsD.mode = :production
25
+ StatsD.prefix = 'my_app' # An optional prefix to be added to each stat.
23
26
  StatsD.default_sample_rate = 0.1 # Sample 10% of events. By default all events are reported.
24
27
  ```
25
28
 
@@ -132,3 +135,22 @@ You can instrument class methods, just like instance methods, using the metaprog
132
135
  AWS::S3::Base.singleton_class.extend StatsD::Instrument
133
136
  AWS::S3::Base.singleton_class.statsd_measure :request, 'S3.request'
134
137
  ```
138
+
139
+ ## Reliance on DNS
140
+ 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.
141
+
142
+ ### Common Workarounds
143
+ 1. Using an IP avoids the DNS lookup but generally requires an application deploy to change.
144
+ 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.
145
+ 3. Installing caching software such as nscd that uses the DNS TTL avoids most DNS lookups but makes the exact moment of change indeterminate.
146
+
147
+ ## Compatibility
148
+
149
+ Tested on:
150
+
151
+ * Ruby 1.8.7
152
+ * Ruby Enterprise Edition 1.8.7
153
+ * Ruby 1.9.2
154
+ * Ruby 1.9.3
155
+
156
+ Ruby 1.9 compatibility is planned for the long term. Your mileage may vary with other Ruby environments.
@@ -11,12 +11,13 @@ end
11
11
 
12
12
  module StatsD
13
13
  class << self
14
- attr_accessor :host, :port, :mode, :logger, :enabled, :default_sample_rate
14
+ attr_accessor :host, :port, :mode, :logger, :enabled, :default_sample_rate,
15
+ :prefix
15
16
  end
16
17
  self.enabled = true
17
18
  self.default_sample_rate = 1
18
19
 
19
- Timeout = defined?(::SystemTimer) ? ::SystemTimer : ::Timeout
20
+ TimeoutClass = defined?(::SystemTimer) ? ::SystemTimer : ::Timeout
20
21
 
21
22
  # StatsD.server = 'localhost:1234'
22
23
  def self.server=(conn)
@@ -113,6 +114,11 @@ module StatsD
113
114
  write(key, delta, :incr, sample_rate)
114
115
  end
115
116
 
117
+ #gaugor:333|g
118
+ def self.gauge(key, value, sample_rate = default_sample_rate)
119
+ write(key, value, :g, sample_rate)
120
+ end
121
+
116
122
  private
117
123
 
118
124
  def self.socket
@@ -123,17 +129,19 @@ module StatsD
123
129
  return unless enabled
124
130
  return if sample_rate < 1 && rand > sample_rate
125
131
 
126
- command = "#{k}:#{v}"
132
+ command = "#{self.prefix + '.' if self.prefix}#{k}:#{v}"
127
133
  case op
128
134
  when :incr
129
135
  command << '|c'
130
136
  when :ms
131
137
  command << '|ms'
138
+ when :g
139
+ command << '|g'
132
140
  end
133
141
 
134
142
  command << "|@#{sample_rate}" if sample_rate < 1
135
143
 
136
- if mode == :production
144
+ if mode.to_s == 'production'
137
145
  socket_wrapper { socket.send(command, 0, host, port) }
138
146
  else
139
147
  logger.info "[StatsD] #{command}"
@@ -141,7 +149,7 @@ module StatsD
141
149
  end
142
150
 
143
151
  def self.socket_wrapper(options = {})
144
- Timeout.timeout(options.fetch(:timeout, 0.1)) { yield }
152
+ TimeoutClass.timeout(options.fetch(:timeout, 0.1)) { yield }
145
153
  rescue Timeout::Error, SocketError, IOError, SystemCallError => e
146
154
  logger.error e
147
155
  end
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "statsd-instrument"
3
- s.version = '1.1.2'
3
+ s.version = '1.2.0'
4
4
  s.authors = ["Jesse Storimer"]
5
5
  s.email = ["jesse@shopify.com"]
6
6
  s.homepage = "http://github.com/shopify/statsd-instrument"
@@ -1,3 +1,9 @@
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
+
1
7
  require 'statsd-instrument'
2
8
  require 'test/unit'
3
9
  require 'mocha'
@@ -47,6 +53,7 @@ ActiveMerchant::Base.extend StatsD::Instrument
47
53
 
48
54
  class StatsDTest < Test::Unit::TestCase
49
55
  def setup
56
+ StatsD.mode = nil
50
57
  StatsD.stubs(:increment)
51
58
  end
52
59
 
@@ -141,19 +148,64 @@ class StatsDTest < Test::Unit::TestCase
141
148
  StatsD.mode = :test
142
149
  end
143
150
 
151
+ def test_write_supports_gauge_syntax
152
+ StatsD.unstub(:gauge)
153
+
154
+ StatsD.mode = :production
155
+ StatsD.server = 'localhost:123'
156
+
157
+ UDPSocket.any_instance.expects(:send).with('fooy:42|g', 0, 'localhost', 123)
158
+
159
+ StatsD.gauge('fooy', 42)
160
+ end
161
+
144
162
  def test_should_not_write_when_disabled
145
163
  StatsD.enabled = false
146
164
  StatsD.expects(:logger).never
147
165
  StatsD.increment('fooz')
148
166
  StatsD.enabled = true
149
167
  end
150
-
168
+
169
+ def test_statsd_mode
170
+ StatsD.unstub(:increment)
171
+ StatsD.logger.expects(:info).once
172
+ StatsD.expects(:socket_wrapper).twice
173
+ StatsD.mode = :foo
174
+ StatsD.increment('foo')
175
+ StatsD.mode = :production
176
+ StatsD.increment('foo')
177
+ StatsD.mode = 'production'
178
+ StatsD.increment('foo')
179
+ end
180
+
181
+ def test_statsd_prefix
182
+ StatsD.unstub(:increment)
183
+ StatsD.prefix = 'my_app'
184
+ StatsD.logger.expects(:info).once.with do |string|
185
+ string.include?('my_app.foo')
186
+ end
187
+ StatsD.logger.expects(:info).once.with do |string|
188
+ string.include?('food')
189
+ end
190
+ StatsD.increment('foo')
191
+ StatsD.prefix = nil
192
+ StatsD.increment('food')
193
+ end
194
+
151
195
  def test_statsd_measure_with_explicit_value
152
196
  StatsD.expects(:write).with('values.foobar', 42, :ms)
153
197
 
154
198
  StatsD.measure('values.foobar', 42)
155
199
  end
156
200
 
201
+ def test_statsd_gauge
202
+ StatsD.expects(:write).with('values.foobar', 12, :g, 1)
203
+
204
+ StatsD.default_sample_rate = 1
205
+
206
+ StatsD.gauge('values.foobar', 12)
207
+ end
208
+
157
209
  def test_socket_error_should_not_raise
158
210
  StatsD.mode = :production
159
211
  UDPSocket.any_instance.expects(:send).raises(SocketError)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: statsd-instrument
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.2
4
+ version: 1.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-02-15 00:00:00.000000000 Z
12
+ date: 2012-04-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: mocha
16
- requirement: &2155684560 !ruby/object:Gem::Requirement
16
+ requirement: &2178819120 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,7 +21,7 @@ dependencies:
21
21
  version: '0'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *2155684560
24
+ version_requirements: *2178819120
25
25
  description: A StatsD client for Ruby apps. Provides metaprogramming methods to inject
26
26
  StatsD instrumentation into your code.
27
27
  email:
@@ -31,6 +31,7 @@ extensions: []
31
31
  extra_rdoc_files: []
32
32
  files:
33
33
  - .gitignore
34
+ - .travis.yml
34
35
  - Gemfile
35
36
  - LICENSE
36
37
  - README.md