statsd-instrument 3.11.2 → 4.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +5 -0
- data/lib/statsd/instrument/aggregator.rb +3 -3
- data/lib/statsd/instrument/client.rb +38 -24
- data/lib/statsd/instrument/compiled_metric.rb +9 -9
- data/lib/statsd/instrument/datagram.rb +3 -3
- data/lib/statsd/instrument/datagram_builder.rb +12 -12
- data/lib/statsd/instrument/dogstatsd_datagram.rb +11 -11
- data/lib/statsd/instrument/dogstatsd_datagram_builder.rb +1 -1
- data/lib/statsd/instrument/sanitization.rb +34 -0
- data/lib/statsd/instrument/version.rb +1 -1
- data/lib/statsd/instrument.rb +1 -0
- data/test/aggregator_test.rb +68 -100
- data/test/client_test.rb +64 -0
- data/test/newline_normalization_test.rb +262 -0
- data/test/rubocop/singleton_configuration_test.rb +1 -3
- data/test/sanitization_test.rb +49 -0
- metadata +7 -2
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class NewlineNormalizationTest < Minitest::Test
|
|
6
|
+
def setup
|
|
7
|
+
@old_client = StatsD.singleton_client
|
|
8
|
+
@sink = StatsD::Instrument::CaptureSink.new(parent: StatsD::Instrument::NullSink.new)
|
|
9
|
+
@clients = []
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def teardown
|
|
13
|
+
StatsD.singleton_client = @old_client
|
|
14
|
+
@clients.each do |client|
|
|
15
|
+
aggregator = client.instance_variable_get(:@aggregator)
|
|
16
|
+
next unless aggregator
|
|
17
|
+
|
|
18
|
+
aggregator.instance_variable_get(:@flush_thread)&.kill
|
|
19
|
+
ObjectSpace.undefine_finalizer(aggregator)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def test_all_generic_metric_types_keep_line_breaks_inside_the_prefix
|
|
24
|
+
builder = StatsD::Instrument::DatagramBuilder.new(prefix: "storefront")
|
|
25
|
+
[:c, :g, :ms, :s, :h, :d, :kv].each do |type|
|
|
26
|
+
["\n", "\r", "\r\n"].each do |delimiter|
|
|
27
|
+
datagram = builder.public_send(type, "http.requests#{delimiter}checkout", 1, nil, nil)
|
|
28
|
+
assert_equal("storefront.http.requests#{"_" * delimiter.size}checkout:1|#{type}", datagram)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def test_prefix_and_name_are_sanitized_without_mutating_inputs
|
|
34
|
+
prefix = "app\r\nnamespace"
|
|
35
|
+
name = "name\r\nchild"
|
|
36
|
+
builder = StatsD::Instrument::DatagramBuilder.new(prefix: prefix)
|
|
37
|
+
assert_equal("app__namespace.name__child:1|c", builder.c(name, 1, nil, nil))
|
|
38
|
+
assert_equal("app\r\nnamespace", prefix)
|
|
39
|
+
assert_equal("name\r\nchild", name)
|
|
40
|
+
assert_equal("name__child", builder.send(:normalize_name, name))
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def test_array_and_hash_tags_remove_delimiters_without_mutating_inputs
|
|
44
|
+
builder = StatsD::Instrument::DatagramBuilder.new
|
|
45
|
+
array = ["k\r\ney:v\r\na|l,ue", "good:tag"].freeze
|
|
46
|
+
hash = { "k\r\ney" => "v\r\na|l,ue", good: "tag" }.freeze
|
|
47
|
+
[array, hash].each do |tags|
|
|
48
|
+
assert_equal("name:1|c|#key:value,good:tag", builder.c("name", 1, nil, tags))
|
|
49
|
+
end
|
|
50
|
+
assert_equal("k\r\ney:v\r\na|l,ue", array.first)
|
|
51
|
+
assert_equal("v\r\na|l,ue", hash.values.first)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def test_serialized_tags_preserve_commas_as_separators
|
|
55
|
+
builder = StatsD::Instrument::DatagramBuilder.new
|
|
56
|
+
assert_equal("name:1|c|#a:one_,b:two_", builder.c("name", 1, nil, "a:one\r,b:two\n"))
|
|
57
|
+
assert_equal("name:1|c|#a:one,b:two", builder.c("name", 1, nil, "a:one,b:two"))
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def test_default_tags_in_each_supported_representation
|
|
61
|
+
[["k:v\n"], { k: "v\n" }, "k:v\n"].each do |tags|
|
|
62
|
+
builder = StatsD::Instrument::DatagramBuilder.new(default_tags: tags)
|
|
63
|
+
datagram = builder.c("name", 1, nil, ["extra:tag"])
|
|
64
|
+
refute_match(/[\r\n]/, datagram)
|
|
65
|
+
assert_includes(datagram, ",extra:tag")
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def test_set_values_replace_newlines
|
|
70
|
+
builder = StatsD::Instrument::DatagramBuilder.new(prefix: "app")
|
|
71
|
+
assert_equal("app.users:alice__smith|s", builder.s("users", "alice\r\nsmith", nil, nil))
|
|
72
|
+
assert_equal("app.users:42|s", builder.s("users", 42, nil, nil))
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def test_unicode_and_valid_inputs_are_unchanged
|
|
76
|
+
builder = StatsD::Instrument::DatagramBuilder.new(prefix: "shop")
|
|
77
|
+
assert_equal("shop.café:1|c|#city:東京", builder.c("café", 1, nil, ["city:東京"]))
|
|
78
|
+
name = +"safe.name"
|
|
79
|
+
assert_same(name, builder.send(:normalize_name, name))
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def test_dogstatsd_service_check_name_and_tags
|
|
83
|
+
builder = StatsD::Instrument::DogStatsDDatagramBuilder.new(prefix: "app\n")
|
|
84
|
+
assert_equal("_sc|app_.service_check|0|#key:value", builder._sc("service\rcheck", :ok, tags: ["key:va\nlue"]))
|
|
85
|
+
# Event text has its own documented escaping; tag normalization must preserve it.
|
|
86
|
+
event = builder._e("title", "first\nsecond", tags: ["key:va\nlue"])
|
|
87
|
+
refute_match(/[\r\n]/, event)
|
|
88
|
+
assert_includes(event, 'first\nsecond')
|
|
89
|
+
assert_includes(event, "|#key:value")
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def test_normal_and_aggregated_client_paths
|
|
93
|
+
[false, true].each do |aggregate|
|
|
94
|
+
client = new_client(aggregate)
|
|
95
|
+
[:increment, :gauge, :measure, :distribution, :histogram].each do |method|
|
|
96
|
+
client.public_send(method, "metric\r\nname", 1, tags: { "k\r\ney" => "va\nlue" })
|
|
97
|
+
client.public_send(method, "unprefixed\nname", 1, tags: ["key:va\nlue"], no_prefix: true)
|
|
98
|
+
end
|
|
99
|
+
client.set("set\nname", "v\nalue", tags: ["key:va\nlue"])
|
|
100
|
+
client.force_flush
|
|
101
|
+
assert_equal(11, @sink.datagrams.size)
|
|
102
|
+
@sink.datagrams.each do |datagram|
|
|
103
|
+
refute_match(/[\r\n]/, datagram.source)
|
|
104
|
+
assert_includes(datagram.source, "key:value")
|
|
105
|
+
end
|
|
106
|
+
@sink.clear
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def test_aggregator_finalizer_and_unhealthy_thread_fallback
|
|
111
|
+
client = new_client(true)
|
|
112
|
+
aggregator = client.instance_variable_get(:@aggregator)
|
|
113
|
+
client.increment("name\nchild", tags: ["key:va\nlue"])
|
|
114
|
+
finalizer = aggregator.instance_variable_get(:@finalizer)
|
|
115
|
+
StatsD::Instrument::Aggregator.finalize(finalizer).call
|
|
116
|
+
assert_equal(1, @sink.datagrams.size)
|
|
117
|
+
refute_match(/[\r\n]/, @sink.datagrams.first.source)
|
|
118
|
+
|
|
119
|
+
@sink.clear
|
|
120
|
+
aggregator.stubs(:thread_healthcheck).returns(false)
|
|
121
|
+
client.increment("name\nchild", tags: ["key:va\nlue"])
|
|
122
|
+
assert_equal(1, @sink.datagrams.size)
|
|
123
|
+
refute_match(/[\r\n]/, @sink.datagrams.first.source)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def test_compiled_static_and_dynamic_fields_with_and_without_aggregation
|
|
127
|
+
[false, true].each do |aggregate|
|
|
128
|
+
client = new_client(aggregate)
|
|
129
|
+
StatsD.singleton_client = client
|
|
130
|
+
[
|
|
131
|
+
StatsD::Instrument::CompiledMetric::Counter,
|
|
132
|
+
StatsD::Instrument::CompiledMetric::Gauge,
|
|
133
|
+
StatsD::Instrument::CompiledMetric::Distribution,
|
|
134
|
+
].each do |base|
|
|
135
|
+
metric = Class.new(base) do
|
|
136
|
+
define(name: "name\r\nchild", static_tags: { "static\nkey" => "va\rlue" }, tags: { dynamic: String, symbol: Symbol })
|
|
137
|
+
end
|
|
138
|
+
2.times { metric.public_send(base.method_name, 1, dynamic: "va\nlue", symbol: :"sym\rbol") }
|
|
139
|
+
client.force_flush
|
|
140
|
+
assert_equal(aggregate ? 1 : 2, @sink.datagrams.size)
|
|
141
|
+
@sink.datagrams.each do |datagram|
|
|
142
|
+
refute_match(/[\r\n]/, datagram.source)
|
|
143
|
+
assert_includes(datagram.source, "app_.name__child:")
|
|
144
|
+
assert_includes(datagram.source, "statickey:value")
|
|
145
|
+
assert_includes(datagram.source, "dynamic:value,symbol:symbol")
|
|
146
|
+
end
|
|
147
|
+
@sink.clear
|
|
148
|
+
|
|
149
|
+
metric = Class.new(base) { define(name: "static\nname", static_tags: { key: "va\nlue" }) }
|
|
150
|
+
metric.public_send(base.method_name, 1)
|
|
151
|
+
client.force_flush
|
|
152
|
+
assert_equal(1, @sink.datagrams.size)
|
|
153
|
+
refute_match(/[\r\n]/, @sink.datagrams.first.source)
|
|
154
|
+
@sink.clear
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def test_compiled_default_tags_and_dynamic_keys
|
|
160
|
+
builder = StatsD::Instrument::CompiledMetric::DatagramBlueprintBuilder
|
|
161
|
+
[["default:va\nlue"], { default: "va\nlue" }, "default:va\nlue"].each do |tags|
|
|
162
|
+
blueprint = builder.build(
|
|
163
|
+
name: "name\n",
|
|
164
|
+
type: "c",
|
|
165
|
+
client_prefix: "app\r",
|
|
166
|
+
no_prefix: false,
|
|
167
|
+
default_tags: tags,
|
|
168
|
+
static_tags: {},
|
|
169
|
+
dynamic_tags: { "dy\nnamic" => String },
|
|
170
|
+
sample_rate: 1,
|
|
171
|
+
)
|
|
172
|
+
datagram = StatsD::Instrument::CompiledMetric::PrecompiledDatagram.new(["va\nlue"], blueprint, 1).to_datagram(1)
|
|
173
|
+
assert_equal("app_.name_:1|c|#default:value,dynamic:value", datagram)
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def test_compiled_dynamic_tags_are_checked_after_mutation_and_with_cache_disabled
|
|
178
|
+
StatsD.singleton_client = new_client(false)
|
|
179
|
+
metric = Class.new(StatsD::Instrument::CompiledMetric::Counter) do
|
|
180
|
+
define(name: "name", tags: { key: String }, max_cache_size: 0)
|
|
181
|
+
end
|
|
182
|
+
tag = +"value"
|
|
183
|
+
metric.increment(key: tag)
|
|
184
|
+
@sink.clear
|
|
185
|
+
tag << "\nwith|newline"
|
|
186
|
+
metric.increment(key: tag)
|
|
187
|
+
assert_equal(1, @sink.datagrams.size)
|
|
188
|
+
refute_match(/[\r\n]/, @sink.datagrams.first.source)
|
|
189
|
+
assert_includes(@sink.datagrams.first.source, "|#default:value,key:valuewithnewline")
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def test_compiled_name_does_not_freeze_the_input_string
|
|
193
|
+
StatsD.singleton_client = new_client(false)
|
|
194
|
+
name = +"name"
|
|
195
|
+
metric = Class.new(StatsD::Instrument::CompiledMetric::Counter)
|
|
196
|
+
metric.define(name: name)
|
|
197
|
+
name << ".changed"
|
|
198
|
+
assert_equal("name", metric.metric_name)
|
|
199
|
+
assert_predicate(metric.metric_name, :frozen?)
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def test_normalization_is_silent
|
|
203
|
+
StatsD.logger.expects(:warn).never
|
|
204
|
+
StatsD.logger.expects(:error).never
|
|
205
|
+
client = new_client(false)
|
|
206
|
+
client.increment("name\n", tags: ["key:va\nlue"])
|
|
207
|
+
assert_equal(1, @sink.datagrams.size)
|
|
208
|
+
assert_equal("app_.name_:1|c|#default:value,key:value", @sink.datagrams.first.source)
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def test_names_and_prefixes_share_normalization_across_all_paths
|
|
212
|
+
[false, true].each do |aggregate|
|
|
213
|
+
[" ", "\t", "\n", "\r", "\f", "\v", ":", "|", "@"].each do |character|
|
|
214
|
+
client = new_client(aggregate).clone_with_options(prefix: "app#{character}prefix")
|
|
215
|
+
@clients << client
|
|
216
|
+
StatsD.singleton_client = client
|
|
217
|
+
client.increment("my#{character}value")
|
|
218
|
+
client.increment("my#{character}value", no_prefix: true)
|
|
219
|
+
metric = Class.new(StatsD::Instrument::CompiledMetric::Counter)
|
|
220
|
+
metric.define(name: "my#{character}value")
|
|
221
|
+
metric.increment
|
|
222
|
+
unprefixed = Class.new(StatsD::Instrument::CompiledMetric::Counter)
|
|
223
|
+
unprefixed.define(name: "my#{character}value", no_prefix: true)
|
|
224
|
+
unprefixed.increment
|
|
225
|
+
client.force_flush
|
|
226
|
+
assert_equal(4, @sink.datagrams.size)
|
|
227
|
+
assert_equal(["app_prefix.my_value", "app_prefix.my_value", "my_value", "my_value"], @sink.datagrams.map(&:name).sort)
|
|
228
|
+
assert_equal("my_value", metric.metric_name)
|
|
229
|
+
@sink.clear
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def test_tag_values_and_service_check_messages_keep_spaces
|
|
235
|
+
builder = StatsD::Instrument::DogStatsDDatagramBuilder.new(prefix: "my app")
|
|
236
|
+
assert_equal("my_app.my_metric:1|c|#key:hello world", builder.c("my metric", 1, nil, ["key:hello world"]))
|
|
237
|
+
assert_equal("my_app.my_metric:1|c|#key:hello world", builder.c("my metric", 1, nil, { key: "hello world" }))
|
|
238
|
+
assert_equal("my_app.users:Alice Smith|s", builder.s("users", "Alice Smith", nil, nil))
|
|
239
|
+
assert_equal("_sc|my_app.my_service|0|m:hello world_", builder._sc("my service", :ok, message: "hello world\n"))
|
|
240
|
+
|
|
241
|
+
StatsD.singleton_client = new_client(false)
|
|
242
|
+
metric = Class.new(StatsD::Instrument::CompiledMetric::Counter)
|
|
243
|
+
metric.define(name: "my metric", static_tags: { static: "hello world" }, tags: { dynamic: String })
|
|
244
|
+
metric.increment(dynamic: "hello world")
|
|
245
|
+
assert_includes(@sink.datagrams.last.tags, "static:hello world")
|
|
246
|
+
assert_includes(@sink.datagrams.last.tags, "dynamic:hello world")
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
private
|
|
250
|
+
|
|
251
|
+
def new_client(aggregate)
|
|
252
|
+
client = StatsD::Instrument::Client.new(
|
|
253
|
+
sink: @sink,
|
|
254
|
+
prefix: "app\n",
|
|
255
|
+
default_tags: ["default:va\nlue"],
|
|
256
|
+
enable_aggregation: aggregate,
|
|
257
|
+
aggregation_flush_interval: 3600,
|
|
258
|
+
)
|
|
259
|
+
@clients << client
|
|
260
|
+
client
|
|
261
|
+
end
|
|
262
|
+
end
|
|
@@ -19,9 +19,7 @@ module Rubocop
|
|
|
19
19
|
def test_offense_statsd_prefix
|
|
20
20
|
assert_offense('StatsD.prefix = "foo"')
|
|
21
21
|
# The interpolation is intentionally literal source passed to the cop under test.
|
|
22
|
-
|
|
23
|
-
assert_offense('"#{StatsD.prefix}.foo"')
|
|
24
|
-
# rubocop:enable Lint/InterpolationCheck
|
|
22
|
+
assert_offense("\"\#{StatsD.prefix}.foo\"")
|
|
25
23
|
end
|
|
26
24
|
|
|
27
25
|
def test_offense_statsd_default_tags
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class SanitizationTest < Minitest::Test
|
|
6
|
+
def test_clean_input_is_returned_without_copying_or_freezing
|
|
7
|
+
[:name, :tag, :service_check_message].each do |method|
|
|
8
|
+
mutable = +"café.safe_value"
|
|
9
|
+
assert_same(mutable, StatsD::Instrument::Sanitization.public_send(method, mutable))
|
|
10
|
+
refute_predicate(mutable, :frozen?)
|
|
11
|
+
assert_same(mutable.freeze, StatsD::Instrument::Sanitization.public_send(method, mutable))
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def test_name_replaces_each_ascii_whitespace_and_protocol_delimiter
|
|
16
|
+
[" ", "\t", "\n", "\r", "\f", "\v", ":", "|", "@"].each do |character|
|
|
17
|
+
name = +"prefix.#{character}my#{character}value"
|
|
18
|
+
expected_original = name.dup
|
|
19
|
+
assert_equal("prefix._my_value", StatsD::Instrument::Sanitization.name(name))
|
|
20
|
+
assert_equal(expected_original, name)
|
|
21
|
+
refute_predicate(name, :frozen?)
|
|
22
|
+
end
|
|
23
|
+
assert_equal("name___value", StatsD::Instrument::Sanitization.name("name \t\nvalue"))
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def test_name_does_not_expand_whitespace_matching_to_unicode
|
|
27
|
+
name = "café\u00a0value"
|
|
28
|
+
assert_same(name, StatsD::Instrument::Sanitization.name(name))
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def test_tags_and_values_keep_ordinary_whitespace
|
|
32
|
+
text = "hello \tworld\f\v"
|
|
33
|
+
[:tag, :service_check_message].each do |method|
|
|
34
|
+
assert_same(text, StatsD::Instrument::Sanitization.public_send(method, text))
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def test_each_field_preserves_its_existing_replacement_rules
|
|
39
|
+
sanitizer = StatsD::Instrument::Sanitization
|
|
40
|
+
assert_equal("tag:value", sanitizer.tag("tag:va|,\r\nlue"))
|
|
41
|
+
assert_equal("hello world____", sanitizer.service_check_message("hello world:|@\n"))
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def test_compiled_name_helper_returns_clean_input_unchanged
|
|
45
|
+
name = +"name"
|
|
46
|
+
assert_same(name, StatsD::Instrument::CompiledMetric::DatagramBlueprintBuilder.normalize_name(name))
|
|
47
|
+
refute_predicate(name, :frozen?)
|
|
48
|
+
end
|
|
49
|
+
end
|
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:
|
|
4
|
+
version: 4.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jesse Storimer
|
|
@@ -71,6 +71,7 @@ files:
|
|
|
71
71
|
- lib/statsd/instrument/rubocop/positional_arguments.rb
|
|
72
72
|
- lib/statsd/instrument/rubocop/singleton_configuration.rb
|
|
73
73
|
- lib/statsd/instrument/rubocop/splat_arguments.rb
|
|
74
|
+
- lib/statsd/instrument/sanitization.rb
|
|
74
75
|
- lib/statsd/instrument/sink.rb
|
|
75
76
|
- lib/statsd/instrument/statsd_datagram_builder.rb
|
|
76
77
|
- lib/statsd/instrument/strict.rb
|
|
@@ -101,6 +102,7 @@ files:
|
|
|
101
102
|
- test/integration_test.rb
|
|
102
103
|
- test/log_sink_test.rb
|
|
103
104
|
- test/matchers_test.rb
|
|
105
|
+
- test/newline_normalization_test.rb
|
|
104
106
|
- test/null_sink_test.rb
|
|
105
107
|
- test/rubocop/measure_as_dist_argument_test.rb
|
|
106
108
|
- test/rubocop/metaprogramming_positional_arguments_test.rb
|
|
@@ -110,6 +112,7 @@ files:
|
|
|
110
112
|
- test/rubocop/positional_arguments_test.rb
|
|
111
113
|
- test/rubocop/singleton_configuration_test.rb
|
|
112
114
|
- test/rubocop/splat_arguments_test.rb
|
|
115
|
+
- test/sanitization_test.rb
|
|
113
116
|
- test/statsd_datagram_builder_test.rb
|
|
114
117
|
- test/statsd_instrumentation_test.rb
|
|
115
118
|
- test/statsd_test.rb
|
|
@@ -135,7 +138,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
135
138
|
- !ruby/object:Gem::Version
|
|
136
139
|
version: '0'
|
|
137
140
|
requirements: []
|
|
138
|
-
rubygems_version: 4.0.
|
|
141
|
+
rubygems_version: 4.0.21
|
|
139
142
|
specification_version: 4
|
|
140
143
|
summary: A StatsD client for Ruby apps
|
|
141
144
|
test_files:
|
|
@@ -161,6 +164,7 @@ test_files:
|
|
|
161
164
|
- test/integration_test.rb
|
|
162
165
|
- test/log_sink_test.rb
|
|
163
166
|
- test/matchers_test.rb
|
|
167
|
+
- test/newline_normalization_test.rb
|
|
164
168
|
- test/null_sink_test.rb
|
|
165
169
|
- test/rubocop/measure_as_dist_argument_test.rb
|
|
166
170
|
- test/rubocop/metaprogramming_positional_arguments_test.rb
|
|
@@ -170,6 +174,7 @@ test_files:
|
|
|
170
174
|
- test/rubocop/positional_arguments_test.rb
|
|
171
175
|
- test/rubocop/singleton_configuration_test.rb
|
|
172
176
|
- test/rubocop/splat_arguments_test.rb
|
|
177
|
+
- test/sanitization_test.rb
|
|
173
178
|
- test/statsd_datagram_builder_test.rb
|
|
174
179
|
- test/statsd_instrumentation_test.rb
|
|
175
180
|
- test/statsd_test.rb
|