statsd-instrument 3.5.12 → 3.6.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 41254f0057c645926c54b36ec4bf937352444740f0cae248b1feed1f35ce4044
4
- data.tar.gz: 3d2131889385d2755a738d735ca9a20dba0342e645d58312c4007b7a1835b249
3
+ metadata.gz: a5e3cda783c5f0c7de2c30175ab001cef492c3ad0e0923af3d3a4840df7d6005
4
+ data.tar.gz: b31685696c6e1ad8e5cd36a8115eca2363ed9a732a483534004b2163453b323a
5
5
  SHA512:
6
- metadata.gz: 46a4f427f2e298c242a84c7f90a715a7d4397c28ad5db8f89f8b669e3867c7b253a5858a61e35768fada113b56202dc43d91cffb68b9626ea79c26fd15d10a67
7
- data.tar.gz: 99b1979f9b3b9a4e502c78a42bfa48348600eece64646ddfdd2470ae1d3b4cc52123e3edaef539886c667ff2e9eca98051c55c5fec7c6ccc76e1404e2f5f2800
6
+ metadata.gz: 658663a99a273170ad72436eae0142d707e35a8cc2bbf5befd89a7cd225db5673c5ec676e8f96a168411f443fa7d3e6b73f60c6f081067082b2003920cef264b
7
+ data.tar.gz: bc8930e083ec158ca6a945186c2156a0890ebe74edb63080dc6ced9ca691498edc9d81ae746ec80477471c3b2f09d3abb95042002c0c8e7d72afeb9ab360526c
data/CHANGELOG.md CHANGED
@@ -6,6 +6,14 @@ section below.
6
6
 
7
7
  ## Unreleased changes
8
8
 
9
+ ## Version 3.6.1
10
+
11
+ - Fix `ArgumentError` when passing an empty Hash as tags.
12
+
13
+ ## Version 3.6.0
14
+
15
+ - Optimized datagram building.
16
+
9
17
  ## Version 3.5.12
10
18
 
11
19
  - Update CONTRIBUTING docs about release process
@@ -140,13 +140,15 @@ module StatsD
140
140
  # on their frequency, rather than changing the default sample rate.
141
141
  #
142
142
  # @return [Float] (default: 1.0) A value between 0.0 and 1.0.
143
- attr_reader :default_sample_rate
143
+ def default_sample_rate
144
+ @default_sample_rate || 1.0
145
+ end
144
146
 
145
147
  # Instantiates a new client.
146
148
  # @see .from_env to instantiate a client using environment variables.
147
149
  def initialize(
148
150
  prefix: nil,
149
- default_sample_rate: 1.0,
151
+ default_sample_rate: nil,
150
152
  default_tags: nil,
151
153
  implementation: "datadog",
152
154
  sink: StatsD::Instrument::NullSink.new,
@@ -199,9 +201,10 @@ module StatsD
199
201
  # @return [void]
200
202
  def increment(name, value = 1, sample_rate: nil, tags: nil, no_prefix: false)
201
203
  sample_rate ||= @default_sample_rate
202
- return StatsD::Instrument::VOID unless sample?(sample_rate)
203
-
204
- emit(datagram_builder(no_prefix: no_prefix).c(name, value, sample_rate, tags))
204
+ if sample_rate.nil? || sample?(sample_rate)
205
+ emit(datagram_builder(no_prefix: no_prefix).c(name, value, sample_rate, tags))
206
+ end
207
+ StatsD::Instrument::VOID
205
208
  end
206
209
 
207
210
  # Emits a timing metric.
@@ -217,9 +220,10 @@ module StatsD
217
220
  end
218
221
 
219
222
  sample_rate ||= @default_sample_rate
220
- return StatsD::Instrument::VOID unless sample?(sample_rate)
221
-
222
- emit(datagram_builder(no_prefix: no_prefix).ms(name, value, sample_rate, tags))
223
+ if sample_rate.nil? || sample?(sample_rate)
224
+ emit(datagram_builder(no_prefix: no_prefix).ms(name, value, sample_rate, tags))
225
+ end
226
+ StatsD::Instrument::VOID
223
227
  end
224
228
 
225
229
  # Emits a gauge metric.
@@ -237,9 +241,10 @@ module StatsD
237
241
  # @return [void]
238
242
  def gauge(name, value, sample_rate: nil, tags: nil, no_prefix: false)
239
243
  sample_rate ||= @default_sample_rate
240
- return StatsD::Instrument::VOID unless sample?(sample_rate)
241
-
242
- emit(datagram_builder(no_prefix: no_prefix).g(name, value, sample_rate, tags))
244
+ if sample_rate.nil? || sample?(sample_rate)
245
+ emit(datagram_builder(no_prefix: no_prefix).g(name, value, sample_rate, tags))
246
+ end
247
+ StatsD::Instrument::VOID
243
248
  end
244
249
 
245
250
  # Emits a set metric, which counts distinct values.
@@ -251,9 +256,10 @@ module StatsD
251
256
  # @return [void]
252
257
  def set(name, value, sample_rate: nil, tags: nil, no_prefix: false)
253
258
  sample_rate ||= @default_sample_rate
254
- return StatsD::Instrument::VOID unless sample?(sample_rate)
255
-
256
- emit(datagram_builder(no_prefix: no_prefix).s(name, value, sample_rate, tags))
259
+ if sample_rate.nil? || sample?(sample_rate)
260
+ emit(datagram_builder(no_prefix: no_prefix).s(name, value, sample_rate, tags))
261
+ end
262
+ StatsD::Instrument::VOID
257
263
  end
258
264
 
259
265
  # Emits a distribution metric, which builds a histogram of the reported
@@ -274,9 +280,10 @@ module StatsD
274
280
  end
275
281
 
276
282
  sample_rate ||= @default_sample_rate
277
- return StatsD::Instrument::VOID unless sample?(sample_rate)
278
-
279
- emit(datagram_builder(no_prefix: no_prefix).d(name, value, sample_rate, tags))
283
+ if sample_rate.nil? || sample?(sample_rate)
284
+ emit(datagram_builder(no_prefix: no_prefix).d(name, value, sample_rate, tags))
285
+ end
286
+ StatsD::Instrument::VOID
280
287
  end
281
288
 
282
289
  # Emits a histogram metric, which builds a histogram of the reported values.
@@ -292,9 +299,10 @@ module StatsD
292
299
  # @return [void]
293
300
  def histogram(name, value, sample_rate: nil, tags: nil, no_prefix: false)
294
301
  sample_rate ||= @default_sample_rate
295
- return StatsD::Instrument::VOID unless sample?(sample_rate)
296
-
297
- emit(datagram_builder(no_prefix: no_prefix).h(name, value, sample_rate, tags))
302
+ if sample_rate.nil? || sample?(sample_rate)
303
+ emit(datagram_builder(no_prefix: no_prefix).h(name, value, sample_rate, tags))
304
+ end
305
+ StatsD::Instrument::VOID
298
306
  end
299
307
 
300
308
  # @!endgroup
@@ -317,7 +325,7 @@ module StatsD
317
325
  stop = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
318
326
 
319
327
  sample_rate ||= @default_sample_rate
320
- if sample?(sample_rate)
328
+ if sample_rate.nil? || sample?(sample_rate)
321
329
  metric_type ||= datagram_builder(no_prefix: no_prefix).latency_metric_type
322
330
  latency_in_ms = stop - start
323
331
  emit(datagram_builder(no_prefix: no_prefix).send(metric_type, name, latency_in_ms, sample_rate, tags))
@@ -20,8 +20,8 @@ module StatsD
20
20
  end
21
21
 
22
22
  def initialize(prefix: nil, default_tags: nil)
23
- @prefix = prefix.nil? ? "" : "#{normalize_name(prefix)}."
24
- @default_tags = normalize_tags(default_tags)
23
+ @prefix = prefix.nil? ? "" : "#{prefix}.".tr(":|@", "_")
24
+ @default_tags = default_tags.nil? || default_tags.empty? ? nil : compile_tags(default_tags, "|#".b)
25
25
  end
26
26
 
27
27
  def c(name, value, sample_rate, tags)
@@ -58,26 +58,6 @@ module StatsD
58
58
 
59
59
  protected
60
60
 
61
- attr_reader :prefix, :default_tags
62
-
63
- # Utility function to convert tags to the canonical form.
64
- #
65
- # - Tags specified as key value pairs will be converted into an array
66
- # - Tags are normalized to remove unsupported characters
67
- #
68
- # @param tags [Array<String>, Hash<String, String>, nil] Tags specified in any form.
69
- # @return [Array<String>, nil] the list of tags in canonical form.
70
- def normalize_tags(tags)
71
- return [] unless tags
72
-
73
- tags = tags.map { |k, v| "#{k}:#{v}" } if tags.is_a?(Hash)
74
-
75
- # Fast path when no string replacement is needed
76
- return tags unless tags.any? { |tag| /[|,]/.match?(tag) }
77
-
78
- tags.map { |tag| tag.tr("|,", "") }
79
- end
80
-
81
61
  # Utility function to remove invalid characters from a StatsD metric name
82
62
  def normalize_name(name)
83
63
  # Fast path when no normalization is needed to avoid copying the string
@@ -87,12 +67,49 @@ module StatsD
87
67
  end
88
68
 
89
69
  def generate_generic_datagram(name, value, type, sample_rate, tags)
90
- tags = normalize_tags(tags) + default_tags
91
- datagram = +"#{@prefix}#{normalize_name(name)}:#{value}|#{type}"
92
- datagram << "|@#{sample_rate}" if sample_rate && sample_rate < 1
93
- datagram << "|##{tags.join(",")}" unless tags.empty?
70
+ datagram = "".b <<
71
+ @prefix <<
72
+ (/[:|@]/.match?(name) ? name.tr(":|@", "_") : name) <<
73
+ ":" << value.to_s <<
74
+ "|" << type
75
+
76
+ datagram << "|@" << sample_rate.to_s if sample_rate && sample_rate < 1
77
+
78
+ unless @default_tags.nil?
79
+ datagram << @default_tags
80
+ end
81
+
82
+ unless tags.nil? || tags.empty?
83
+ datagram << (@default_tags.nil? ? "|#" : ",")
84
+ compile_tags(tags, datagram)
85
+ end
86
+
94
87
  datagram
95
88
  end
89
+
90
+ def compile_tags(tags, buffer = "".b)
91
+ if tags.is_a?(Hash)
92
+ first = true
93
+ tags.each do |key, value|
94
+ if first
95
+ first = false
96
+ else
97
+ buffer << ","
98
+ end
99
+ key = key.to_s
100
+ key = key.tr("|,", "") if /[|,]/.match?(key)
101
+ value = value.to_s
102
+ value = value.tr("|,", "") if /[|,]/.match?(value)
103
+ buffer << key << ":" << value
104
+ end
105
+ else
106
+ if tags.any? { |tag| /[|,]/.match?(tag) }
107
+ tags = tags.map { |tag| tag.tr("|,", "") }
108
+ end
109
+ buffer << tags.join(",")
110
+ end
111
+ buffer
112
+ end
96
113
  end
97
114
  end
98
115
  end
@@ -36,7 +36,6 @@ module StatsD
36
36
 
37
37
  escaped_title = "#{@prefix}#{title}".gsub("\n", '\n')
38
38
  escaped_text = text.gsub("\n", '\n')
39
- tags = normalize_tags(tags) + default_tags
40
39
 
41
40
  datagram = +"_e{#{escaped_title.length},#{escaped_text.length}}:#{escaped_title}|#{escaped_text}"
42
41
  datagram << "|h:#{hostname}" if hostname
@@ -45,7 +44,16 @@ module StatsD
45
44
  datagram << "|p:#{priority}" if priority
46
45
  datagram << "|s:#{source_type_name}" if source_type_name
47
46
  datagram << "|t:#{alert_type}" if alert_type
48
- datagram << "|##{tags.join(",")}" unless tags.empty?
47
+
48
+ unless @default_tags.nil?
49
+ datagram << @default_tags
50
+ end
51
+
52
+ unless tags.nil? || tags.empty?
53
+ datagram << (@default_tags.nil? ? "|#" : ",")
54
+ compile_tags(tags, datagram)
55
+ end
56
+
49
57
  datagram
50
58
  end
51
59
 
@@ -63,12 +71,20 @@ module StatsD
63
71
  # @see https://docs.datadoghq.com/developers/dogstatsd/datagram_shell/#service-checks
64
72
  def _sc(name, status, timestamp: nil, hostname: nil, tags: nil, message: nil)
65
73
  status_number = status.is_a?(Integer) ? status : SERVICE_CHECK_STATUS_VALUES.fetch(status.to_sym)
66
- tags = normalize_tags(tags) + default_tags
67
74
 
68
75
  datagram = +"_sc|#{@prefix}#{normalize_name(name)}|#{status_number}"
69
76
  datagram << "|h:#{hostname}" if hostname
70
77
  datagram << "|d:#{timestamp.to_i}" if timestamp
71
- datagram << "|##{tags.join(",")}" unless tags.empty?
78
+
79
+ unless @default_tags.nil?
80
+ datagram << @default_tags
81
+ end
82
+
83
+ unless tags.nil? || tags.empty?
84
+ datagram << (@default_tags.nil? ? "|#" : ",")
85
+ compile_tags(tags, datagram)
86
+ end
87
+
72
88
  datagram << "|m:#{normalize_name(message)}" if message
73
89
  datagram
74
90
  end
@@ -9,10 +9,8 @@ module StatsD
9
9
 
10
10
  protected
11
11
 
12
- def normalize_tags(tags)
13
- raise NotImplementedError, "#{self.class.name} does not support tags" if tags
14
-
15
- super
12
+ def compile_tags(*)
13
+ raise NotImplementedError, "#{self.class.name} does not support tags"
16
14
  end
17
15
  end
18
16
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module StatsD
4
4
  module Instrument
5
- VERSION = "3.5.12"
5
+ VERSION = "3.6.1"
6
6
  end
7
7
  end
data/test/client_test.rb CHANGED
@@ -206,7 +206,7 @@ class ClientTest < Minitest::Test
206
206
  mock_sink.stubs(:sample?).returns(false, true, false, false, true)
207
207
  mock_sink.expects(:<<).twice
208
208
 
209
- client = StatsD::Instrument::Client.new(sink: mock_sink)
209
+ client = StatsD::Instrument::Client.new(sink: mock_sink, default_sample_rate: 0.5)
210
210
  5.times { client.increment("metric") }
211
211
  end
212
212
 
@@ -14,17 +14,17 @@ class DatagramBuilderTest < Minitest::Test
14
14
  assert_equal("fo_o", @datagram_builder.send(:normalize_name, "fo:o"))
15
15
  end
16
16
 
17
- def test_normalize_unsupported_tag_names
18
- assert_equal(["ign#ored"], @datagram_builder.send(:normalize_tags, ["ign#o|re,d"]))
17
+ def test_compile_unsupported_tag_names
18
+ assert_equal("ign#ored", @datagram_builder.send(:compile_tags, ["ign#o|re,d"]))
19
19
  # NOTE: how this is interpreted by the backend is undefined.
20
20
  # We rely on the user to not do stuff like this if they don't want to be surprised.
21
21
  # We do not want to take the performance hit of normalizing this.
22
- assert_equal(["lol::class:omg::lol"], @datagram_builder.send(:normalize_tags, "lol::class" => "omg::lol"))
22
+ assert_equal("lol::class:omg::lol", @datagram_builder.send(:compile_tags, { "lol::class" => "omg::lol" }))
23
23
  end
24
24
 
25
- def test_normalize_tags_converts_hash_to_array
26
- assert_equal(["tag:value"], @datagram_builder.send(:normalize_tags, tag: "value"))
27
- assert_equal(["tag1:v1", "tag2:v2"], @datagram_builder.send(:normalize_tags, tag1: "v1", tag2: "v2"))
25
+ def test_compile_tags_converts_hash_to_array
26
+ assert_equal("tag:value", @datagram_builder.send(:compile_tags, { tag: "value" }))
27
+ assert_equal("tag1:v1,tag2:v2", @datagram_builder.send(:compile_tags, { tag1: "v1", tag2: "v2" }))
28
28
  end
29
29
 
30
30
  def test_c
@@ -76,6 +76,12 @@ class DatagramBuilderTest < Minitest::Test
76
76
  end
77
77
 
78
78
  def test_tags
79
+ datagram = @datagram_builder.d("foo", 10, nil, {})
80
+ assert_equal("foo:10|d", datagram)
81
+
82
+ datagram = @datagram_builder.d("foo", 10, nil, [])
83
+ assert_equal("foo:10|d", datagram)
84
+
79
85
  datagram = @datagram_builder.d("foo", 10, nil, ["foo", "bar"])
80
86
  assert_equal("foo:10|d|#foo,bar", datagram)
81
87
 
@@ -103,7 +109,7 @@ class DatagramBuilderTest < Minitest::Test
103
109
  assert_equal("bar:1|c|#foo", datagram)
104
110
 
105
111
  datagram = datagram_builder.c("bar", 1, nil, a: "b")
106
- assert_equal("bar:1|c|#a:b,foo", datagram)
112
+ assert_equal("bar:1|c|#foo,a:b", datagram)
107
113
 
108
114
  # We do not filter out duplicates, because detecting dupes is too time consuming.
109
115
  # We let the server deal with the situation
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: 3.5.12
4
+ version: 3.6.1
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: 2023-08-25 00:00:00.000000000 Z
13
+ date: 2023-11-06 00:00:00.000000000 Z
14
14
  dependencies: []
15
15
  description: A StatsD client for Ruby apps. Provides metaprogramming methods to inject
16
16
  StatsD instrumentation into your code.
@@ -122,7 +122,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
122
122
  - !ruby/object:Gem::Version
123
123
  version: '0'
124
124
  requirements: []
125
- rubygems_version: 3.4.18
125
+ rubygems_version: 3.4.21
126
126
  signing_key:
127
127
  specification_version: 4
128
128
  summary: A StatsD client for Ruby apps