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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 828679b3ff6ef3a2acce023e8b3cc5d362fe8c41ac17acee8bd2d5662ae3b2f3
4
- data.tar.gz: 0c836007b9b82eb7e0cf056f86d9426e8f43b1e1543876c53819b8e0f46c8235
3
+ metadata.gz: cfde2027b6fb73eee85ed0c612db51df707c2b01bec2266a3f2049acc34990f1
4
+ data.tar.gz: 5b1bb3263af1cbdde2bb84cf4d92f2e84ad7e0a0b3eaa5ad67f048750c062c46
5
5
  SHA512:
6
- metadata.gz: dc31df8c212fa4ab0854075528a03729d8600fabbc2e387ec4bf4c3c712a5106600c68065d5204d082f3d9fbaeafa74c8dc6cee15c8dea03fe7de192bcfb654e
7
- data.tar.gz: 552b383c99f0071662d83991dc5e3472b0cc73125ef9fa3c558de1a59b8bf48fed3dc0d7b96e62808cf0bb044e65c4e332e569e7c9add6dcaf72a0300bfb4ca3
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 companion thread will automatically flush the buffered metrics if the buffer gets full or when you are closing the instance.
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 companion thread or the buffering mode, you can instantiate a client that behaves exactly as in v4.x (i.e. no companion thread and flush on every metric submission):
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 companion thread for flushing. This provides better performance, but you need to consider the following pitfalls:
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 companion thread to flush metrics.
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 companion thread.
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 companion 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.
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.
@@ -12,6 +12,7 @@ module Datadog
12
12
  telemetry.reset
13
13
  end
14
14
 
15
+ # not thread safe: `Sender` instances that use this are required to properly synchronize or sequence calls to this method
15
16
  def write(payload)
16
17
  logger.debug { "Statsd: #{payload}" } if logger
17
18
 
@@ -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
@@ -4,6 +4,6 @@ require_relative 'connection'
4
4
 
5
5
  module Datadog
6
6
  class Statsd
7
- VERSION = '5.3.0'
7
+ VERSION = '5.3.2'
8
8
  end
9
9
  end
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.0
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-10-06 00:00:00.000000000 Z
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.0/CHANGELOG.md
47
- documentation_uri: https://www.rubydoc.info/gems/dogstatsd-ruby/5.3.0
48
- source_code_uri: https://github.com/DataDog/dogstatsd-ruby/tree/v5.3.0
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
- rubyforge_project:
65
- rubygems_version: 2.7.10
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