statsd-instrument 2.1.1 → 2.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 46fc4b2306e65ec55ec96d05f26653460d43ece8
4
- data.tar.gz: c4657dafe04761702c5464de9b277f77e1106530
3
+ metadata.gz: 185cb2c919df0365e7808fdc36f0eece2ffac2aa
4
+ data.tar.gz: 6f64c341a7d7cd1ef9ae7400b99cca75641388f8
5
5
  SHA512:
6
- metadata.gz: 2e450334ecc746a8066b86975a208a5bf9d0bec99d6117080aa407106909cc3636321fd49e6663f847bce8d40da7a19e3bfd945087420c8ad04b70032f029c45
7
- data.tar.gz: a080a4c6497edd7881a9abd20f955e2796b08c9524c246cfbbd62cc6d7a66e8d03a4978c4c8dcd544110b5e7c07365dbae89b7f8748f5916eaf95d038a08c6da
6
+ metadata.gz: 95db3eab39e1cecaa4938bab5df81de7f9c4c0b36d8f0640a0a95b6b0d036f65edb91f180a41d3ee64446841430f29d58d42ad9c58bfec1967114236f0d18030
7
+ data.tar.gz: 7df38af3a361e4ba803994f09292c66c2c78ecaf681e02aa937982cdd7ab9005c0872a1442a96d0d2fdcafc43e36535363a38cb3dadc94cc3bf49761bc49b6cd
@@ -1,10 +1,8 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.0
4
- - 2.1
5
- - 2.2
6
- - jruby-19mode
7
- - rbx-2
3
+ - 2.1.10
4
+ - 2.2.6
5
+ - 2.3.3
8
6
  - ruby-head
9
7
 
10
8
  matrix:
@@ -5,9 +5,51 @@ please at an entry to the "unreleased changes" section below.
5
5
 
6
6
  ### Unreleased changes
7
7
 
8
+ ### Version 2.1.2
9
+
10
+ - Use `prepend` instead of rewriting classes for metaprogramming methods.
11
+ - RSpec: make matchers more flexible.
12
+ - Bugfix: Only ask Rails for the environment when it's actually loaded.
13
+
14
+ ### Version 2.1.1
15
+
16
+ - Add `assert_statsd_calls` to from validating cases where one has multiple metrics with the same name and type being recorded, but with different options.
17
+
18
+ ### Version 2.1.0
19
+
20
+ - Fix rspec-rails compatibility
21
+ - Add `value` keyword argument to all metric types.
22
+
23
+ ### Version 2.0.12
24
+
25
+ - Make StatsD client thread-safe
26
+ - Assertions: Ensure sample rates have proper values.
27
+ - Assertions: Make tag assertions work more intuitively
28
+ - RSpec: Add backwards compatibility for RSpec 2
29
+
30
+ ### Version 2.0.11
31
+
32
+ - Don't change method visibility when adding instrumentation to methods using metaprogramming
33
+ - RSpec: add support for Compound expectations
34
+
35
+ ### Version 2.0.10
36
+
37
+ - Assertions: allow ignoring certain tags when asserting for other tags to be present.
38
+
39
+ ### Version 2.0.9
40
+
41
+ - Better error message for `assert_no_statsd_calls`
42
+
43
+ ### Version 2.0.8
44
+
45
+ - More tag handling performance improvements.
46
+ - RSpec matchers documentation improvements
47
+
48
+ ### Version 2.0.7
49
+
50
+ - Tag handling performance improvements.
51
+ - Test against Ruby 2.2.
8
52
  - Drop support for Ruby 1.9.3.
9
- - Add support for Ruby 2.2.
10
- - Make library compatible with RSpec 2.
11
53
 
12
54
  ### Version 2.0.6
13
55
 
@@ -15,7 +57,6 @@ please at an entry to the "unreleased changes" section below.
15
57
  - Default behavior: in a **staging** environment, the defaults are now the same as in a **production environment**.
16
58
  - Documentation overhaul
17
59
 
18
-
19
60
  ### Version 2.0.5
20
61
 
21
62
  - Allow for nested assertions using the `assert_statsd_*` assertion methods.
data/README.md CHANGED
@@ -280,6 +280,12 @@ RSpec.describe 'Matchers' do
280
280
  }.to trigger_statsd_increment('counter', times: 2)
281
281
  end
282
282
 
283
+ it 'will pass if it matches argument' do
284
+ expect {
285
+ StatsD.measure('counter', 0.3001)
286
+ }.to trigger_statsd_measure('counter', value: be_between(0.29, 0.31))
287
+ end
288
+
283
289
  it 'will pass if there is no matching StatsD call on negative expectation' do
284
290
  expect { StatsD.increment('other_counter') }.not_to trigger_statsd_increment('counter')
285
291
  end
@@ -40,6 +40,16 @@ module StatsD
40
40
  # StatsD metrics. E.g., yopu can create counters on how often a method is called, how often it is
41
41
  # successful, the duration of the methods call, etc.
42
42
  module Instrument
43
+ # @private
44
+ def statsd_instrumentations
45
+ if defined?(@statsd_instrumentations)
46
+ @statsd_instrumentations
47
+ elsif respond_to?(:superclass) && superclass.respond_to?(:statsd_instrumentations)
48
+ superclass.statsd_instrumentations
49
+ else
50
+ @statsd_instrumentations = {}
51
+ end
52
+ end
43
53
 
44
54
  # @private
45
55
  def self.generate_metric_name(metric_name, callee, *args)
@@ -70,9 +80,9 @@ module StatsD
70
80
  # @param metric_options (see StatsD#measure)
71
81
  # @return [void]
72
82
  def statsd_measure(method, name, *metric_options)
73
- add_to_method(method, name, :measure) do |old_method, new_method, metric_name, *args|
74
- define_method(new_method) do |*args, &block|
75
- StatsD.measure(StatsD::Instrument.generate_metric_name(metric_name, self, *args), nil, *metric_options) { send(old_method, *args, &block) }
83
+ add_to_method(method, name, :measure) do
84
+ define_method(method) do |*args, &block|
85
+ StatsD.measure(StatsD::Instrument.generate_metric_name(name, self, *args), nil, *metric_options) { super(*args, &block) }
76
86
  end
77
87
  end
78
88
  end
@@ -93,10 +103,10 @@ module StatsD
93
103
  # @return [void]
94
104
  # @see #statsd_count_if
95
105
  def statsd_count_success(method, name, *metric_options)
96
- add_to_method(method, name, :count_success) do |old_method, new_method, metric_name|
97
- define_method(new_method) do |*args, &block|
106
+ add_to_method(method, name, :count_success) do
107
+ define_method(method) do |*args, &block|
98
108
  begin
99
- truthiness = result = send(old_method, *args, &block)
109
+ truthiness = result = super(*args, &block)
100
110
  rescue
101
111
  truthiness = false
102
112
  raise
@@ -105,7 +115,7 @@ module StatsD
105
115
  result
106
116
  ensure
107
117
  suffix = truthiness == false ? 'failure' : 'success'
108
- StatsD.increment("#{StatsD::Instrument.generate_metric_name(metric_name, self, *args)}.#{suffix}", 1, *metric_options)
118
+ StatsD.increment("#{StatsD::Instrument.generate_metric_name(name, self, *args)}.#{suffix}", 1, *metric_options)
109
119
  end
110
120
  end
111
121
  end
@@ -125,10 +135,10 @@ module StatsD
125
135
  # @return [void]
126
136
  # @see #statsd_count_success
127
137
  def statsd_count_if(method, name, *metric_options)
128
- add_to_method(method, name, :count_if) do |old_method, new_method, metric_name|
129
- define_method(new_method) do |*args, &block|
138
+ add_to_method(method, name, :count_if) do
139
+ define_method(method) do |*args, &block|
130
140
  begin
131
- truthiness = result = send(old_method, *args, &block)
141
+ truthiness = result = super(*args, &block)
132
142
  rescue
133
143
  truthiness = false
134
144
  raise
@@ -136,7 +146,7 @@ module StatsD
136
146
  truthiness = (yield(result) rescue false) if block_given?
137
147
  result
138
148
  ensure
139
- StatsD.increment(StatsD::Instrument.generate_metric_name(metric_name, self, *args), *metric_options) if truthiness
149
+ StatsD.increment(StatsD::Instrument.generate_metric_name(name, self, *args), *metric_options) if truthiness
140
150
  end
141
151
  end
142
152
  end
@@ -152,10 +162,10 @@ module StatsD
152
162
  # @param metric_options (see #statsd_measure)
153
163
  # @return [void]
154
164
  def statsd_count(method, name, *metric_options)
155
- add_to_method(method, name, :count) do |old_method, new_method, metric_name|
156
- define_method(new_method) do |*args, &block|
157
- StatsD.increment(StatsD::Instrument.generate_metric_name(metric_name, self, *args), 1, *metric_options)
158
- send(old_method, *args, &block)
165
+ add_to_method(method, name, :count) do
166
+ define_method(method) do |*args, &block|
167
+ StatsD.increment(StatsD::Instrument.generate_metric_name(name, self, *args), 1, *metric_options)
168
+ super(*args, &block)
159
169
  end
160
170
  end
161
171
  end
@@ -198,40 +208,33 @@ module StatsD
198
208
 
199
209
  private
200
210
 
201
- def add_to_method(method, name, action, &block)
202
- metric_name = name
203
-
204
- method_name_without_statsd = :"#{method}_for_#{action}_on_#{self.name}_without_#{name}"
205
- # raw_ssl_request_for_measure_on_FedEx_without_ActiveMerchant.Shipping.#{self.class.name}.ssl_request
211
+ def statsd_instrumentation_for(method, name, action)
212
+ unless statsd_instrumentations.key?([method, name, action])
213
+ mod = Module.new do
214
+ define_singleton_method(:inspect) do
215
+ "StatsD_Instrument_#{method}_for_#{action}_with_#{name}"
216
+ end
217
+ end
218
+ @statsd_instrumentations = statsd_instrumentations.merge([method, name, action] => mod)
219
+ end
220
+ @statsd_instrumentations[[method, name, action]]
221
+ end
206
222
 
207
- method_name_with_statsd = :"#{method}_for_#{action}_on_#{self.name}_with_#{name}"
208
- # raw_ssl_request_for_measure_on_FedEx_with_ActiveMerchant.Shipping.#{self.class.name}.ssl_request
223
+ def add_to_method(method, name, action, &block)
224
+ instrumentation_module = statsd_instrumentation_for(method, name, action)
209
225
 
210
- raise ArgumentError, "already instrumented #{method} for #{self.name}" if method_defined? method_name_without_statsd
226
+ raise ArgumentError, "already instrumented #{method} for #{self.name}" if instrumentation_module.method_defined?(method)
211
227
  raise ArgumentError, "could not find method #{method} for #{self.name}" unless method_defined?(method) || private_method_defined?(method)
212
228
 
213
229
  method_scope = method_visibility(method)
214
230
 
215
- alias_method method_name_without_statsd, method
216
- yield method_name_without_statsd, method_name_with_statsd, metric_name
217
- alias_method method, method_name_with_statsd
218
-
219
- private(method_name_without_statsd)
220
- send(method_scope, method)
221
- private(method_name_with_statsd)
231
+ instrumentation_module.module_eval(&block)
232
+ instrumentation_module.send(method_scope, method)
233
+ prepend(instrumentation_module) unless self < instrumentation_module
222
234
  end
223
235
 
224
236
  def remove_from_method(method, name, action)
225
- method_name_without_statsd = :"#{method}_for_#{action}_on_#{self.name}_without_#{name}"
226
- method_name_with_statsd = :"#{method}_for_#{action}_on_#{self.name}_with_#{name}"
227
-
228
- method_scope = method_visibility(method)
229
-
230
- send(:remove_method, method_name_with_statsd)
231
- alias_method method, method_name_without_statsd
232
- send(:remove_method, method_name_without_statsd)
233
-
234
- send(method_scope, method)
237
+ statsd_instrumentation_for(method, name, action).send(:remove_method, method)
235
238
  end
236
239
 
237
240
  def method_visibility(method)
@@ -28,7 +28,7 @@ module StatsD::Instrument::Environment
28
28
  #
29
29
  # @return [String] The detected environment.
30
30
  def environment
31
- if defined?(Rails)
31
+ if defined?(Rails) && Rails.respond_to?(:env)
32
32
  Rails.env.to_s
33
33
  else
34
34
  ENV['RAILS_ENV'] || ENV['RACK_ENV'] || ENV['ENV'] || 'development'
@@ -55,13 +55,33 @@ module StatsD::Instrument::Matchers
55
55
  [:sample_rate, :value, :tags].each do |expectation|
56
56
  next unless options[expectation]
57
57
 
58
- if metrics.all? { |m| m.public_send(expectation) != options[expectation] }
59
- raise RSpec::Expectations::ExpectationNotMetError, "Unexpected StatsD #{expectation.to_s.gsub('_', ' ')} for metric #{metric_name}"
58
+ num_matches = metrics.count do |m|
59
+ matcher = RSpec::Matchers::BuiltIn::Match.new(options[expectation])
60
+ matcher.matches?(m.public_send(expectation))
61
+ end
62
+
63
+ found = options[:times] ? num_matches == options[:times] : num_matches > 0
64
+
65
+ if !found
66
+ message = metric_information(metric_name, options, metrics, expectation)
67
+ raise RSpec::Expectations::ExpectationNotMetError, message
60
68
  end
61
69
  end
62
70
 
63
71
  true
64
72
  end
73
+
74
+ def metric_information(metric_name, options, metrics, expectation)
75
+ message = "expected StatsD #{expectation.inspect} for metric '#{metric_name}' to be called"
76
+
77
+ message += "\n "
78
+ message += options[:times] ? "exactly #{options[:times]} times" : "at least once"
79
+ message += " with: #{options[expectation]}"
80
+
81
+ message += "\n captured metric values: #{metrics.map(&expectation).join(', ')}"
82
+
83
+ message
84
+ end
65
85
  end
66
86
 
67
87
  CUSTOM_MATCHERS.each do |method_name, metric_type|
@@ -1,5 +1,5 @@
1
1
  module StatsD
2
2
  module Instrument
3
- VERSION = "2.1.1"
3
+ VERSION = "2.1.2"
4
4
  end
5
5
  end
@@ -1,5 +1,7 @@
1
1
  require 'test_helper'
2
2
 
3
+ module Rails; end
4
+
3
5
  class EnvironmentTest < Minitest::Test
4
6
 
5
7
  def setup
@@ -32,4 +34,13 @@ class EnvironmentTest < Minitest::Test
32
34
  assert_equal 1234, backend.port
33
35
  assert_equal :datadog, backend.implementation
34
36
  end
37
+
38
+ def test_uses_env_when_rails_does_not_respond_to_env
39
+ assert_equal ENV['ENV'], StatsD::Instrument::Environment.environment
40
+ end
41
+
42
+ def test_uses_rails_env_when_rails_is_available
43
+ Rails.stubs(:env).returns('production')
44
+ assert_equal 'production', StatsD::Instrument::Environment.environment
45
+ end
35
46
  end
@@ -10,7 +10,7 @@ class MatchersTest < Minitest::Test
10
10
  refute StatsD::Instrument::Matchers::Increment.new(:c, 'counter', {}).matches? lambda { StatsD.increment('not_counter') }
11
11
  end
12
12
 
13
- def test_statsd_increment_compound
13
+ def test_statsd_increment_compound_matched
14
14
  matcher_1 = StatsD::Instrument::Matchers::Increment.new(:c, 'counter', tags: ['a'])
15
15
  matcher_2 = StatsD::Instrument::Matchers::Increment.new(:c, 'counter', tags: ['b'])
16
16
 
@@ -20,6 +20,16 @@ class MatchersTest < Minitest::Test
20
20
  }
21
21
  end
22
22
 
23
+ def test_statsd_increment_compound_not_matched
24
+ matcher_1 = StatsD::Instrument::Matchers::Increment.new(:c, 'counter', tags: ['a'])
25
+ matcher_2 = StatsD::Instrument::Matchers::Increment.new(:c, 'counter', tags: ['b'])
26
+
27
+ refute RSpec::Matchers::BuiltIn::Compound::And.new(matcher_1, matcher_2).matches? lambda {
28
+ StatsD.increment('counter', tags: ['a'])
29
+ StatsD.increment('counter', tags: ['a'])
30
+ }
31
+ end
32
+
23
33
  def test_statsd_increment_with_times_matched
24
34
  assert StatsD::Instrument::Matchers::Increment.new(:c, 'counter', times: 1).matches? lambda { StatsD.increment('counter') }
25
35
  end
@@ -40,6 +50,20 @@ class MatchersTest < Minitest::Test
40
50
  assert StatsD::Instrument::Matchers::Increment.new(:c, 'counter', value: 1).matches? lambda { StatsD.increment('counter') }
41
51
  end
42
52
 
53
+ def test_statsd_increment_with_value_matched_when_multiple_metrics
54
+ assert StatsD::Instrument::Matchers::Increment.new(:c, 'counter', value: 1).matches? lambda {
55
+ StatsD.increment('counter', value: 2)
56
+ StatsD.increment('counter', value: 1)
57
+ }
58
+ end
59
+
60
+ def test_statsd_increment_with_value_not_matched_when_multiple_metrics
61
+ refute StatsD::Instrument::Matchers::Increment.new(:c, 'counter', value: 1).matches? lambda {
62
+ StatsD.increment('counter', value: 2)
63
+ StatsD.increment('counter', value: 3)
64
+ }
65
+ end
66
+
43
67
  def test_statsd_increment_with_value_not_matched
44
68
  refute StatsD::Instrument::Matchers::Increment.new(:c, 'counter', value: 3).matches? lambda { StatsD.increment('counter') }
45
69
  end
@@ -51,4 +75,28 @@ class MatchersTest < Minitest::Test
51
75
  def test_statsd_increment_with_tags_not_matched
52
76
  refute StatsD::Instrument::Matchers::Increment.new(:c, 'counter', tags: ['a', 'b']).matches? lambda { StatsD.increment('counter', tags: ['c']) }
53
77
  end
78
+
79
+ def test_statsd_increment_with_times_and_value_matched
80
+ assert StatsD::Instrument::Matchers::Increment.new(:c, 'counter', times: 2, value: 1).matches? lambda {
81
+ StatsD.increment('counter', value: 1)
82
+ StatsD.increment('counter', value: 1)
83
+ }
84
+ end
85
+
86
+ def test_statsd_increment_with_times_and_value_not_matched
87
+ refute StatsD::Instrument::Matchers::Increment.new(:c, 'counter', times: 2, value: 1).matches? lambda {
88
+ StatsD.increment('counter', value: 1)
89
+ StatsD.increment('counter', value: 2)
90
+ }
91
+ end
92
+
93
+ def test_statsd_increment_with_sample_rate_and_argument_matcher_matched
94
+ between_matcher = RSpec::Matchers::BuiltIn::BeBetween.new(0.4, 0.6).inclusive
95
+ assert StatsD::Instrument::Matchers::Increment.new(:c, 'counter', sample_rate: between_matcher).matches? lambda { StatsD.increment('counter', sample_rate: 0.5) }
96
+ end
97
+
98
+ def test_statsd_increment_with_sample_rate_and_argument_matcher_not_matched
99
+ between_matcher = RSpec::Matchers::BuiltIn::BeBetween.new(0.4, 0.6).inclusive
100
+ refute StatsD::Instrument::Matchers::Increment.new(:c, 'counter', sample_rate: between_matcher).matches? lambda { StatsD.increment('counter', sample_rate: 0.7) }
101
+ end
54
102
  end
@@ -288,6 +288,22 @@ class StatsDInstrumentationTest < Minitest::Test
288
288
  InstrumentedClass.statsd_count :private_and_instrumented, 'InstrumentedClass.private_and_instrumented'
289
289
  end
290
290
 
291
+ def test_statsd_works_with_prepended_modules
292
+ mod = Module.new do
293
+ define_method(:foo) { super() }
294
+ end
295
+ klass = Class.new do
296
+ prepend mod
297
+ extend StatsD::Instrument
298
+ define_method(:foo) {}
299
+ statsd_count :foo, "foo"
300
+ end
301
+
302
+ assert_statsd_increment("foo") do
303
+ klass.new.foo
304
+ end
305
+ end
306
+
291
307
  private
292
308
 
293
309
  def assert_scope(klass, method, expected_scope)
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: 2.1.1
4
+ version: 2.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jesse Storimer
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2016-06-28 00:00:00.000000000 Z
13
+ date: 2016-12-06 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rake