statsd-instrument 2.5.1 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop-https---shopify-github-io-ruby-style-guide-rubocop-yml +1 -1
  3. data/.rubocop.yml +11 -6
  4. data/.yardopts +5 -0
  5. data/CHANGELOG.md +75 -6
  6. data/README.md +54 -46
  7. data/benchmark/datagram-client +41 -0
  8. data/lib/statsd/instrument/assertions.rb +168 -57
  9. data/lib/statsd/instrument/backends/udp_backend.rb +20 -29
  10. data/lib/statsd/instrument/capture_sink.rb +27 -0
  11. data/lib/statsd/instrument/client.rb +313 -0
  12. data/lib/statsd/instrument/datagram.rb +75 -0
  13. data/lib/statsd/instrument/datagram_builder.rb +101 -0
  14. data/lib/statsd/instrument/dogstatsd_datagram_builder.rb +71 -0
  15. data/lib/statsd/instrument/environment.rb +106 -29
  16. data/lib/statsd/instrument/log_sink.rb +24 -0
  17. data/lib/statsd/instrument/null_sink.rb +13 -0
  18. data/lib/statsd/instrument/rubocop/measure_as_dist_argument.rb +39 -0
  19. data/lib/statsd/instrument/rubocop/metaprogramming_positional_arguments.rb +6 -10
  20. data/lib/statsd/instrument/rubocop/metric_prefix_argument.rb +37 -0
  21. data/lib/statsd/instrument/rubocop/metric_return_value.rb +7 -6
  22. data/lib/statsd/instrument/rubocop/metric_value_keyword_argument.rb +11 -20
  23. data/lib/statsd/instrument/rubocop/positional_arguments.rb +13 -13
  24. data/lib/statsd/instrument/rubocop/splat_arguments.rb +8 -14
  25. data/lib/statsd/instrument/rubocop.rb +64 -0
  26. data/lib/statsd/instrument/statsd_datagram_builder.rb +14 -0
  27. data/lib/statsd/instrument/strict.rb +112 -22
  28. data/lib/statsd/instrument/udp_sink.rb +62 -0
  29. data/lib/statsd/instrument/version.rb +1 -1
  30. data/lib/statsd/instrument.rb +191 -100
  31. data/test/assertions_test.rb +139 -176
  32. data/test/capture_sink_test.rb +44 -0
  33. data/test/client_test.rb +164 -0
  34. data/test/compatibility/dogstatsd_datagram_compatibility_test.rb +162 -0
  35. data/test/datagram_builder_test.rb +120 -0
  36. data/test/deprecations_test.rb +56 -10
  37. data/test/dogstatsd_datagram_builder_test.rb +32 -0
  38. data/test/environment_test.rb +73 -7
  39. data/test/log_sink_test.rb +37 -0
  40. data/test/null_sink_test.rb +13 -0
  41. data/test/rubocop/measure_as_dist_argument_test.rb +44 -0
  42. data/test/rubocop/metaprogramming_positional_arguments_test.rb +1 -1
  43. data/test/rubocop/metric_prefix_argument_test.rb +38 -0
  44. data/test/rubocop/metric_return_value_test.rb +1 -1
  45. data/test/rubocop/metric_value_keyword_argument_test.rb +1 -1
  46. data/test/rubocop/positional_arguments_test.rb +1 -1
  47. data/test/rubocop/splat_arguments_test.rb +1 -1
  48. data/test/statsd_datagram_builder_test.rb +22 -0
  49. data/test/statsd_instrumentation_test.rb +0 -24
  50. data/test/statsd_test.rb +0 -23
  51. data/test/test_helper.rb +0 -2
  52. data/test/udp_backend_test.rb +25 -8
  53. data/test/udp_sink_test.rb +85 -0
  54. metadata +38 -2
@@ -4,24 +4,62 @@ require 'logger'
4
4
 
5
5
  # The environment module is used to detect, and initialize the environment in
6
6
  # which this library is active. It will use different default values based on the environment.
7
- module StatsD::Instrument::Environment
8
- extend self
7
+ class StatsD::Instrument::Environment
8
+ class << self
9
+ def from_env
10
+ @from_env ||= StatsD::Instrument::Environment.new(ENV)
11
+ end
9
12
 
10
- # Instantiates a default backend for the current environment.
11
- #
12
- # @return [StatsD::Instrument::Backend]
13
- # @see #environment
14
- def default_backend
15
- case environment
16
- when 'production', 'staging'
17
- StatsD::Instrument::Backends::UDPBackend.new(ENV['STATSD_ADDR'], ENV['STATSD_IMPLEMENTATION'])
18
- when 'test'
19
- StatsD::Instrument::Backends::NullBackend.new
20
- else
21
- StatsD::Instrument::Backends::LoggerBackend.new(StatsD.logger)
13
+ # Detects the current environment, either by asking Rails, or by inspecting environment variables.
14
+ #
15
+ # - Within a Rails application, <tt>Rails.env</tt> is used.
16
+ # - It will check the following environment variables in order: <tt>RAILS_ENV</tt>, <tt>RACK_ENV</tt>, <tt>ENV</tt>.
17
+ # - If none of these are set, it will return <tt>development</tt>
18
+ #
19
+ # @return [String] The detected environment.
20
+ def environment
21
+ from_env.environment
22
+ end
23
+
24
+ # Instantiates a default backend for the current environment.
25
+ #
26
+ # @return [StatsD::Instrument::Backend]
27
+ # @see #environment
28
+ def default_backend
29
+ case environment
30
+ when 'production', 'staging'
31
+ StatsD::Instrument::Backends::UDPBackend.new(from_env.statsd_addr, from_env.statsd_implementation)
32
+ when 'test'
33
+ StatsD::Instrument::Backends::NullBackend.new
34
+ else
35
+ StatsD::Instrument::Backends::LoggerBackend.new(StatsD.logger)
36
+ end
37
+ end
38
+
39
+ # Sets default values for sample rate and logger.
40
+ #
41
+ # - Default sample rate is set to the value in the STATSD_SAMPLE_RATE environment variable,
42
+ # or 1.0 otherwise. See {StatsD#default_sample_rate}
43
+ # - {StatsD#logger} is set to a logger that send output to stderr.
44
+ #
45
+ # If you are including this library inside a Rails environment, additional initialization will
46
+ # be done as part of the {StatsD::Instrument::Railtie}.
47
+ #
48
+ # @return [void]
49
+ def setup
50
+ StatsD.prefix = from_env.statsd_prefix
51
+ StatsD.default_tags = from_env.statsd_default_tags
52
+ StatsD.default_sample_rate = from_env.statsd_sample_rate
53
+ StatsD.logger = Logger.new($stderr)
22
54
  end
23
55
  end
24
56
 
57
+ attr_reader :env
58
+
59
+ def initialize(env)
60
+ @env = env
61
+ end
62
+
25
63
  # Detects the current environment, either by asking Rails, or by inspecting environment variables.
26
64
  #
27
65
  # - Within a Rails application, <tt>Rails.env</tt> is used.
@@ -30,26 +68,65 @@ module StatsD::Instrument::Environment
30
68
  #
31
69
  # @return [String] The detected environment.
32
70
  def environment
33
- if defined?(Rails) && Rails.respond_to?(:env)
71
+ if env['STATSD_ENV']
72
+ env['STATSD_ENV']
73
+ elsif defined?(Rails) && Rails.respond_to?(:env)
34
74
  Rails.env.to_s
35
75
  else
36
- ENV['RAILS_ENV'] || ENV['RACK_ENV'] || ENV['ENV'] || 'development'
76
+ env['RAILS_ENV'] || env['RACK_ENV'] || env['ENV'] || 'development'
37
77
  end
38
78
  end
39
79
 
40
- # Sets default values for sample rate and logger.
41
- #
42
- # - Default sample rate is set to the value in the STATSD_SAMPLE_RATE environment variable,
43
- # or 1.0 otherwise. See {StatsD#default_sample_rate}
44
- # - {StatsD#logger} is set to a logger that send output to stderr.
45
- #
46
- # If you are including this library inside a Rails environment, additional initialization will
47
- # be done as part of the {StatsD::Instrument::Railtie}.
48
- #
49
- # @return [void]
50
- def setup
51
- StatsD.default_sample_rate = ENV.fetch('STATSD_SAMPLE_RATE', 1.0).to_f
52
- StatsD.logger = Logger.new($stderr)
80
+ def statsd_implementation
81
+ env.fetch('STATSD_IMPLEMENTATION', 'statsd')
82
+ end
83
+
84
+ def statsd_sample_rate
85
+ env.fetch('STATSD_SAMPLE_RATE', 1.0).to_f
86
+ end
87
+
88
+ def statsd_prefix
89
+ env.fetch('STATSD_PREFIX', nil)
90
+ end
91
+
92
+ def statsd_addr
93
+ env.fetch('STATSD_ADDR', 'localhost:8125')
94
+ end
95
+
96
+ def statsd_default_tags
97
+ env.key?('STATSD_DEFAULT_TAGS') ? env.fetch('STATSD_DEFAULT_TAGS').split(',') : nil
98
+ end
99
+
100
+ def default_client
101
+ @default_client ||= StatsD::Instrument::Client.new(
102
+ sink: default_sink_for_environment,
103
+ datagram_builder_class: default_datagram_builder_class_for_implementation,
104
+ default_sample_rate: statsd_sample_rate,
105
+ prefix: statsd_prefix,
106
+ default_tags: statsd_default_tags,
107
+ )
108
+ end
109
+
110
+ def default_datagram_builder_class_for_implementation
111
+ case statsd_implementation
112
+ when 'statsd'
113
+ StatsD::Instrument::StatsDDatagramBuilder
114
+ when 'datadog', 'dogstatsd'
115
+ StatsD::Instrument::DogStatsDDatagramBuilder
116
+ else
117
+ raise NotImplementedError, "No implementation for #{statsd_implementation}"
118
+ end
119
+ end
120
+
121
+ def default_sink_for_environment
122
+ case environment
123
+ when 'production', 'staging'
124
+ StatsD::Instrument::UDPSink.for_addr(statsd_addr)
125
+ when 'test'
126
+ StatsD::Instrument::NullSink.new
127
+ else
128
+ StatsD::Instrument::LogSink.new(StatsD.logger)
129
+ end
53
130
  end
54
131
  end
55
132
 
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @note This class is part of the new Client implementation that is intended
4
+ # to become the new default in the next major release of this library.
5
+ class StatsD::Instrument::LogSink
6
+ attr_reader :logger, :severity
7
+
8
+ def initialize(logger, severity: Logger::DEBUG)
9
+ @logger = logger
10
+ @severity = severity
11
+ end
12
+
13
+ def sample?(_sample_rate)
14
+ true
15
+ end
16
+
17
+ def <<(datagram)
18
+ # Some implementations require a newline at the end of datagrams.
19
+ # When logging, we make sure those newlines are removed using chomp.
20
+
21
+ logger.add(severity, "[StatsD] #{datagram.chomp}")
22
+ self
23
+ end
24
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @note This class is part of the new Client implementation that is intended
4
+ # to become the new default in the next major release of this library.
5
+ class StatsD::Instrument::NullSink
6
+ def sample?(_sample_rate)
7
+ false
8
+ end
9
+
10
+ def <<(_datagram)
11
+ self # noop
12
+ end
13
+ end
@@ -0,0 +1,39 @@
1
+ # frozen-string-literal: true
2
+
3
+ require_relative '../rubocop' unless defined?(RuboCop::Cop::StatsD)
4
+
5
+ module RuboCop
6
+ module Cop
7
+ module StatsD
8
+ # This Rubocop will check for specifying the `as_dist: true` keyword argument on `StatsD.measure`
9
+ # and `statsd_measure`. This argument is deprecated. Instead, you can use `StatsD.distribution`
10
+ # (or `statsd_distribution`) directly.
11
+ #
12
+ # To run this cop on your codebase:
13
+ #
14
+ # rubocop --require `bundle show statsd-instrument`/lib/statsd/instrument/rubocop.rb \
15
+ # --only StatsD/MeasureAsDistArgument
16
+ #
17
+ # This cop will not autocorrect offenses.
18
+ class MeasureAsDistArgument < Cop
19
+ include RuboCop::Cop::StatsD
20
+
21
+ MSG = <<~MSG
22
+ Do not use StatsD.measure(..., as_dist: true). This is deprecated.
23
+
24
+ Use StatsD.distribution (or statsd_distribution) instead.
25
+ MSG
26
+
27
+ def on_send(node)
28
+ if metric_method?(node) && node.method_name == :measure
29
+ add_offense(node) if has_keyword_argument?(node, :as_dist)
30
+ end
31
+
32
+ if metaprogramming_method?(node) && node.method_name == :statsd_measure
33
+ add_offense(node) if has_keyword_argument?(node, :as_dist)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -1,5 +1,7 @@
1
1
  # frozen-string-literal: true
2
2
 
3
+ require_relative '../rubocop' unless defined?(RuboCop::Cop::StatsD)
4
+
3
5
  module RuboCop
4
6
  module Cop
5
7
  module StatsD
@@ -10,23 +12,17 @@ module RuboCop
10
12
  # Use the following Rubocop invocation to check your project's codebase:
11
13
  #
12
14
  # rubocop --only StatsD/MetaprogrammingPositionalArguments
13
- # -r `bundle show statsd-instrument`/lib/statsd/instrument/rubocop/metaprogramming_positional_arguments.rb
15
+ # -r `bundle show statsd-instrument`/lib/statsd/instrument/rubocop.rb
14
16
  #
15
17
  #
16
18
  # This cop will not autocorrect the offenses it finds, but generally the fixes are easy to fix
17
19
  class MetaprogrammingPositionalArguments < Cop
18
- MSG = 'Use keyword arguments for StatsD metaprogramming macros'
20
+ include RuboCop::Cop::StatsD
19
21
 
20
- METAPROGRAMMING_METHODS = %i{
21
- statsd_measure
22
- statsd_distribution
23
- statsd_count_success
24
- statsd_count_if
25
- statsd_count
26
- }
22
+ MSG = 'Use keyword arguments for StatsD metaprogramming macros'
27
23
 
28
24
  def on_send(node)
29
- if METAPROGRAMMING_METHODS.include?(node.method_name)
25
+ if metaprogramming_method?(node)
30
26
  arguments = node.arguments.dup
31
27
  arguments.shift # method
32
28
  arguments.shift # metric
@@ -0,0 +1,37 @@
1
+ # frozen-string-literal: true
2
+
3
+ require_relative '../rubocop' unless defined?(RuboCop::Cop::StatsD)
4
+
5
+ module RuboCop
6
+ module Cop
7
+ module StatsD
8
+ # This Rubocop will check for specifying the `prefix` keyword argument on `StatsD` metric
9
+ # methods and `statsd_*` metaprogramming methods. To run this cop on your codebase:
10
+ #
11
+ # rubocop --require `bundle show statsd-instrument`/lib/statsd/instrument/rubocop.rb \
12
+ # --only StatsD/MetricPrefixArgument
13
+ #
14
+ # This cop will not autocorrect offenses.
15
+ class MetricPrefixArgument < Cop
16
+ include RuboCop::Cop::StatsD
17
+
18
+ MSG = <<~MSG
19
+ Do not use StatsD.metric(..., prefix: "foo"). The prefix argument is deprecated.
20
+
21
+ You can simply include the prefix in the metric name instead.
22
+ If you want to override the global prefix, you can set `no_prefix: true`.
23
+ MSG
24
+
25
+ def on_send(node)
26
+ if metric_method?(node)
27
+ add_offense(node) if has_keyword_argument?(node, :prefix)
28
+ end
29
+
30
+ if metaprogramming_method?(node)
31
+ add_offense(node) if has_keyword_argument?(node, :prefix)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -1,28 +1,29 @@
1
1
  # frozen-string-literal: true
2
2
 
3
+ require_relative '../rubocop' unless defined?(RuboCop::Cop::StatsD)
4
+
3
5
  module RuboCop
4
6
  module Cop
5
7
  module StatsD
6
8
  # This Rubocop will check for using the return value of StatsD metric calls, which is deprecated.
7
9
  # To check your codebase, use the following Rubocop invocation:
8
10
  #
9
- # rubocop --require `bundle show statsd-instrument`/lib/statsd/instrument/rubocop/metric_return_value.rb \
11
+ # rubocop --require `bundle show statsd-instrument`/lib/statsd/instrument/rubocop.rb \
10
12
  # --only StatsD/MetricReturnValue
11
13
  #
12
14
  # This cop cannot autocorrect offenses. In production code, StatsD should be used in a fire-and-forget
13
15
  # fashion. This means that you shouldn't rely on the return value. If you really need to access the
14
16
  # emitted metrics, you can look into `capture_statsd_calls`
15
17
  class MetricReturnValue < Cop
18
+ include RuboCop::Cop::StatsD
19
+
16
20
  MSG = 'Do not use the return value of StatsD metric methods'
17
21
 
18
- STATSD_METRIC_METHODS = %i{increment gauge measure set histogram distribution key_value}
19
22
  INVALID_PARENTS = %i{lvasgn array pair send return yield}
20
23
 
21
24
  def on_send(node)
22
- if node.receiver&.type == :const && node.receiver&.const_name == "StatsD"
23
- if STATSD_METRIC_METHODS.include?(node.method_name) && node.arguments.last&.type != :block_pass
24
- add_offense(node.parent) if INVALID_PARENTS.include?(node.parent&.type)
25
- end
25
+ if metric_method?(node) && node.arguments.last&.type != :block_pass
26
+ add_offense(node.parent) if INVALID_PARENTS.include?(node.parent&.type)
26
27
  end
27
28
  end
28
29
  end
@@ -1,5 +1,7 @@
1
1
  # frozen-string-literal: true
2
2
 
3
+ require_relative '../rubocop' unless defined?(RuboCop::Cop::StatsD)
4
+
3
5
  module RuboCop
4
6
  module Cop
5
7
  module StatsD
@@ -7,7 +9,7 @@ module RuboCop
7
9
  # deprecated. Use the following Rubocop invocation to check your project's codebase:
8
10
  #
9
11
  # rubocop --require \
10
- # `bundle show statsd-instrument`/lib/statsd/instrument/rubocop/metric_value_keyword_argument.rb \
12
+ # `bundle show statsd-instrument`/lib/statsd/instrument/rubocop.rb \
11
13
  # --only StatsD/MetricValueKeywordArgument
12
14
  #
13
15
  # This cop will not autocorrect offenses. Most of the time, these are easy to fix by providing the
@@ -15,29 +17,18 @@ module RuboCop
15
17
  #
16
18
  # `StatsD.increment('foo', value: 3)` => `StatsD.increment('foo', 3)`
17
19
  class MetricValueKeywordArgument < Cop
18
- MSG = 'Do not use the value keyword argument, but use a positional argument'
19
-
20
- STATSD_METRIC_METHODS = %i{increment gauge measure set histogram distribution key_value}
20
+ include RuboCop::Cop::StatsD
21
21
 
22
- def on_send(node)
23
- if node.receiver&.type == :const && node.receiver&.const_name == "StatsD"
24
- if STATSD_METRIC_METHODS.include?(node.method_name)
25
- last_argument = if node.arguments.last&.type == :block_pass
26
- node.arguments[node.arguments.length - 2]
27
- else
28
- node.arguments[node.arguments.length - 1]
29
- end
22
+ MSG = <<~MSG
23
+ Do not use the StatsD.metric('name', value: <value>, ...). The `value` keyword argument is deprecated.
30
24
 
31
- check_keyword_arguments_for_value_entry(node, last_argument) if last_argument&.type == :hash
32
- end
33
- end
34
- end
25
+ Use a positional argument instead: StatsD.metric('name', <value>, ...).
26
+ MSG
35
27
 
36
- def check_keyword_arguments_for_value_entry(node, keyword_arguments)
37
- value_pair_found = keyword_arguments.child_nodes.any? do |pair|
38
- pair.child_nodes[0].type == :sym && pair.child_nodes[0].value == :value
28
+ def on_send(node)
29
+ if metric_method?(node) && has_keyword_argument?(node, :value)
30
+ add_offense(node)
39
31
  end
40
- add_offense(node) if value_pair_found
41
32
  end
42
33
  end
43
34
  end
@@ -1,5 +1,7 @@
1
1
  # frozen-string-literal: true
2
2
 
3
+ require_relative '../rubocop' unless defined?(RuboCop::Cop::StatsD)
4
+
3
5
  module RuboCop
4
6
  module Cop
5
7
  module StatsD
@@ -8,14 +10,14 @@ module RuboCop
8
10
  #
9
11
  # Use the following Rubocop invocation to check your project's codebase:
10
12
  #
11
- # rubocop --require `bundle show statsd-instrument`/lib/statsd/instrument/rubocop/positional_arguments.rb \
13
+ # rubocop --require `bundle show statsd-instrument`/lib/statsd/instrument/rubocop.rb \
12
14
  # --only StatsD/PositionalArguments
13
15
  #
14
16
  # This cop can autocorrect some offenses it finds, but not all of them.
15
17
  class PositionalArguments < Cop
16
- MSG = 'Use keyword arguments for StatsD calls'
18
+ include RuboCop::Cop::StatsD
17
19
 
18
- STATSD_SINGLETON_METHODS = %i{increment gauge measure set histogram distribution key_value}
20
+ MSG = 'Use keyword arguments for StatsD calls'
19
21
 
20
22
  POSITIONAL_ARGUMENT_TYPES = Set[:int, :float, :nil]
21
23
  UNKNOWN_ARGUMENT_TYPES = Set[:send, :const, :lvar, :splat]
@@ -26,16 +28,14 @@ module RuboCop
26
28
  ACCEPTED_ARGUMENT_TYPES = KEYWORD_ARGUMENT_TYPES | BLOCK_ARGUMENT_TYPES
27
29
 
28
30
  def on_send(node)
29
- if node.receiver&.type == :const && node.receiver&.const_name == "StatsD"
30
- if STATSD_SINGLETON_METHODS.include?(node.method_name) && node.arguments.length >= 3
31
- case node.arguments[2].type
32
- when *REFUSED_ARGUMENT_TYPES
33
- add_offense(node)
34
- when *ACCEPTED_ARGUMENT_TYPES
35
- nil
36
- else
37
- $stderr.puts "[StatsD/PositionalArguments] Unhandled argument type: #{node.arguments[2].type.inspect}"
38
- end
31
+ if metric_method?(node) && node.arguments.length >= 3
32
+ case node.arguments[2].type
33
+ when *REFUSED_ARGUMENT_TYPES
34
+ add_offense(node)
35
+ when *ACCEPTED_ARGUMENT_TYPES
36
+ nil
37
+ else
38
+ $stderr.puts "[StatsD/PositionalArguments] Unhandled argument type: #{node.arguments[2].type.inspect}"
39
39
  end
40
40
  end
41
41
  end
@@ -1,5 +1,7 @@
1
1
  # frozen-string-literal: true
2
2
 
3
+ require_relative '../rubocop' unless defined?(RuboCop::Cop::StatsD)
4
+
3
5
  module RuboCop
4
6
  module Cop
5
7
  module StatsD
@@ -7,30 +9,22 @@ module RuboCop
7
9
  # this rule on your codebase, invoke Rubocop this way:
8
10
  #
9
11
  # rubocop --require \
10
- # `bundle show statsd-instrument`/lib/statsd/instrument/rubocop/splat_arguments.rb \
12
+ # `bundle show statsd-instrument`/lib/statsd/instrument/rubocop.rb \
11
13
  # --only StatsD/SplatArguments
12
14
  #
13
15
  # This cop will not autocorrect offenses.
14
16
  class SplatArguments < Cop
15
- MSG = 'Do not use splat arguments in StatsD metric calls'
17
+ include RuboCop::Cop::StatsD
16
18
 
17
- STATSD_METRIC_METHODS = %i{increment gauge measure set histogram distribution key_value}
19
+ MSG = 'Do not use splat arguments in StatsD metric calls'
18
20
 
19
21
  def on_send(node)
20
- if node.receiver&.type == :const && node.receiver&.const_name == "StatsD"
21
- if STATSD_METRIC_METHODS.include?(node.method_name)
22
- check_for_splat_arguments(node)
22
+ if metric_method?(node)
23
+ if node.arguments.any? { |arg| arg.type == :splat }
24
+ add_offense(node)
23
25
  end
24
26
  end
25
27
  end
26
-
27
- private
28
-
29
- def check_for_splat_arguments(node)
30
- if node.arguments.any? { |arg| arg.type == :splat }
31
- add_offense(node)
32
- end
33
- end
34
28
  end
35
29
  end
36
30
  end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module StatsD
6
+ METRIC_METHODS = %i{
7
+ increment
8
+ gauge
9
+ measure
10
+ set
11
+ histogram
12
+ distribution
13
+ key_value
14
+ }
15
+
16
+ METAPROGRAMMING_METHODS = %i{
17
+ statsd_measure
18
+ statsd_distribution
19
+ statsd_count_success
20
+ statsd_count_if
21
+ statsd_count
22
+ }
23
+
24
+ private
25
+
26
+ def metaprogramming_method?(node)
27
+ METAPROGRAMMING_METHODS.include?(node.method_name)
28
+ end
29
+
30
+ def metric_method?(node)
31
+ node.receiver&.type == :const &&
32
+ node.receiver&.const_name == "StatsD" &&
33
+ METRIC_METHODS.include?(node.method_name)
34
+ end
35
+
36
+ def has_keyword_argument?(node, sym)
37
+ if (kwargs = keyword_arguments(node))
38
+ kwargs.child_nodes.detect do |pair|
39
+ pair.child_nodes[0]&.type == :sym && pair.child_nodes[0].value == sym
40
+ end
41
+ end
42
+ end
43
+
44
+ def keyword_arguments(node)
45
+ return nil if node.arguments.empty?
46
+ last_argument = if node.arguments.last&.type == :block_pass
47
+ node.arguments[node.arguments.length - 2]
48
+ else
49
+ node.arguments[node.arguments.length - 1]
50
+ end
51
+
52
+ last_argument&.type == :hash ? last_argument : nil
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ require_relative 'rubocop/metaprogramming_positional_arguments'
59
+ require_relative 'rubocop/metric_return_value'
60
+ require_relative 'rubocop/metric_value_keyword_argument'
61
+ require_relative 'rubocop/positional_arguments'
62
+ require_relative 'rubocop/splat_arguments'
63
+ require_relative 'rubocop/measure_as_dist_argument'
64
+ require_relative 'rubocop/metric_prefix_argument'
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @note This class is part of the new Client implementation that is intended
4
+ # to become the new default in the next major release of this library.
5
+ class StatsD::Instrument::StatsDDatagramBuilder < StatsD::Instrument::DatagramBuilder
6
+ unsupported_datagram_types :h, :d, :kv
7
+
8
+ protected
9
+
10
+ def normalize_tags(tags)
11
+ raise NotImplementedError, "#{self.class.name} does not support tags" if tags
12
+ super
13
+ end
14
+ end