statsd-instrument 3.0.0 → 3.0.1

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 (49) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +3 -3
  3. data/.rubocop.yml +3 -13
  4. data/CHANGELOG.md +6 -0
  5. data/Gemfile +8 -0
  6. data/README.md +2 -2
  7. data/Rakefile +1 -1
  8. data/bin/rake +29 -0
  9. data/bin/rubocop +29 -0
  10. data/lib/statsd/instrument.rb +4 -1
  11. data/lib/statsd/instrument/assertions.rb +200 -196
  12. data/lib/statsd/instrument/capture_sink.rb +23 -19
  13. data/lib/statsd/instrument/client.rb +414 -410
  14. data/lib/statsd/instrument/datagram.rb +69 -65
  15. data/lib/statsd/instrument/datagram_builder.rb +81 -77
  16. data/lib/statsd/instrument/dogstatsd_datagram.rb +76 -72
  17. data/lib/statsd/instrument/dogstatsd_datagram_builder.rb +68 -64
  18. data/lib/statsd/instrument/environment.rb +80 -77
  19. data/lib/statsd/instrument/expectation.rb +96 -92
  20. data/lib/statsd/instrument/helpers.rb +11 -7
  21. data/lib/statsd/instrument/log_sink.rb +20 -16
  22. data/lib/statsd/instrument/matchers.rb +86 -70
  23. data/lib/statsd/instrument/null_sink.rb +12 -8
  24. data/lib/statsd/instrument/railtie.rb +11 -7
  25. data/lib/statsd/instrument/statsd_datagram_builder.rb +12 -8
  26. data/lib/statsd/instrument/udp_sink.rb +50 -46
  27. data/lib/statsd/instrument/version.rb +1 -1
  28. data/statsd-instrument.gemspec +2 -8
  29. data/test/assertions_test.rb +12 -12
  30. data/test/capture_sink_test.rb +8 -8
  31. data/test/client_test.rb +54 -54
  32. data/test/datagram_builder_test.rb +29 -29
  33. data/test/datagram_test.rb +1 -1
  34. data/test/dogstatsd_datagram_builder_test.rb +28 -28
  35. data/test/environment_test.rb +9 -9
  36. data/test/helpers/rubocop_helper.rb +9 -6
  37. data/test/helpers_test.rb +5 -5
  38. data/test/integration_test.rb +1 -1
  39. data/test/log_sink_test.rb +2 -2
  40. data/test/matchers_test.rb +36 -36
  41. data/test/null_sink_test.rb +2 -2
  42. data/test/rubocop/metric_return_value_test.rb +3 -3
  43. data/test/rubocop/positional_arguments_test.rb +10 -10
  44. data/test/statsd_instrumentation_test.rb +66 -66
  45. data/test/statsd_test.rb +44 -44
  46. data/test/test_helper.rb +6 -4
  47. data/test/udp_sink_test.rb +8 -8
  48. metadata +7 -103
  49. data/.rubocop-https---shopify-github-io-ruby-style-guide-rubocop-yml +0 -1027
@@ -1,83 +1,87 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # The Datagram class parses and inspects a StatsD datagrams
4
- #
5
- # @note This class is part of the new Client implementation that is intended
6
- # to become the new default in the next major release of this library.
7
- class StatsD::Instrument::Datagram
8
- attr_reader :source
3
+ module StatsD
4
+ module Instrument
5
+ # The Datagram class parses and inspects a StatsD datagrams
6
+ #
7
+ # @note This class is part of the new Client implementation that is intended
8
+ # to become the new default in the next major release of this library.
9
+ class Datagram
10
+ attr_reader :source
9
11
 
10
- def initialize(source)
11
- @source = source
12
- end
12
+ def initialize(source)
13
+ @source = source
14
+ end
13
15
 
14
- # @return [Float] The sample rate at which this datagram was emitted, between 0 and 1.
15
- def sample_rate
16
- parsed_datagram[:sample_rate] ? Float(parsed_datagram[:sample_rate]) : 1.0
17
- end
16
+ # @return [Float] The sample rate at which this datagram was emitted, between 0 and 1.
17
+ def sample_rate
18
+ parsed_datagram[:sample_rate] ? Float(parsed_datagram[:sample_rate]) : 1.0
19
+ end
18
20
 
19
- def type
20
- @type ||= parsed_datagram[:type].to_sym
21
- end
21
+ def type
22
+ @type ||= parsed_datagram[:type].to_sym
23
+ end
22
24
 
23
- def name
24
- parsed_datagram[:name]
25
- end
25
+ def name
26
+ parsed_datagram[:name]
27
+ end
26
28
 
27
- def value
28
- @value ||= case type
29
- when :c
30
- Integer(parsed_datagram[:value])
31
- when :g, :h, :d, :kv, :ms
32
- Float(parsed_datagram[:value])
33
- when :s
34
- String(parsed_datagram[:value])
35
- else
36
- parsed_datagram[:value]
37
- end
38
- end
29
+ def value
30
+ @value ||= case type
31
+ when :c
32
+ Integer(parsed_datagram[:value])
33
+ when :g, :h, :d, :kv, :ms
34
+ Float(parsed_datagram[:value])
35
+ when :s
36
+ String(parsed_datagram[:value])
37
+ else
38
+ parsed_datagram[:value]
39
+ end
40
+ end
39
41
 
40
- def tags
41
- @tags ||= parsed_datagram[:tags] ? parsed_datagram[:tags].split(',') : nil
42
- end
42
+ def tags
43
+ @tags ||= parsed_datagram[:tags] ? parsed_datagram[:tags].split(',') : nil
44
+ end
43
45
 
44
- def inspect
45
- "#<#{self.class.name}:\"#{@source}\">"
46
- end
46
+ def inspect
47
+ "#<#{self.class.name}:\"#{@source}\">"
48
+ end
47
49
 
48
- def hash
49
- source.hash
50
- end
50
+ def hash
51
+ source.hash
52
+ end
51
53
 
52
- def eql?(other)
53
- case other
54
- when StatsD::Instrument::Datagram
55
- source == other.source
56
- when String
57
- source == other
58
- else
59
- false
60
- end
61
- end
54
+ def eql?(other)
55
+ case other
56
+ when StatsD::Instrument::Datagram
57
+ source == other.source
58
+ when String
59
+ source == other
60
+ else
61
+ false
62
+ end
63
+ end
62
64
 
63
- alias_method :==, :eql?
65
+ alias_method :==, :eql?
64
66
 
65
- private
67
+ private
66
68
 
67
- PARSER = %r{
68
- \A
69
- (?<name>[^\:\|\@]+)\:(?<value>[^\:\|\@]+)\|(?<type>c|ms|g|s|h|d)
70
- (?:\|\@(?<sample_rate>\d*(?:\.\d*)?))?
71
- (?:\|\#(?<tags>(?:[^\|,]+(?:,[^\|,]+)*)))?
72
- \n? # In some implementations, the datagram may include a trailing newline.
73
- \z
74
- }x
69
+ PARSER = %r{
70
+ \A
71
+ (?<name>[^\:\|\@]+)\:(?<value>[^\:\|\@]+)\|(?<type>c|ms|g|s|h|d)
72
+ (?:\|\@(?<sample_rate>\d*(?:\.\d*)?))?
73
+ (?:\|\#(?<tags>(?:[^\|,]+(?:,[^\|,]+)*)))?
74
+ \n? # In some implementations, the datagram may include a trailing newline.
75
+ \z
76
+ }x
75
77
 
76
- def parsed_datagram
77
- @parsed ||= if (match_info = PARSER.match(@source))
78
- match_info
79
- else
80
- raise ArgumentError, "Invalid StatsD datagram: #{@source}"
78
+ def parsed_datagram
79
+ @parsed ||= if (match_info = PARSER.match(@source))
80
+ match_info
81
+ else
82
+ raise ArgumentError, "Invalid StatsD datagram: #{@source}"
83
+ end
84
+ end
81
85
  end
82
86
  end
83
87
  end
@@ -1,101 +1,105 @@
1
1
  # frozen_string_literal: true
2
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::DatagramBuilder
6
- unless Regexp.method_defined?(:match?) # for ruby 2.3
7
- module RubyBackports
8
- refine Regexp do
9
- def match?(str)
10
- match(str) != nil
3
+ module StatsD
4
+ module Instrument
5
+ # @note This class is part of the new Client implementation that is intended
6
+ # to become the new default in the next major release of this library.
7
+ class DatagramBuilder
8
+ unless Regexp.method_defined?(:match?) # for ruby 2.3
9
+ module RubyBackports
10
+ refine Regexp do
11
+ def match?(str)
12
+ match(str) != nil
13
+ end
14
+ end
11
15
  end
12
- end
13
- end
14
16
 
15
- using RubyBackports
16
- end
17
+ using(RubyBackports)
18
+ end
17
19
 
18
- def self.unsupported_datagram_types(*types)
19
- types.each do |type|
20
- define_method(type) do |_, _, _, _|
21
- raise NotImplementedError, "Type #{type} metrics are not supported by #{self.class.name}."
20
+ def self.unsupported_datagram_types(*types)
21
+ types.each do |type|
22
+ define_method(type) do |_, _, _, _|
23
+ raise NotImplementedError, "Type #{type} metrics are not supported by #{self.class.name}."
24
+ end
25
+ end
22
26
  end
23
- end
24
- end
25
27
 
26
- def self.datagram_class
27
- StatsD::Instrument::Datagram
28
- end
28
+ def self.datagram_class
29
+ StatsD::Instrument::Datagram
30
+ end
29
31
 
30
- def initialize(prefix: nil, default_tags: nil)
31
- @prefix = prefix.nil? ? "" : "#{normalize_name(prefix)}."
32
- @default_tags = normalize_tags(default_tags)
33
- end
32
+ def initialize(prefix: nil, default_tags: nil)
33
+ @prefix = prefix.nil? ? "" : "#{normalize_name(prefix)}."
34
+ @default_tags = normalize_tags(default_tags)
35
+ end
34
36
 
35
- def c(name, value, sample_rate, tags)
36
- generate_generic_datagram(name, value, 'c', sample_rate, tags)
37
- end
37
+ def c(name, value, sample_rate, tags)
38
+ generate_generic_datagram(name, value, 'c', sample_rate, tags)
39
+ end
38
40
 
39
- def g(name, value, sample_rate, tags)
40
- generate_generic_datagram(name, value, 'g', sample_rate, tags)
41
- end
41
+ def g(name, value, sample_rate, tags)
42
+ generate_generic_datagram(name, value, 'g', sample_rate, tags)
43
+ end
42
44
 
43
- def ms(name, value, sample_rate, tags)
44
- generate_generic_datagram(name, value, 'ms', sample_rate, tags)
45
- end
45
+ def ms(name, value, sample_rate, tags)
46
+ generate_generic_datagram(name, value, 'ms', sample_rate, tags)
47
+ end
46
48
 
47
- def s(name, value, sample_rate, tags)
48
- generate_generic_datagram(name, value, 's', sample_rate, tags)
49
- end
49
+ def s(name, value, sample_rate, tags)
50
+ generate_generic_datagram(name, value, 's', sample_rate, tags)
51
+ end
50
52
 
51
- def h(name, value, sample_rate, tags)
52
- generate_generic_datagram(name, value, 'h', sample_rate, tags)
53
- end
53
+ def h(name, value, sample_rate, tags)
54
+ generate_generic_datagram(name, value, 'h', sample_rate, tags)
55
+ end
54
56
 
55
- def d(name, value, sample_rate, tags)
56
- generate_generic_datagram(name, value, 'd', sample_rate, tags)
57
- end
57
+ def d(name, value, sample_rate, tags)
58
+ generate_generic_datagram(name, value, 'd', sample_rate, tags)
59
+ end
58
60
 
59
- def kv(name, value, sample_rate, tags)
60
- generate_generic_datagram(name, value, 'kv', sample_rate, tags)
61
- end
61
+ def kv(name, value, sample_rate, tags)
62
+ generate_generic_datagram(name, value, 'kv', sample_rate, tags)
63
+ end
62
64
 
63
- def latency_metric_type
64
- :ms
65
- end
65
+ def latency_metric_type
66
+ :ms
67
+ end
66
68
 
67
- protected
69
+ protected
68
70
 
69
- attr_reader :prefix, :default_tags
71
+ attr_reader :prefix, :default_tags
70
72
 
71
- # Utility function to convert tags to the canonical form.
72
- #
73
- # - Tags specified as key value pairs will be converted into an array
74
- # - Tags are normalized to remove unsupported characters
75
- #
76
- # @param tags [Array<String>, Hash<String, String>, nil] Tags specified in any form.
77
- # @return [Array<String>, nil] the list of tags in canonical form.
78
- def normalize_tags(tags)
79
- return [] unless tags
80
- tags = tags.map { |k, v| "#{k}:#{v}" } if tags.is_a?(Hash)
73
+ # Utility function to convert tags to the canonical form.
74
+ #
75
+ # - Tags specified as key value pairs will be converted into an array
76
+ # - Tags are normalized to remove unsupported characters
77
+ #
78
+ # @param tags [Array<String>, Hash<String, String>, nil] Tags specified in any form.
79
+ # @return [Array<String>, nil] the list of tags in canonical form.
80
+ def normalize_tags(tags)
81
+ return [] unless tags
82
+ tags = tags.map { |k, v| "#{k}:#{v}" } if tags.is_a?(Hash)
81
83
 
82
- # Fast path when no string replacement is needed
83
- return tags unless tags.any? { |tag| /[|,]/.match?(tag) }
84
- tags.map { |tag| tag.tr('|,', '') }
85
- end
84
+ # Fast path when no string replacement is needed
85
+ return tags unless tags.any? { |tag| /[|,]/.match?(tag) }
86
+ tags.map { |tag| tag.tr('|,', '') }
87
+ end
86
88
 
87
- # Utility function to remove invalid characters from a StatsD metric name
88
- def normalize_name(name)
89
- # Fast path when no normalization is needed to avoid copying the string
90
- return name unless /[:|@]/.match?(name)
91
- name.tr(':|@', '_')
92
- end
89
+ # Utility function to remove invalid characters from a StatsD metric name
90
+ def normalize_name(name)
91
+ # Fast path when no normalization is needed to avoid copying the string
92
+ return name unless /[:|@]/.match?(name)
93
+ name.tr(':|@', '_')
94
+ end
93
95
 
94
- def generate_generic_datagram(name, value, type, sample_rate, tags)
95
- tags = normalize_tags(tags) + default_tags
96
- datagram = +"#{@prefix}#{normalize_name(name)}:#{value}|#{type}"
97
- datagram << "|@#{sample_rate}" if sample_rate && sample_rate < 1
98
- datagram << "|##{tags.join(',')}" unless tags.empty?
99
- datagram
96
+ def generate_generic_datagram(name, value, type, sample_rate, tags)
97
+ tags = normalize_tags(tags) + default_tags
98
+ datagram = +"#{@prefix}#{normalize_name(name)}:#{value}|#{type}"
99
+ datagram << "|@#{sample_rate}" if sample_rate && sample_rate < 1
100
+ datagram << "|##{tags.join(',')}" unless tags.empty?
101
+ datagram
102
+ end
103
+ end
100
104
  end
101
105
  end
@@ -1,88 +1,92 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # The Datagram class parses and inspects a StatsD datagrams
4
- #
5
- # @note This class is part of the new Client implementation that is intended
6
- # to become the new default in the next major release of this library.
7
- class StatsD::Instrument::DogStatsDDatagram < StatsD::Instrument::Datagram
8
- def name
9
- @name ||= case type
10
- when :_e then parsed_datagram[:name].gsub('\n', "\n")
11
- else super
12
- end
13
- end
3
+ module StatsD
4
+ module Instrument
5
+ # The Datagram class parses and inspects a StatsD datagrams
6
+ #
7
+ # @note This class is part of the new Client implementation that is intended
8
+ # to become the new default in the next major release of this library.
9
+ class DogStatsDDatagram < StatsD::Instrument::Datagram
10
+ def name
11
+ @name ||= case type
12
+ when :_e then parsed_datagram[:name].gsub('\n', "\n")
13
+ else super
14
+ end
15
+ end
14
16
 
15
- def value
16
- @value ||= case type
17
- when :_sc then Integer(parsed_datagram[:value])
18
- when :_e then parsed_datagram[:value].gsub('\n', "\n")
19
- else super
20
- end
21
- end
17
+ def value
18
+ @value ||= case type
19
+ when :_sc then Integer(parsed_datagram[:value])
20
+ when :_e then parsed_datagram[:value].gsub('\n', "\n")
21
+ else super
22
+ end
23
+ end
22
24
 
23
- def hostname
24
- parsed_datagram[:hostname]
25
- end
25
+ def hostname
26
+ parsed_datagram[:hostname]
27
+ end
26
28
 
27
- def timestamp
28
- Time.at(Integer(parsed_datagram[:timestamp])).utc
29
- end
29
+ def timestamp
30
+ Time.at(Integer(parsed_datagram[:timestamp])).utc
31
+ end
30
32
 
31
- def aggregation_key
32
- parsed_datagram[:aggregation_key]
33
- end
33
+ def aggregation_key
34
+ parsed_datagram[:aggregation_key]
35
+ end
34
36
 
35
- def source_type_name
36
- parsed_datagram[:source_type_name]
37
- end
37
+ def source_type_name
38
+ parsed_datagram[:source_type_name]
39
+ end
38
40
 
39
- def priority
40
- parsed_datagram[:priority]
41
- end
41
+ def priority
42
+ parsed_datagram[:priority]
43
+ end
42
44
 
43
- def alert_type
44
- parsed_datagram[:alert_type]
45
- end
45
+ def alert_type
46
+ parsed_datagram[:alert_type]
47
+ end
46
48
 
47
- def message
48
- parsed_datagram[:message]
49
- end
49
+ def message
50
+ parsed_datagram[:message]
51
+ end
50
52
 
51
- protected
53
+ protected
52
54
 
53
- def parsed_datagram
54
- @parsed ||= if (match_info = PARSER.match(@source))
55
- match_info
56
- else
57
- raise ArgumentError, "Invalid DogStatsD datagram: #{@source}"
58
- end
59
- end
55
+ def parsed_datagram
56
+ @parsed ||= if (match_info = PARSER.match(@source))
57
+ match_info
58
+ else
59
+ raise ArgumentError, "Invalid DogStatsD datagram: #{@source}"
60
+ end
61
+ end
60
62
 
61
- SERVICE_CHECK_PARSER = %r{
62
- \A
63
- (?<type>_sc)\|(?<name>[^\|]+)\|(?<value>\d+)
64
- (?:\|h:(?<hostname>[^\|]+))?
65
- (?:\|d:(?<timestamp>\d+))?
66
- (?:\|\#(?<tags>(?:[^\|,]+(?:,[^\|,]+)*)))?
67
- (?:\|m:(?<message>[^\|]+))?
68
- \n? # In some implementations, the datagram may include a trailing newline.
69
- \z
70
- }x
63
+ SERVICE_CHECK_PARSER = %r{
64
+ \A
65
+ (?<type>_sc)\|(?<name>[^\|]+)\|(?<value>\d+)
66
+ (?:\|h:(?<hostname>[^\|]+))?
67
+ (?:\|d:(?<timestamp>\d+))?
68
+ (?:\|\#(?<tags>(?:[^\|,]+(?:,[^\|,]+)*)))?
69
+ (?:\|m:(?<message>[^\|]+))?
70
+ \n? # In some implementations, the datagram may include a trailing newline.
71
+ \z
72
+ }x
71
73
 
72
- # |k:my-key|p:low|s:source|t:success|
73
- EVENT_PARSER = %r{
74
- \A
75
- (?<type>_e)\{\d+\,\d+\}:(?<name>[^\|]+)\|(?<value>[^\|]+)
76
- (?:\|h:(?<hostname>[^\|]+))?
77
- (?:\|d:(?<timestamp>\d+))?
78
- (?:\|k:(?<aggregation_key>[^\|]+))?
79
- (?:\|p:(?<priority>[^\|]+))?
80
- (?:\|s:(?<source_type_name>[^\|]+))?
81
- (?:\|t:(?<alert_type>[^\|]+))?
82
- (?:\|\#(?<tags>(?:[^\|,]+(?:,[^\|,]+)*)))?
83
- \n? # In some implementations, the datagram may include a trailing newline.
84
- \z
85
- }x
74
+ # |k:my-key|p:low|s:source|t:success|
75
+ EVENT_PARSER = %r{
76
+ \A
77
+ (?<type>_e)\{\d+\,\d+\}:(?<name>[^\|]+)\|(?<value>[^\|]+)
78
+ (?:\|h:(?<hostname>[^\|]+))?
79
+ (?:\|d:(?<timestamp>\d+))?
80
+ (?:\|k:(?<aggregation_key>[^\|]+))?
81
+ (?:\|p:(?<priority>[^\|]+))?
82
+ (?:\|s:(?<source_type_name>[^\|]+))?
83
+ (?:\|t:(?<alert_type>[^\|]+))?
84
+ (?:\|\#(?<tags>(?:[^\|,]+(?:,[^\|,]+)*)))?
85
+ \n? # In some implementations, the datagram may include a trailing newline.
86
+ \z
87
+ }x
86
88
 
87
- PARSER = Regexp.union(StatsD::Instrument::Datagram::PARSER, SERVICE_CHECK_PARSER, EVENT_PARSER)
89
+ PARSER = Regexp.union(StatsD::Instrument::Datagram::PARSER, SERVICE_CHECK_PARSER, EVENT_PARSER)
90
+ end
91
+ end
88
92
  end