statsd-instrument 3.8.0 → 3.9.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/.github/pull_request_template.md +14 -0
- data/.github/workflows/benchmark.yml +2 -2
- data/.github/workflows/lint.yml +1 -1
- data/.github/workflows/tests.yml +2 -2
- data/.ruby-version +1 -1
- data/CHANGELOG.md +12 -0
- data/Gemfile +7 -0
- data/README.md +46 -0
- data/Rakefile +11 -0
- data/benchmark/local-udp-throughput +178 -13
- data/benchmark/send-metrics-to-local-udp-receiver +6 -4
- data/lib/statsd/instrument/aggregator.rb +259 -0
- data/lib/statsd/instrument/{batched_udp_sink.rb → batched_sink.rb} +40 -24
- data/lib/statsd/instrument/client.rb +65 -7
- data/lib/statsd/instrument/datagram.rb +6 -2
- data/lib/statsd/instrument/datagram_builder.rb +21 -0
- data/lib/statsd/instrument/environment.rb +35 -7
- data/lib/statsd/instrument/{udp_sink.rb → sink.rb} +34 -25
- data/lib/statsd/instrument/udp_connection.rb +39 -0
- data/lib/statsd/instrument/uds_connection.rb +52 -0
- data/lib/statsd/instrument/version.rb +1 -1
- data/lib/statsd/instrument.rb +9 -3
- data/test/aggregator_test.rb +142 -0
- data/test/client_test.rb +36 -1
- data/test/datagram_builder_test.rb +5 -0
- data/test/dispatcher_stats_test.rb +3 -3
- data/test/environment_test.rb +4 -4
- data/test/integration_test.rb +51 -0
- data/test/test_helper.rb +6 -1
- data/test/udp_sink_test.rb +7 -6
- data/test/uds_sink_test.rb +187 -0
- metadata +16 -8
data/test/udp_sink_test.rb
CHANGED
@@ -107,7 +107,8 @@ module UDPSinkTests
|
|
107
107
|
private
|
108
108
|
|
109
109
|
def build_sink(host = @host, port = @port)
|
110
|
-
|
110
|
+
connection = StatsD::Instrument::UdpConnection.new(host, port)
|
111
|
+
StatsD::Instrument::Sink.new(connection)
|
111
112
|
end
|
112
113
|
|
113
114
|
def read_datagrams(count, timeout: ENV["CI"] ? 5 : 1)
|
@@ -132,7 +133,7 @@ class UDPSinkTest < Minitest::Test
|
|
132
133
|
@receiver.bind("localhost", 0)
|
133
134
|
@host = @receiver.addr[2]
|
134
135
|
@port = @receiver.addr[1]
|
135
|
-
@sink_class = StatsD::Instrument::
|
136
|
+
@sink_class = StatsD::Instrument::Sink
|
136
137
|
end
|
137
138
|
|
138
139
|
def teardown
|
@@ -167,7 +168,7 @@ class UDPSinkTest < Minitest::Test
|
|
167
168
|
ensure
|
168
169
|
StatsD.logger = previous_logger
|
169
170
|
# Make sure our fake socket is closed so that it doesn't interfere with other tests
|
170
|
-
udp_sink&.send(:
|
171
|
+
udp_sink&.send(:invalidate_connection)
|
171
172
|
end
|
172
173
|
end
|
173
174
|
end
|
@@ -180,7 +181,7 @@ class BatchedUDPSinkTest < Minitest::Test
|
|
180
181
|
@receiver.bind("localhost", 0)
|
181
182
|
@host = @receiver.addr[2]
|
182
183
|
@port = @receiver.addr[1]
|
183
|
-
@sink_class = StatsD::Instrument::
|
184
|
+
@sink_class = StatsD::Instrument::BatchedSink
|
184
185
|
@sinks = []
|
185
186
|
end
|
186
187
|
|
@@ -221,9 +222,9 @@ class BatchedUDPSinkTest < Minitest::Test
|
|
221
222
|
private
|
222
223
|
|
223
224
|
def build_sink(host = @host, port = @port, buffer_capacity: 50, statistics_interval: 0)
|
225
|
+
sink = StatsD::Instrument::Sink.for_addr("#{host}:#{port}")
|
224
226
|
sink = @sink_class.new(
|
225
|
-
|
226
|
-
port,
|
227
|
+
sink,
|
227
228
|
buffer_capacity: buffer_capacity,
|
228
229
|
statistics_interval: statistics_interval,
|
229
230
|
)
|
@@ -0,0 +1,187 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "test_helper"
|
4
|
+
|
5
|
+
module UdsTestHelper
|
6
|
+
MAX_READ_BYTES = 64 * 1024
|
7
|
+
private_constant :MAX_READ_BYTES
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def create_socket_file
|
12
|
+
tmpdir = Dir.mktmpdir
|
13
|
+
socket_path = File.join(tmpdir, "sockets", "statsd.sock")
|
14
|
+
FileUtils.mkdir_p(File.dirname(socket_path))
|
15
|
+
|
16
|
+
socket_path
|
17
|
+
end
|
18
|
+
|
19
|
+
def create_receiver(socket_path)
|
20
|
+
FileUtils.rm_f(socket_path)
|
21
|
+
receiver = Socket.new(Socket::AF_UNIX, Socket::SOCK_DGRAM)
|
22
|
+
receiver.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true)
|
23
|
+
receiver.setsockopt(Socket::SOL_SOCKET, Socket::SO_RCVBUF, (2 * MAX_READ_BYTES).to_i)
|
24
|
+
receiver.bind(Socket.pack_sockaddr_un(socket_path))
|
25
|
+
|
26
|
+
receiver
|
27
|
+
end
|
28
|
+
|
29
|
+
def build_sink(socket_path)
|
30
|
+
connection = StatsD::Instrument::UdsConnection.new(socket_path)
|
31
|
+
@sink_class.new(connection)
|
32
|
+
end
|
33
|
+
|
34
|
+
def sink
|
35
|
+
@sink ||= build_sink(@socket_path)
|
36
|
+
end
|
37
|
+
|
38
|
+
def skip_on_jruby(message = "JRuby does not support UNIX domain sockets")
|
39
|
+
skip(message) if RUBY_PLATFORM == "java"
|
40
|
+
end
|
41
|
+
|
42
|
+
def read_datagrams(count, timeout: ENV["CI"] ? 5 : 1)
|
43
|
+
datagrams = []
|
44
|
+
count.times do
|
45
|
+
if @receiver.wait_readable(timeout)
|
46
|
+
|
47
|
+
datagrams += @receiver.recvfrom(MAX_READ_BYTES).first.lines(chomp: true)
|
48
|
+
break if datagrams.size >= count
|
49
|
+
else
|
50
|
+
break
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
datagrams
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class UdsSinkTest < Minitest::Test
|
59
|
+
include UdsTestHelper
|
60
|
+
|
61
|
+
def setup
|
62
|
+
@sink_class = StatsD::Instrument::Sink
|
63
|
+
@socket_path = create_socket_file
|
64
|
+
skip_on_jruby
|
65
|
+
|
66
|
+
@receiver = create_receiver(@socket_path)
|
67
|
+
end
|
68
|
+
|
69
|
+
def teardown
|
70
|
+
return if RUBY_PLATFORM == "java"
|
71
|
+
|
72
|
+
@receiver.close
|
73
|
+
FileUtils.rm_f(@socket_path)
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_send_metric_with_tags
|
77
|
+
metric = "test.metric"
|
78
|
+
value = 42
|
79
|
+
tags = { region: "us-west", environment: "production" }
|
80
|
+
sink << "#{metric}:#{value}|c|##{"region:#{tags[:region]},environment:#{tags[:environment]}"}"
|
81
|
+
# Assert that the metric with tags was sent successfully
|
82
|
+
|
83
|
+
datagrams = read_datagrams(1)
|
84
|
+
assert_equal("test.metric:42|c|#region:us-west,environment:production".b, datagrams.first)
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_send_metric_with_sample_rate
|
88
|
+
metric = "test.metric"
|
89
|
+
value = 42
|
90
|
+
sample_rate = 0.5
|
91
|
+
sink << "#{metric}:#{value}|c|@#{sample_rate}"
|
92
|
+
datagrams = read_datagrams(1)
|
93
|
+
assert_equal("test.metric:42|c|@0.5".b, datagrams.first)
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_flush_with_empty_batch
|
97
|
+
sink.flush
|
98
|
+
datagrams = read_datagrams(1, timeout: 0.1)
|
99
|
+
assert_empty(datagrams)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
class BatchedUdsSinkTest < Minitest::Test
|
104
|
+
include UdsTestHelper
|
105
|
+
|
106
|
+
def setup
|
107
|
+
@socket_path = create_socket_file
|
108
|
+
@sink_class = StatsD::Instrument::BatchedSink
|
109
|
+
@sinks = []
|
110
|
+
|
111
|
+
skip_on_jruby
|
112
|
+
|
113
|
+
@receiver = create_receiver(@socket_path)
|
114
|
+
end
|
115
|
+
|
116
|
+
def teardown
|
117
|
+
return if RUBY_PLATFORM == "java"
|
118
|
+
|
119
|
+
@receiver.close
|
120
|
+
FileUtils.remove_entry(@socket_path)
|
121
|
+
@sinks.each(&:shutdown)
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_send_metric_with_tags
|
125
|
+
metric = "test.metric"
|
126
|
+
value = 42
|
127
|
+
tags = { region: "us-west", environment: "production" }
|
128
|
+
sink << "#{metric}:#{value}|c|##{"region:#{tags[:region]},environment:#{tags[:environment]}"}"
|
129
|
+
datagrams = read_datagrams(1)
|
130
|
+
assert_equal("test.metric:42|c|#region:us-west,environment:production".b, datagrams.first)
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_send_metric_with_sample_rate
|
134
|
+
metric = "test.metric"
|
135
|
+
value = 42
|
136
|
+
sample_rate = 0.5
|
137
|
+
sink << "#{metric}:#{value}|c|@#{sample_rate}"
|
138
|
+
datagrams = read_datagrams(1)
|
139
|
+
assert_equal("test.metric:42|c|@0.5".b, datagrams.first)
|
140
|
+
end
|
141
|
+
|
142
|
+
def test_flush_with_empty_batch
|
143
|
+
sink.flush(blocking: false)
|
144
|
+
datagrams = read_datagrams(1, timeout: 0.1)
|
145
|
+
assert_empty(datagrams)
|
146
|
+
end
|
147
|
+
|
148
|
+
def test_flush
|
149
|
+
buffer_size = 50
|
150
|
+
sink = build_sink(@socket_path, buffer_capacity: buffer_size)
|
151
|
+
dispatcher = sink.instance_variable_get(:@dispatcher)
|
152
|
+
buffer = dispatcher.instance_variable_get(:@buffer)
|
153
|
+
(buffer_size * 2).times { |i| sink << "foo:#{i}|c" }
|
154
|
+
assert(!buffer.empty?)
|
155
|
+
sink.flush(blocking: false)
|
156
|
+
assert(buffer.empty?)
|
157
|
+
end
|
158
|
+
|
159
|
+
def test_statistics
|
160
|
+
datagrams = StatsD.singleton_client.capture do
|
161
|
+
buffer_size = 2
|
162
|
+
sink = build_sink(@socket_path, buffer_capacity: buffer_size, statistics_interval: 0.1)
|
163
|
+
2.times { |i| sink << "foo:#{i}|c" }
|
164
|
+
sink.flush(blocking: false)
|
165
|
+
sink.instance_variable_get(:@dispatcher).instance_variable_get(:@statistics).maybe_flush!(force: true)
|
166
|
+
end
|
167
|
+
|
168
|
+
assert(datagrams.any? { |d| d.name.start_with?("statsd_instrument.batched_uds_sink.avg_batch_length") })
|
169
|
+
assert(datagrams.any? { |d| d.name.start_with?("statsd_instrument.batched_uds_sink.avg_batched_packet_size") })
|
170
|
+
assert(datagrams.any? { |d| d.name.start_with?("statsd_instrument.batched_uds_sink.avg_buffer_length") })
|
171
|
+
assert(datagrams.any? { |d| d.name.start_with?("statsd_instrument.batched_uds_sink.batched_sends") })
|
172
|
+
assert(datagrams.any? { |d| d.name.start_with?("statsd_instrument.batched_uds_sink.synchronous_sends") })
|
173
|
+
end
|
174
|
+
|
175
|
+
private
|
176
|
+
|
177
|
+
def build_sink(socket_path, buffer_capacity: 50, statistics_interval: 0)
|
178
|
+
sink = StatsD::Instrument::Sink.for_addr(socket_path)
|
179
|
+
sink = @sink_class.new(
|
180
|
+
sink,
|
181
|
+
buffer_capacity: buffer_capacity,
|
182
|
+
statistics_interval: statistics_interval,
|
183
|
+
)
|
184
|
+
@sinks << sink
|
185
|
+
sink
|
186
|
+
end
|
187
|
+
end
|
metadata
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: statsd-instrument
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jesse Storimer
|
8
8
|
- Tobias Lutke
|
9
9
|
- Willem van Bergen
|
10
|
-
autorequire:
|
10
|
+
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2024-
|
13
|
+
date: 2024-08-19 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.
|
@@ -21,6 +21,7 @@ extensions: []
|
|
21
21
|
extra_rdoc_files: []
|
22
22
|
files:
|
23
23
|
- ".github/CODEOWNERS"
|
24
|
+
- ".github/pull_request_template.md"
|
24
25
|
- ".github/workflows/benchmark.yml"
|
25
26
|
- ".github/workflows/cla.yml"
|
26
27
|
- ".github/workflows/lint.yml"
|
@@ -43,8 +44,9 @@ files:
|
|
43
44
|
- bin/rubocop
|
44
45
|
- lib/statsd-instrument.rb
|
45
46
|
- lib/statsd/instrument.rb
|
47
|
+
- lib/statsd/instrument/aggregator.rb
|
46
48
|
- lib/statsd/instrument/assertions.rb
|
47
|
-
- lib/statsd/instrument/
|
49
|
+
- lib/statsd/instrument/batched_sink.rb
|
48
50
|
- lib/statsd/instrument/capture_sink.rb
|
49
51
|
- lib/statsd/instrument/client.rb
|
50
52
|
- lib/statsd/instrument/datagram.rb
|
@@ -67,12 +69,15 @@ files:
|
|
67
69
|
- lib/statsd/instrument/rubocop/positional_arguments.rb
|
68
70
|
- lib/statsd/instrument/rubocop/singleton_configuration.rb
|
69
71
|
- lib/statsd/instrument/rubocop/splat_arguments.rb
|
72
|
+
- lib/statsd/instrument/sink.rb
|
70
73
|
- lib/statsd/instrument/statsd_datagram_builder.rb
|
71
74
|
- lib/statsd/instrument/strict.rb
|
72
|
-
- lib/statsd/instrument/
|
75
|
+
- lib/statsd/instrument/udp_connection.rb
|
76
|
+
- lib/statsd/instrument/uds_connection.rb
|
73
77
|
- lib/statsd/instrument/version.rb
|
74
78
|
- shipit.rubygems.yml
|
75
79
|
- statsd-instrument.gemspec
|
80
|
+
- test/aggregator_test.rb
|
76
81
|
- test/assertions_test.rb
|
77
82
|
- test/benchmark/clock_gettime.rb
|
78
83
|
- test/benchmark/metrics.rb
|
@@ -104,12 +109,13 @@ files:
|
|
104
109
|
- test/statsd_test.rb
|
105
110
|
- test/test_helper.rb
|
106
111
|
- test/udp_sink_test.rb
|
112
|
+
- test/uds_sink_test.rb
|
107
113
|
homepage: https://github.com/Shopify/statsd-instrument
|
108
114
|
licenses:
|
109
115
|
- MIT
|
110
116
|
metadata:
|
111
117
|
allowed_push_host: https://rubygems.org
|
112
|
-
post_install_message:
|
118
|
+
post_install_message:
|
113
119
|
rdoc_options: []
|
114
120
|
require_paths:
|
115
121
|
- lib
|
@@ -124,11 +130,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
124
130
|
- !ruby/object:Gem::Version
|
125
131
|
version: '0'
|
126
132
|
requirements: []
|
127
|
-
rubygems_version: 3.5.
|
128
|
-
signing_key:
|
133
|
+
rubygems_version: 3.5.17
|
134
|
+
signing_key:
|
129
135
|
specification_version: 4
|
130
136
|
summary: A StatsD client for Ruby apps
|
131
137
|
test_files:
|
138
|
+
- test/aggregator_test.rb
|
132
139
|
- test/assertions_test.rb
|
133
140
|
- test/benchmark/clock_gettime.rb
|
134
141
|
- test/benchmark/metrics.rb
|
@@ -160,3 +167,4 @@ test_files:
|
|
160
167
|
- test/statsd_test.rb
|
161
168
|
- test/test_helper.rb
|
162
169
|
- test/udp_sink_test.rb
|
170
|
+
- test/uds_sink_test.rb
|