dogstatsd-ruby 5.5.0 → 5.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +11 -1
- data/lib/datadog/statsd/connection.rb +1 -1
- data/lib/datadog/statsd/connection_cfg.rb +56 -7
- data/lib/datadog/statsd/forwarder.rb +7 -2
- data/lib/datadog/statsd/message_buffer.rb +9 -1
- data/lib/datadog/statsd/sender.rb +4 -1
- data/lib/datadog/statsd/single_thread_sender.rb +16 -2
- data/lib/datadog/statsd/version.rb +1 -1
- data/lib/datadog/statsd.rb +11 -2
- metadata +6 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 20363c18876c0641ab23a8cee8d28c22de3e4210420e398d639d6a7b384da168
|
4
|
+
data.tar.gz: 851d63e75192dd81451f7a94abba7efe5c81e9c4afdc2dce8102a76e44a10d9a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 72f565700a7ddf32ca56a686617e840c53ad167770be812a66ad6af5d1641c96f89796fe147c1565c38c7d83be14fc638e0f8ce76a00e62e980f43a510826d18
|
7
|
+
data.tar.gz: 659bbd4b5b669a11bf62f723387d0263d76a243bda5c6b5de101700b20ad2991d6fd6535832857acdd15b0f809faff80cb1e9f459e1ddacb3262a6be27c4785f
|
data/README.md
CHANGED
@@ -183,7 +183,7 @@ There is also an implicit message which closes the queue which will cause the se
|
|
183
183
|
statsd = Datadog::Statsd.new('localhost', 8125)
|
184
184
|
```
|
185
185
|
|
186
|
-
The message queue's maximum size (in messages) is given by the `sender_queue_size` argument, and has appropriate defaults for UDP (2048)
|
186
|
+
The message queue's maximum size (in messages) is given by the `sender_queue_size` argument, and has appropriate defaults for UDP (2048), UDS (512) and `single_thread: true` (1).
|
187
187
|
|
188
188
|
The `buffer_flush_interval`, if enabled, is implemented with an additional thread which manages the timing of those flushes. This additional thread is used even if `single_thread: true`.
|
189
189
|
|
@@ -209,6 +209,16 @@ By default, instances of `Datadog::Statsd` are thread-safe and we recommend that
|
|
209
209
|
|
210
210
|
When using the `single_thread: true` mode, instances of `Datadog::Statsd` are still thread-safe, but you may run into contention on heavily-threaded applications, so we don’t recommend (for performance reasons) reusing these instances.
|
211
211
|
|
212
|
+
### Delaying serialization
|
213
|
+
|
214
|
+
By default, message serialization happens synchronously whenever stat methods such as `#increment` gets called, blocking the caller. If the blocking is impacting your program's performance, you may want to consider the `delay_serialization: true` mode.
|
215
|
+
|
216
|
+
The `delay_serialization: true` mode delays the serialization of metrics to avoid the wait when submitting metrics. Serialization will still have to happen at some point, but it might be postponed until a more convenient time, such as after an HTTP request has completed.
|
217
|
+
|
218
|
+
In `single_thread: true` mode, you'll probably want to set `sender_queue_size:` from it's default of `1` to some greater value, so that it can benefit from `delay_serialization: true`. Messages will then be queued unserialized in the sender queue and processed normally whenever `sender_queue_size` is reached or `#flush` is called. You might set `sender_queue_size: Float::INFINITY` to allow for an unbounded queue that will only be processed on explicit `#flush`.
|
219
|
+
|
220
|
+
In `single_thread: false` mode, `delay_serialization: true`, will cause serialization to happen inside the sender thread.
|
221
|
+
|
212
222
|
## Versioning
|
213
223
|
|
214
224
|
This Ruby gem is using [Semantic Versioning](https://guides.rubygems.org/patterns/#semantic-versioning) but please note that supported Ruby versions can change in a minor release of this library.
|
@@ -23,12 +23,25 @@ module Datadog
|
|
23
23
|
|
24
24
|
private
|
25
25
|
|
26
|
+
ERROR_MESSAGE = "Valid environment variables combination for connection configuration:\n" +
|
27
|
+
" - DD_DOGSTATSD_URL for UDP or UDS connection.\n" +
|
28
|
+
" Example for UDP: DD_DOGSTATSD_URL='udp://localhost:8125'\n" +
|
29
|
+
" Example for UDS: DD_DOGSTATSD_URL='unix:///path/to/unix.sock'\n" +
|
30
|
+
" or\n" +
|
31
|
+
" - DD_AGENT_HOST and DD_DOGSTATSD_PORT for an UDP connection. E.g. DD_AGENT_HOST='localhost' DD_DOGSTATSD_PORT=8125\n" +
|
32
|
+
" or\n" +
|
33
|
+
" - DD_DOGSTATSD_SOCKET for an UDS connection: E.g. DD_DOGSTATSD_SOCKET='/path/to/unix.sock'\n" +
|
34
|
+
" Note that DD_DOGSTATSD_URL has priority on other environment variables."
|
35
|
+
|
26
36
|
DEFAULT_HOST = '127.0.0.1'
|
27
37
|
DEFAULT_PORT = 8125
|
28
38
|
|
39
|
+
UDP_PREFIX = 'udp://'
|
40
|
+
UDS_PREFIX = 'unix://'
|
41
|
+
|
29
42
|
def initialize_with_constructor_args(host: nil, port: nil, socket_path: nil)
|
30
43
|
try_initialize_with(host: host, port: port, socket_path: socket_path,
|
31
|
-
|
44
|
+
error_message:
|
32
45
|
"Both UDP: (host/port #{host}:#{port}) and UDS (socket_path #{socket_path}) " +
|
33
46
|
"constructor arguments were given. Use only one or the other.",
|
34
47
|
)
|
@@ -36,13 +49,11 @@ module Datadog
|
|
36
49
|
|
37
50
|
def initialize_with_env_vars()
|
38
51
|
try_initialize_with(
|
52
|
+
dogstatsd_url: ENV['DD_DOGSTATSD_URL'],
|
39
53
|
host: ENV['DD_AGENT_HOST'],
|
40
54
|
port: ENV['DD_DOGSTATSD_PORT'] && ENV['DD_DOGSTATSD_PORT'].to_i,
|
41
55
|
socket_path: ENV['DD_DOGSTATSD_SOCKET'],
|
42
|
-
|
43
|
-
"Both UDP (DD_AGENT_HOST/DD_DOGSTATSD_PORT #{ENV['DD_AGENT_HOST']}:#{ENV['DD_DOGSTATSD_PORT']}) " +
|
44
|
-
"and UDS (DD_DOGSTATSD_SOCKET #{ENV['DD_DOGSTATSD_SOCKET']}) environment variables are set. " +
|
45
|
-
"Set only one or the other.",
|
56
|
+
error_message: ERROR_MESSAGE,
|
46
57
|
)
|
47
58
|
end
|
48
59
|
|
@@ -50,9 +61,13 @@ module Datadog
|
|
50
61
|
try_initialize_with(host: DEFAULT_HOST, port: DEFAULT_PORT)
|
51
62
|
end
|
52
63
|
|
53
|
-
def try_initialize_with(host: nil, port: nil, socket_path: nil,
|
64
|
+
def try_initialize_with(dogstatsd_url: nil, host: nil, port: nil, socket_path: nil, error_message: ERROR_MESSAGE)
|
54
65
|
if (host || port) && socket_path
|
55
|
-
raise ArgumentError,
|
66
|
+
raise ArgumentError, error_message
|
67
|
+
end
|
68
|
+
|
69
|
+
if dogstatsd_url
|
70
|
+
host, port, socket_path = parse_dogstatsd_url(str: dogstatsd_url.to_s)
|
56
71
|
end
|
57
72
|
|
58
73
|
if host || port
|
@@ -71,6 +86,40 @@ module Datadog
|
|
71
86
|
|
72
87
|
return false
|
73
88
|
end
|
89
|
+
|
90
|
+
def parse_dogstatsd_url(str:)
|
91
|
+
# udp socket connection
|
92
|
+
|
93
|
+
if str.start_with?(UDP_PREFIX)
|
94
|
+
dogstatsd_url = str[UDP_PREFIX.size..str.size]
|
95
|
+
host = nil
|
96
|
+
port = nil
|
97
|
+
|
98
|
+
if dogstatsd_url.include?(":")
|
99
|
+
parts = dogstatsd_url.split(":")
|
100
|
+
if parts.size > 2
|
101
|
+
raise ArgumentError, "Error: DD_DOGSTATSD_URL wrong format for an UDP connection. E.g. 'udp://localhost:8125'"
|
102
|
+
end
|
103
|
+
|
104
|
+
host = parts[0]
|
105
|
+
port = parts[1].to_i
|
106
|
+
else
|
107
|
+
host = dogstatsd_url
|
108
|
+
end
|
109
|
+
|
110
|
+
return host, port, nil
|
111
|
+
end
|
112
|
+
|
113
|
+
# unix socket connection
|
114
|
+
|
115
|
+
if str.start_with?(UDS_PREFIX)
|
116
|
+
return nil, nil, str[UDS_PREFIX.size..str.size]
|
117
|
+
end
|
118
|
+
|
119
|
+
# malformed value
|
120
|
+
|
121
|
+
raise ArgumentError, "Error: DD_DOGSTATSD_URL has been provided but is not starting with 'udp://' nor 'unix://'"
|
122
|
+
end
|
74
123
|
end
|
75
124
|
end
|
76
125
|
end
|
@@ -21,7 +21,9 @@ module Datadog
|
|
21
21
|
|
22
22
|
single_thread: false,
|
23
23
|
|
24
|
-
logger: nil
|
24
|
+
logger: nil,
|
25
|
+
|
26
|
+
serializer:
|
25
27
|
)
|
26
28
|
@transport_type = connection_cfg.transport_type
|
27
29
|
|
@@ -52,8 +54,10 @@ module Datadog
|
|
52
54
|
max_payload_size: buffer_max_payload_size,
|
53
55
|
max_pool_size: buffer_max_pool_size || DEFAULT_BUFFER_POOL_SIZE,
|
54
56
|
overflowing_stategy: buffer_overflowing_stategy,
|
57
|
+
serializer: serializer
|
55
58
|
)
|
56
59
|
|
60
|
+
sender_queue_size ||= 1 if single_thread
|
57
61
|
sender_queue_size ||= (@transport_type == :udp ?
|
58
62
|
UDP_DEFAULT_SENDER_QUEUE_SIZE : UDS_DEFAULT_SENDER_QUEUE_SIZE)
|
59
63
|
|
@@ -61,7 +65,8 @@ module Datadog
|
|
61
65
|
SingleThreadSender.new(
|
62
66
|
buffer,
|
63
67
|
logger: logger,
|
64
|
-
flush_interval: buffer_flush_interval
|
68
|
+
flush_interval: buffer_flush_interval,
|
69
|
+
queue_size: sender_queue_size) :
|
65
70
|
Sender.new(
|
66
71
|
buffer,
|
67
72
|
logger: logger,
|
@@ -8,7 +8,8 @@ module Datadog
|
|
8
8
|
def initialize(connection,
|
9
9
|
max_payload_size: nil,
|
10
10
|
max_pool_size: DEFAULT_BUFFER_POOL_SIZE,
|
11
|
-
overflowing_stategy: :drop
|
11
|
+
overflowing_stategy: :drop,
|
12
|
+
serializer:
|
12
13
|
)
|
13
14
|
raise ArgumentError, 'max_payload_size keyword argument must be provided' unless max_payload_size
|
14
15
|
raise ArgumentError, 'max_pool_size keyword argument must be provided' unless max_pool_size
|
@@ -17,12 +18,19 @@ module Datadog
|
|
17
18
|
@max_payload_size = max_payload_size
|
18
19
|
@max_pool_size = max_pool_size
|
19
20
|
@overflowing_stategy = overflowing_stategy
|
21
|
+
@serializer = serializer
|
20
22
|
|
21
23
|
@buffer = String.new
|
22
24
|
clear_buffer
|
23
25
|
end
|
24
26
|
|
25
27
|
def add(message)
|
28
|
+
# Serializes the message if it hasn't been already. Part of the
|
29
|
+
# delay_serialization feature.
|
30
|
+
if message.is_a?(Array)
|
31
|
+
message = @serializer.to_stat(*message[0], **message[1])
|
32
|
+
end
|
33
|
+
|
26
34
|
message_size = message.bytesize
|
27
35
|
|
28
36
|
return nil unless message_size > 0 # to avoid adding empty messages to the buffer
|
@@ -84,7 +84,10 @@ module Datadog
|
|
84
84
|
if message_queue.length <= @queue_size
|
85
85
|
message_queue << message
|
86
86
|
else
|
87
|
-
|
87
|
+
if @telemetry
|
88
|
+
bytesize = message.respond_to?(:bytesize) ? message.bytesize : 0
|
89
|
+
@telemetry.dropped_queue(packets: 1, bytes: bytesize)
|
90
|
+
end
|
88
91
|
end
|
89
92
|
end
|
90
93
|
|
@@ -7,10 +7,12 @@ module Datadog
|
|
7
7
|
# It is using current Process.PID to check it is the result of a recent fork
|
8
8
|
# and it is reseting the MessageBuffer if that's the case.
|
9
9
|
class SingleThreadSender
|
10
|
-
def initialize(message_buffer, logger: nil, flush_interval: nil)
|
10
|
+
def initialize(message_buffer, logger: nil, flush_interval: nil, queue_size: 1)
|
11
11
|
@message_buffer = message_buffer
|
12
12
|
@logger = logger
|
13
13
|
@mx = Mutex.new
|
14
|
+
@message_queue_size = queue_size
|
15
|
+
@message_queue = []
|
14
16
|
@flush_timer = if flush_interval
|
15
17
|
Datadog::Statsd::Timer.new(flush_interval) { flush }
|
16
18
|
else
|
@@ -26,15 +28,21 @@ module Datadog
|
|
26
28
|
# not send, they belong to the parent process, let's clear the buffer.
|
27
29
|
if forked?
|
28
30
|
@message_buffer.reset
|
31
|
+
@message_queue.clear
|
29
32
|
@flush_timer.start if @flush_timer && @flush_timer.stop?
|
30
33
|
update_fork_pid
|
31
34
|
end
|
32
|
-
|
35
|
+
|
36
|
+
@message_queue << message
|
37
|
+
if @message_queue.size >= @message_queue_size
|
38
|
+
drain_message_queue
|
39
|
+
end
|
33
40
|
}
|
34
41
|
end
|
35
42
|
|
36
43
|
def flush(*)
|
37
44
|
@mx.synchronize {
|
45
|
+
drain_message_queue
|
38
46
|
@message_buffer.flush()
|
39
47
|
}
|
40
48
|
end
|
@@ -53,6 +61,12 @@ module Datadog
|
|
53
61
|
|
54
62
|
private
|
55
63
|
|
64
|
+
def drain_message_queue
|
65
|
+
while msg = @message_queue.shift
|
66
|
+
@message_buffer.add(msg)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
56
70
|
# below are "fork management" methods to be able to clean the MessageBuffer
|
57
71
|
# if it detects that it is running in a unknown PID.
|
58
72
|
|
data/lib/datadog/statsd.rb
CHANGED
@@ -76,11 +76,12 @@ module Datadog
|
|
76
76
|
# @option [Logger] logger for debugging
|
77
77
|
# @option [Integer] buffer_max_payload_size max bytes to buffer
|
78
78
|
# @option [Integer] buffer_max_pool_size max messages to buffer
|
79
|
-
# @option [Integer] sender_queue_size size of the sender queue in number of buffers
|
79
|
+
# @option [Integer] sender_queue_size size of the sender queue in number of buffers
|
80
80
|
# @option [Numeric] buffer_flush_interval interval in second to flush buffer
|
81
81
|
# @option [String] socket_path unix socket path
|
82
82
|
# @option [Float] default sample rate if not overridden
|
83
83
|
# @option [Boolean] single_thread flushes the metrics on the main thread instead of in a companion thread
|
84
|
+
# @option [Boolean] delay_serialization delays stat serialization
|
84
85
|
def initialize(
|
85
86
|
host = nil,
|
86
87
|
port = nil,
|
@@ -100,6 +101,7 @@ module Datadog
|
|
100
101
|
logger: nil,
|
101
102
|
|
102
103
|
single_thread: false,
|
104
|
+
delay_serialization: false,
|
103
105
|
|
104
106
|
telemetry_enable: true,
|
105
107
|
telemetry_flush_interval: DEFAULT_TELEMETRY_FLUSH_INTERVAL
|
@@ -112,6 +114,7 @@ module Datadog
|
|
112
114
|
@prefix = @namespace ? "#{@namespace}.".freeze : nil
|
113
115
|
@serializer = Serialization::Serializer.new(prefix: @prefix, global_tags: tags)
|
114
116
|
@sample_rate = sample_rate
|
117
|
+
@delay_serialization = delay_serialization
|
115
118
|
|
116
119
|
@forwarder = Forwarder.new(
|
117
120
|
connection_cfg: ConnectionCfg.new(
|
@@ -133,6 +136,7 @@ module Datadog
|
|
133
136
|
sender_queue_size: sender_queue_size,
|
134
137
|
|
135
138
|
telemetry_flush_interval: telemetry_enable ? telemetry_flush_interval : nil,
|
139
|
+
serializer: serializer
|
136
140
|
)
|
137
141
|
end
|
138
142
|
|
@@ -425,7 +429,12 @@ module Datadog
|
|
425
429
|
sample_rate = opts[:sample_rate] || @sample_rate || 1
|
426
430
|
|
427
431
|
if sample_rate == 1 || opts[:pre_sampled] || rand <= sample_rate
|
428
|
-
full_stat =
|
432
|
+
full_stat =
|
433
|
+
if @delay_serialization
|
434
|
+
[[stat, delta, type], {tags: opts[:tags], sample_rate: sample_rate}]
|
435
|
+
else
|
436
|
+
serializer.to_stat(stat, delta, type, tags: opts[:tags], sample_rate: sample_rate)
|
437
|
+
end
|
429
438
|
|
430
439
|
forwarder.send_message(full_stat)
|
431
440
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dogstatsd-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rein Henrichs
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2023-07-10 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: A Ruby DogStatsd client
|
15
15
|
email: code@datadoghq.com
|
@@ -44,9 +44,9 @@ licenses:
|
|
44
44
|
- MIT
|
45
45
|
metadata:
|
46
46
|
bug_tracker_uri: https://github.com/DataDog/dogstatsd-ruby/issues
|
47
|
-
changelog_uri: https://github.com/DataDog/dogstatsd-ruby/blob/v5.
|
48
|
-
documentation_uri: https://www.rubydoc.info/gems/dogstatsd-ruby/5.
|
49
|
-
source_code_uri: https://github.com/DataDog/dogstatsd-ruby/tree/v5.
|
47
|
+
changelog_uri: https://github.com/DataDog/dogstatsd-ruby/blob/v5.6.0/CHANGELOG.md
|
48
|
+
documentation_uri: https://www.rubydoc.info/gems/dogstatsd-ruby/5.6.0
|
49
|
+
source_code_uri: https://github.com/DataDog/dogstatsd-ruby/tree/v5.6.0
|
50
50
|
post_install_message: |2+
|
51
51
|
|
52
52
|
If you are upgrading from v4.x of the dogstatsd-ruby library, note the major change to the threading model:
|
@@ -66,8 +66,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
66
66
|
- !ruby/object:Gem::Version
|
67
67
|
version: '0'
|
68
68
|
requirements: []
|
69
|
-
|
70
|
-
rubygems_version: 2.7.10
|
69
|
+
rubygems_version: 3.2.3
|
71
70
|
signing_key:
|
72
71
|
specification_version: 4
|
73
72
|
summary: A Ruby DogStatsd client
|