dogstatsd-ruby 5.3.0 → 5.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +12 -6
- data/lib/datadog/statsd/connection.rb +1 -0
- data/lib/datadog/statsd/udp_connection.rb +5 -1
- data/lib/datadog/statsd/uds_connection.rb +5 -1
- data/lib/datadog/statsd/version.rb +1 -1
- metadata +13 -11
- data/lib/datadog/statsd/threaded_sender.rb +0 -132
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cfde2027b6fb73eee85ed0c612db51df707c2b01bec2266a3f2049acc34990f1
|
4
|
+
data.tar.gz: 5b1bb3263af1cbdde2bb84cf4d92f2e84ad7e0a0b3eaa5ad67f048750c062c46
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2b563e322f2eaff18eeb07f786d6277290c032e94859d89d856a7bc2512a278424ab5ec9f94f8bf477a222e9ef00075ad2e0293b29dbb0021a5b6551f836b3c9
|
7
|
+
data.tar.gz: 787b04cc62a139289784a9b1992a152ca74fafa3d97afa68944dea95121ff6d3af80164b551b5430d50b263f0d0c8f702d22c1450faaaebdbc4bc69f09c331fe
|
data/README.md
CHANGED
@@ -46,14 +46,14 @@ change concerning you is the new [threading model](#threading-model):
|
|
46
46
|
|
47
47
|
In practice, it means two things:
|
48
48
|
|
49
|
-
1. Now that the client is buffering metrics before sending them, you have to call `Datadog::Statsd#flush(sync: true)` if you want synchronous behavior. In most cases, this is not needed, as the
|
49
|
+
1. Now that the client is buffering metrics before sending them, you have to call `Datadog::Statsd#flush(sync: true)` if you want synchronous behavior. In most cases, this is not needed, as the sender thread will automatically flush the buffered metrics if the buffer gets full or when you are closing the instance.
|
50
50
|
|
51
51
|
2. You have to make sure you are either:
|
52
52
|
|
53
53
|
* Using a singleton instance of the DogStatsD client instead of creating a new instance whenever you need one; this will let the buffering mechanism flush metrics regularly
|
54
54
|
* Or properly disposing of the DogStatsD client instance when it is not needed anymore using the method `Datadog::Statsd#close`
|
55
55
|
|
56
|
-
If you have issues with the
|
56
|
+
If you have issues with the sender thread or the buffering mode, you can instantiate a client that behaves exactly as in v4.x (i.e. no sender thread and flush on every metric submission):
|
57
57
|
|
58
58
|
```ruby
|
59
59
|
# Create a DogStatsD client instance using UDP
|
@@ -73,9 +73,9 @@ statsd.close()
|
|
73
73
|
|
74
74
|
### v5.x Common Pitfalls
|
75
75
|
|
76
|
-
Version v5.x of `dogstatsd-ruby` is using a
|
76
|
+
Version v5.x of `dogstatsd-ruby` is using a sender thread for flushing. This provides better performance, but you need to consider the following pitfalls:
|
77
77
|
|
78
|
-
1. Applications that use `fork` after having created the dogstatsd instance: the child process will automatically spawn a new
|
78
|
+
1. Applications that use `fork` after having created the dogstatsd instance: the child process will automatically spawn a new sender thread to flush metrics.
|
79
79
|
|
80
80
|
2. Applications that create multiple instances of the client without closing them: it is important to `#close` all instances to free the thread and the socket they are using otherwise you will leak those resources.
|
81
81
|
|
@@ -83,7 +83,7 @@ If you are using [Sidekiq](https://github.com/mperham/sidekiq), please make sure
|
|
83
83
|
|
84
84
|
If you are using [Puma](https://github.com/puma/puma) or [Unicorn](https://yhbt.net/unicorn.git), please make sure to create the instance of DogStatsD in the workers, not in the main process before it forks to create its workers. See [this comment for more details](https://github.com/DataDog/dogstatsd-ruby/issues/179#issuecomment-845570345).
|
85
85
|
|
86
|
-
Applications that run into issues but can't apply these recommendations should use the `single_thread` mode which disables the use of the
|
86
|
+
Applications that run into issues but can't apply these recommendations should use the `single_thread` mode which disables the use of the sender thread.
|
87
87
|
Here is how to instantiate a client in this mode:
|
88
88
|
|
89
89
|
```ruby
|
@@ -152,7 +152,7 @@ statsd.close()
|
|
152
152
|
|
153
153
|
Starting with version 5.0, `dogstatsd-ruby` employs a new threading model where one instance of `Datadog::Statsd` can be shared between threads and where data sending is non-blocking (asynchronous).
|
154
154
|
|
155
|
-
When you instantiate a `Datadog::Statsd`, a
|
155
|
+
When you instantiate a `Datadog::Statsd`, a sender thread is spawned. This thread will be called the Sender thread, as it is modeled by the [Sender](../lib/datadog/statsd/sender.rb) class. You can make use of `single_thread: true` to disable this behavior.
|
156
156
|
|
157
157
|
This thread is stopped when you close the statsd client (`Datadog::Statsd#close`). Instantiating a lot of statsd clients without calling `#close` after they are not needed anymore will most likely lead to threads being leaked.
|
158
158
|
|
@@ -196,6 +196,12 @@ Doing so means the caller thread is blocked and waiting until the data has been
|
|
196
196
|
|
197
197
|
This is useful when preparing to exit the application or when checking unit tests.
|
198
198
|
|
199
|
+
### Thread-safety
|
200
|
+
|
201
|
+
By default, instances of `Datadog::Statsd` are thread-safe and we recommend that a single instance be reused by all application threads (even in applications that employ forking). The sole exception is the `#close` method — this method is not yet thread safe (work in progress here [#209](https://github.com/DataDog/dogstatsd-ruby/pull/209)).
|
202
|
+
|
203
|
+
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.
|
204
|
+
|
199
205
|
## Versioning
|
200
206
|
|
201
207
|
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. As much as possible, we will add a "future deprecation" message in the minor release preceding the one dropping the support.
|
@@ -20,7 +20,6 @@ module Datadog
|
|
20
20
|
@host = host || ENV.fetch('DD_AGENT_HOST', DEFAULT_HOST)
|
21
21
|
@port = port || ENV.fetch('DD_DOGSTATSD_PORT', DEFAULT_PORT).to_i
|
22
22
|
@socket = nil
|
23
|
-
connect
|
24
23
|
end
|
25
24
|
|
26
25
|
def close
|
@@ -37,7 +36,12 @@ module Datadog
|
|
37
36
|
@socket.connect(host, port)
|
38
37
|
end
|
39
38
|
|
39
|
+
# send_message is writing the message in the socket, it may create the socket if nil
|
40
|
+
# It is not thread-safe but since it is called by either the Sender bg thread or the
|
41
|
+
# SingleThreadSender (which is using a mutex while Flushing), only one thread must call
|
42
|
+
# it at a time.
|
40
43
|
def send_message(message)
|
44
|
+
connect unless @socket
|
41
45
|
@socket.send(message, 0)
|
42
46
|
end
|
43
47
|
end
|
@@ -15,7 +15,6 @@ module Datadog
|
|
15
15
|
|
16
16
|
@socket_path = socket_path
|
17
17
|
@socket = nil
|
18
|
-
connect
|
19
18
|
end
|
20
19
|
|
21
20
|
def close
|
@@ -32,7 +31,12 @@ module Datadog
|
|
32
31
|
@socket.connect(Socket.pack_sockaddr_un(@socket_path))
|
33
32
|
end
|
34
33
|
|
34
|
+
# send_message is writing the message in the socket, it may create the socket if nil
|
35
|
+
# It is not thread-safe but since it is called by either the Sender bg thread or the
|
36
|
+
# SingleThreadSender (which is using a mutex while Flushing), only one thread must call
|
37
|
+
# it at a time.
|
35
38
|
def send_message(message)
|
39
|
+
connect unless @socket
|
36
40
|
@socket.sendmsg_nonblock(message)
|
37
41
|
rescue Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::ENOENT => e
|
38
42
|
# TODO: FIXME: This error should be considered as a retryable error in the
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dogstatsd-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.3.
|
4
|
+
version: 5.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rein Henrichs
|
8
8
|
- Karim Bogtob
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2021-
|
12
|
+
date: 2021-11-03 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: A Ruby DogStatsd client
|
15
15
|
email: code@datadoghq.com
|
@@ -34,7 +34,6 @@ files:
|
|
34
34
|
- lib/datadog/statsd/serialization/tag_serializer.rb
|
35
35
|
- lib/datadog/statsd/single_thread_sender.rb
|
36
36
|
- lib/datadog/statsd/telemetry.rb
|
37
|
-
- lib/datadog/statsd/threaded_sender.rb
|
38
37
|
- lib/datadog/statsd/udp_connection.rb
|
39
38
|
- lib/datadog/statsd/uds_connection.rb
|
40
39
|
- lib/datadog/statsd/version.rb
|
@@ -43,10 +42,14 @@ licenses:
|
|
43
42
|
- MIT
|
44
43
|
metadata:
|
45
44
|
bug_tracker_uri: https://github.com/DataDog/dogstatsd-ruby/issues
|
46
|
-
changelog_uri: https://github.com/DataDog/dogstatsd-ruby/blob/v5.3.
|
47
|
-
documentation_uri: https://www.rubydoc.info/gems/dogstatsd-ruby/5.3.
|
48
|
-
source_code_uri: https://github.com/DataDog/dogstatsd-ruby/tree/v5.3.
|
49
|
-
post_install_message:
|
45
|
+
changelog_uri: https://github.com/DataDog/dogstatsd-ruby/blob/v5.3.2/CHANGELOG.md
|
46
|
+
documentation_uri: https://www.rubydoc.info/gems/dogstatsd-ruby/5.3.2
|
47
|
+
source_code_uri: https://github.com/DataDog/dogstatsd-ruby/tree/v5.3.2
|
48
|
+
post_install_message: |2+
|
49
|
+
|
50
|
+
If you are upgrading from v4.x of the dogstatsd-ruby library, note the major change to the threading model:
|
51
|
+
https://github.com/DataDog/dogstatsd-ruby#migrating-from-v4x-to-v5x
|
52
|
+
|
50
53
|
rdoc_options: []
|
51
54
|
require_paths:
|
52
55
|
- lib
|
@@ -61,9 +64,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
61
64
|
- !ruby/object:Gem::Version
|
62
65
|
version: '0'
|
63
66
|
requirements: []
|
64
|
-
|
65
|
-
|
66
|
-
signing_key:
|
67
|
+
rubygems_version: 3.2.22
|
68
|
+
signing_key:
|
67
69
|
specification_version: 4
|
68
70
|
summary: A Ruby DogStatsd client
|
69
71
|
test_files: []
|
@@ -1,132 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Datadog
|
4
|
-
class FlushQueue < Queue
|
5
|
-
end
|
6
|
-
class CloseQueue < Queue
|
7
|
-
end
|
8
|
-
class Statsd
|
9
|
-
# Sender is using a background thread to flush and pack messages
|
10
|
-
# in a `MessageBuffer`.
|
11
|
-
# The communication with this thread is done using a `Queue`.
|
12
|
-
# If the thread is dead, it is starting a new one to avoid having a blocked
|
13
|
-
# Sender with no background thread to communicate with (most of the time,
|
14
|
-
# having a dead background thread means that a fork just happened and that we
|
15
|
-
# are running in the child process).
|
16
|
-
class Sender
|
17
|
-
CLOSEABLE_QUEUES = Queue.instance_methods.include?(:close)
|
18
|
-
|
19
|
-
def initialize(message_buffer, logger: nil)
|
20
|
-
@message_buffer = message_buffer
|
21
|
-
@logger = logger
|
22
|
-
|
23
|
-
# communication and synchronization with the background thread
|
24
|
-
# @mux is also used to not having multiple threads fighting for
|
25
|
-
# closing the Sender or creating a new background thread
|
26
|
-
@channel = Queue.new
|
27
|
-
@mux = Mutex.new
|
28
|
-
|
29
|
-
@is_closed = false
|
30
|
-
|
31
|
-
# start background thread immediately
|
32
|
-
@sender_thread = Thread.new(&method(:send_loop))
|
33
|
-
end
|
34
|
-
|
35
|
-
def flush(sync: false)
|
36
|
-
@mux.synchronize {
|
37
|
-
# we don't want to send a flush action to the bg thread if:
|
38
|
-
# - there is no bg thread running
|
39
|
-
# - the sender has been closed
|
40
|
-
return if !sender_thread.alive? || @is_closed
|
41
|
-
|
42
|
-
if sync
|
43
|
-
# blocking flush
|
44
|
-
blocking_queue = FlushQueue.new
|
45
|
-
channel << blocking_queue
|
46
|
-
blocking_queue.pop # wait for the bg thread to finish its work
|
47
|
-
blocking_queue.close if CLOSEABLE_QUEUES
|
48
|
-
else
|
49
|
-
# asynchronous flush
|
50
|
-
channel << :flush
|
51
|
-
end
|
52
|
-
}
|
53
|
-
end
|
54
|
-
|
55
|
-
def add(message)
|
56
|
-
return if @is_closed # don't send a message to the bg thread if the sender has been closed
|
57
|
-
|
58
|
-
# the bg thread is not running anymore, this is happening if the main process has forked and
|
59
|
-
# we are running in the child, we will spawn a bg thread and reset buffers (containing parents' messages)
|
60
|
-
if !sender_thread.alive?
|
61
|
-
@mux.synchronize {
|
62
|
-
return if @is_closed
|
63
|
-
# test if a call from another thread has already re-created
|
64
|
-
# the background thread before this one acquired the lock
|
65
|
-
break if sender_thread.alive?
|
66
|
-
|
67
|
-
# re-create the channel of communication since we will spawn a new bg thread
|
68
|
-
channel.close if CLOSEABLE_QUEUES
|
69
|
-
@channel = Queue.new
|
70
|
-
message_buffer.reset # don't use messages appended by another fork
|
71
|
-
@sender_thread = Thread.new(&method(:send_loop))
|
72
|
-
}
|
73
|
-
end
|
74
|
-
|
75
|
-
channel << message
|
76
|
-
end
|
77
|
-
|
78
|
-
# Compatibility with `Sender`
|
79
|
-
def start()
|
80
|
-
end
|
81
|
-
|
82
|
-
def stop()
|
83
|
-
return if @is_closed
|
84
|
-
# use this lock to both: not having another thread stopping this instance nor
|
85
|
-
# having a #add call creating a new thread
|
86
|
-
@mux.synchronize {
|
87
|
-
@is_closed = true
|
88
|
-
if sender_thread.alive? # no reasons to stop the bg thread is none is running already
|
89
|
-
blocking_queue = CloseQueue.new
|
90
|
-
channel << blocking_queue
|
91
|
-
blocking_queue.pop # wait for the bg thread to finish its work
|
92
|
-
blocking_queue.close if CLOSEABLE_QUEUES
|
93
|
-
sender_thread.join(3) # wait for completion, timeout after 3 seconds
|
94
|
-
# TODO(remy): should I close `channel` here?
|
95
|
-
end
|
96
|
-
}
|
97
|
-
end
|
98
|
-
|
99
|
-
private
|
100
|
-
|
101
|
-
attr_reader :message_buffer
|
102
|
-
attr_reader :channel
|
103
|
-
attr_reader :mux
|
104
|
-
attr_reader :sender_thread
|
105
|
-
|
106
|
-
def send_loop
|
107
|
-
until (message = channel.pop).nil? && (CLOSEABLE_QUEUES && channel.closed?)
|
108
|
-
# skip if message is nil, e.g. when the channel is empty and closed
|
109
|
-
next unless message
|
110
|
-
|
111
|
-
case message
|
112
|
-
# if a FlushQueue is received, the background thread has to flush the message
|
113
|
-
# buffer and to send an :unblock to let the caller know that it has finished
|
114
|
-
when FlushQueue
|
115
|
-
message_buffer.flush
|
116
|
-
message << :unblock
|
117
|
-
# if a :flush is received, the background thread has to flush asynchronously
|
118
|
-
when :flush
|
119
|
-
message_buffer.flush
|
120
|
-
# if a CloseQueue is received, the background thread has to do a last flush
|
121
|
-
# and to send an :unblock to let the caller know that it has finished
|
122
|
-
when CloseQueue
|
123
|
-
message << :unblock
|
124
|
-
return
|
125
|
-
else
|
126
|
-
message_buffer.add(message)
|
127
|
-
end
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|