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.
- checksums.yaml +4 -4
- data/.rubocop-https---shopify-github-io-ruby-style-guide-rubocop-yml +1 -1
- data/.rubocop.yml +11 -6
- data/.yardopts +5 -0
- data/CHANGELOG.md +75 -6
- data/README.md +54 -46
- data/benchmark/datagram-client +41 -0
- data/lib/statsd/instrument/assertions.rb +168 -57
- data/lib/statsd/instrument/backends/udp_backend.rb +20 -29
- data/lib/statsd/instrument/capture_sink.rb +27 -0
- data/lib/statsd/instrument/client.rb +313 -0
- data/lib/statsd/instrument/datagram.rb +75 -0
- data/lib/statsd/instrument/datagram_builder.rb +101 -0
- data/lib/statsd/instrument/dogstatsd_datagram_builder.rb +71 -0
- data/lib/statsd/instrument/environment.rb +106 -29
- data/lib/statsd/instrument/log_sink.rb +24 -0
- data/lib/statsd/instrument/null_sink.rb +13 -0
- data/lib/statsd/instrument/rubocop/measure_as_dist_argument.rb +39 -0
- data/lib/statsd/instrument/rubocop/metaprogramming_positional_arguments.rb +6 -10
- data/lib/statsd/instrument/rubocop/metric_prefix_argument.rb +37 -0
- data/lib/statsd/instrument/rubocop/metric_return_value.rb +7 -6
- data/lib/statsd/instrument/rubocop/metric_value_keyword_argument.rb +11 -20
- data/lib/statsd/instrument/rubocop/positional_arguments.rb +13 -13
- data/lib/statsd/instrument/rubocop/splat_arguments.rb +8 -14
- data/lib/statsd/instrument/rubocop.rb +64 -0
- data/lib/statsd/instrument/statsd_datagram_builder.rb +14 -0
- data/lib/statsd/instrument/strict.rb +112 -22
- data/lib/statsd/instrument/udp_sink.rb +62 -0
- data/lib/statsd/instrument/version.rb +1 -1
- data/lib/statsd/instrument.rb +191 -100
- data/test/assertions_test.rb +139 -176
- data/test/capture_sink_test.rb +44 -0
- data/test/client_test.rb +164 -0
- data/test/compatibility/dogstatsd_datagram_compatibility_test.rb +162 -0
- data/test/datagram_builder_test.rb +120 -0
- data/test/deprecations_test.rb +56 -10
- data/test/dogstatsd_datagram_builder_test.rb +32 -0
- data/test/environment_test.rb +73 -7
- data/test/log_sink_test.rb +37 -0
- data/test/null_sink_test.rb +13 -0
- data/test/rubocop/measure_as_dist_argument_test.rb +44 -0
- data/test/rubocop/metaprogramming_positional_arguments_test.rb +1 -1
- data/test/rubocop/metric_prefix_argument_test.rb +38 -0
- data/test/rubocop/metric_return_value_test.rb +1 -1
- data/test/rubocop/metric_value_keyword_argument_test.rb +1 -1
- data/test/rubocop/positional_arguments_test.rb +1 -1
- data/test/rubocop/splat_arguments_test.rb +1 -1
- data/test/statsd_datagram_builder_test.rb +22 -0
- data/test/statsd_instrumentation_test.rb +0 -24
- data/test/statsd_test.rb +0 -23
- data/test/test_helper.rb +0 -2
- data/test/udp_backend_test.rb +25 -8
- data/test/udp_sink_test.rb +85 -0
- 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
|
-
|
8
|
-
|
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
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
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
|
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
|
-
|
76
|
+
env['RAILS_ENV'] || env['RACK_ENV'] || env['ENV'] || 'development'
|
37
77
|
end
|
38
78
|
end
|
39
79
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
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
|
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
|
-
|
20
|
+
include RuboCop::Cop::StatsD
|
19
21
|
|
20
|
-
|
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
|
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
|
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
|
23
|
-
if
|
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
|
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
|
-
|
19
|
-
|
20
|
-
STATSD_METRIC_METHODS = %i{increment gauge measure set histogram distribution key_value}
|
20
|
+
include RuboCop::Cop::StatsD
|
21
21
|
|
22
|
-
|
23
|
-
|
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
|
-
|
32
|
-
|
33
|
-
end
|
34
|
-
end
|
25
|
+
Use a positional argument instead: StatsD.metric('name', <value>, ...).
|
26
|
+
MSG
|
35
27
|
|
36
|
-
def
|
37
|
-
|
38
|
-
|
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
|
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
|
-
|
18
|
+
include RuboCop::Cop::StatsD
|
17
19
|
|
18
|
-
|
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
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
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
|
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
|
-
|
17
|
+
include RuboCop::Cop::StatsD
|
16
18
|
|
17
|
-
|
19
|
+
MSG = 'Do not use splat arguments in StatsD metric calls'
|
18
20
|
|
19
21
|
def on_send(node)
|
20
|
-
if node
|
21
|
-
if
|
22
|
-
|
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
|