dogstatsd-ruby 4.0.0 → 4.3.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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +28 -4
  3. data/lib/datadog/statsd.rb +80 -45
  4. metadata +3 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6d2b1b9e7ec2a48c5305f6acda103d0b7a09787801dd899a38fb665f5389e4f3
4
- data.tar.gz: 3d974fffb4ace3bc248e69dcdaabb4c556e6783a25d65af98cb65bdccafc52ee
3
+ metadata.gz: b0a17784b24e078a39ee2717d1b7b25d1879e067a5e356db6f98eb012d2bbef2
4
+ data.tar.gz: 9559cb5d04e7b8dee34becbd0adb9182fb1cbda48ae5de13a470cd1d843d4d8d
5
5
  SHA512:
6
- metadata.gz: 16c82cb62bfd324d5e1dc1c6293fa121b92bd0c88d00474210c5da67f2cb07ae350cc0b717b15739c7a6f09e9021323ba348cec70ec2d0ac66a362f15f81007b
7
- data.tar.gz: 6e82cef56d746ecf7b10890d397e313c143611b18b4ae65db67eb2f252cb27acacb45de03f6447b7b4ebb1666209806d6b048fb2857c5c8790f1f6729f4ae806
6
+ metadata.gz: 652f8010045d42ae2fe2056d6c97f645d54c430b491a1e878cdf85abd22fda2dfbeae74022fb71faa51f5ce636c1bb6dcef60e172ba15c4b74fcd3eded1d9b05
7
+ data.tar.gz: 42f8763913be88f9871568ac966403f19437c4e477792a771b4b10d9645e2e73f6a588f89c4ba8bd218feb44842f1f6a491434eb0cdc64a2e0a47b30287da8f2
data/README.md CHANGED
@@ -28,9 +28,10 @@ statsd = Datadog::Statsd.new('localhost', 8125)
28
28
 
29
29
  # Increment a counter.
30
30
  statsd.increment('page.views')
31
+ statsd.increment('messages.count', by: 2, tags: ['kind:incoming'])
31
32
 
32
33
  # Record a gauge 50% of the time.
33
- statsd.gauge('users.online', 123, :sample_rate=>0.5)
34
+ statsd.gauge('users.online', 123, sample_rate: 0.5)
34
35
 
35
36
  # Sample a histogram
36
37
  statsd.histogram('file.upload.size', 1234)
@@ -48,7 +49,10 @@ statsd.batch do |s|
48
49
  end
49
50
 
50
51
  # Tag a metric.
51
- statsd.histogram('query.time', 10, :tags => ["version:1"])
52
+ statsd.histogram('query.time', 10, tags: ['version:1'])
53
+
54
+ # Tag a metric by passing in a Hash
55
+ statsd.histogram('query.time', 10, :tags => {version: 1})
52
56
 
53
57
  # Auto-close socket after end of block
54
58
  Datadog::Statsd.open('localhost', 8125) do |s|
@@ -62,14 +66,34 @@ Aggregation in the stream is made on hostname/event_type/source_type/aggregation
62
66
 
63
67
  ``` ruby
64
68
  # Post a simple message
65
- statsd.event("There might be a storm tomorrow", "A friend warned me earlier.")
69
+ statsd.event('There might be a storm tomorrow', 'A friend warned me earlier.')
66
70
 
67
71
  # Cry for help
68
- statsd.event("SO MUCH SNOW", "Started yesterday and it won't stop !!", :alert_type => "error", :tags => ["urgent", "endoftheworld"])
72
+ statsd.event(
73
+ 'SO MUCH SNOW',
74
+ "Started yesterday and it won't stop !!",
75
+ alert_type: 'error',
76
+ tags: ['urgent', 'endoftheworld']
77
+ )
69
78
  ```
70
79
 
71
80
 
72
81
 
82
+ Origin detection over UDP
83
+ -------------
84
+ Origin detection is a method to detect which pod DogStatsD packets are coming from in order to add the pod's tags to the tag list.
85
+
86
+ To enable origin detection over UDP, add the following lines to your application manifest
87
+ ```yaml
88
+ env:
89
+ - name: DD_ENTITY_ID
90
+ valueFrom:
91
+ fieldRef:
92
+ fieldPath: metadata.uid
93
+ ```
94
+ The DogStatsD client attaches an internal tag, `entity_id`. The value of this tag is the content of the `DD_ENTITY_ID` environment variable, which is the pod’s UID.
95
+
96
+
73
97
  Documentation
74
98
  -------------
75
99
 
@@ -33,35 +33,19 @@ module Datadog
33
33
  # DogStatsd unix socket path. Not used by default.
34
34
  attr_reader :socket_path
35
35
 
36
- def initialize(host, port, socket_path, logger)
37
- @host = host || DEFAULT_HOST
38
- @port = port || DEFAULT_PORT
39
- @socket_path = socket_path
40
- @logger = logger
36
+ # Close the underlying socket
37
+ def close
38
+ @socket && @socket.close
41
39
  end
42
40
 
43
41
  def write(message)
44
42
  @logger.debug { "Statsd: #{message}" } if @logger
45
- if @socket_path.nil?
46
- socket.send(message, 0)
47
- else
48
- socket.sendmsg_nonblock(message)
49
- end
43
+ send_message(message)
50
44
  rescue StandardError => boom
51
- # Give up on this socket if it looks like it is bad
52
- bad_socket = !@socket_path.nil? && (
53
- boom.is_a?(Errno::ECONNREFUSED) ||
54
- boom.is_a?(Errno::ECONNRESET) ||
55
- boom.is_a?(Errno::ENOENT)
56
- )
57
- if bad_socket
58
- @socket = nil
59
- return
60
- end
61
-
62
45
  # Try once to reconnect if the socket has been closed
63
46
  retries ||= 1
64
- if retries <= 1 && boom.is_a?(IOError) && boom.message =~ /closed stream/i
47
+ if retries <= 1 && boom.is_a?(Errno::ENOTCONN) or
48
+ retries <= 1 && boom.is_a?(IOError) && boom.message =~ /closed stream/i
65
49
  retries += 1
66
50
  begin
67
51
  @socket = connect
@@ -75,27 +59,55 @@ module Datadog
75
59
  nil
76
60
  end
77
61
 
78
- # Close the underlying socket
79
- def close
80
- @socket && @socket.close
81
- end
82
-
83
62
  private
84
63
 
85
64
  def socket
86
65
  @socket ||= connect
87
66
  end
67
+ end
68
+
69
+ class UDPConnection < Connection
70
+ def initialize(host, port, logger)
71
+ @host = host || ENV.fetch('DD_AGENT_HOST', nil) || DEFAULT_HOST
72
+ @port = port || ENV.fetch('DD_DOGSTATSD_PORT', nil) || DEFAULT_PORT
73
+ @logger = logger
74
+ end
75
+
76
+ private
88
77
 
89
78
  def connect
90
- if @socket_path.nil?
91
- socket = UDPSocket.new
92
- socket.connect(@host, @port)
93
- else
94
- socket = Socket.new(Socket::AF_UNIX, Socket::SOCK_DGRAM)
95
- socket.connect(Socket.pack_sockaddr_un(@socket_path))
96
- end
79
+ socket = UDPSocket.new
80
+ socket.connect(@host, @port)
97
81
  socket
98
82
  end
83
+
84
+ def send_message(message)
85
+ socket.send(message, 0)
86
+ end
87
+ end
88
+
89
+ class UDSConnection < Connection
90
+ class BadSocketError < StandardError; end
91
+
92
+ def initialize(socket_path, logger)
93
+ @socket_path = socket_path
94
+ @logger = logger
95
+ end
96
+
97
+ private
98
+
99
+ def connect
100
+ socket = Socket.new(Socket::AF_UNIX, Socket::SOCK_DGRAM)
101
+ socket.connect(Socket.pack_sockaddr_un(@socket_path))
102
+ socket
103
+ end
104
+
105
+ def send_message(message)
106
+ socket.sendmsg_nonblock(message)
107
+ rescue Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::ENOENT => e
108
+ @socket = nil
109
+ raise BadSocketError, "#{e.class}: #{e}"
110
+ end
99
111
  end
100
112
 
101
113
  class Batch
@@ -180,7 +192,7 @@ module Datadog
180
192
  DISTRIBUTION_TYPE = 'd'.freeze
181
193
  TIMING_TYPE = 'ms'.freeze
182
194
  SET_TYPE = 's'.freeze
183
- VERSION = "4.0.0".freeze
195
+ VERSION = "4.3.0".freeze
184
196
 
185
197
  # A namespace to prepend to all statsd calls. Defaults to no namespace.
186
198
  attr_reader :namespace
@@ -194,16 +206,20 @@ module Datadog
194
206
  # Maximum buffer size in bytes before it is flushed
195
207
  attr_reader :max_buffer_bytes
196
208
 
209
+ # Default sample rate
210
+ attr_reader :sample_rate
211
+
197
212
  # Connection
198
213
  attr_reader :connection
199
214
 
200
215
  # @param [String] host your statsd host
201
216
  # @param [Integer] port your statsd port
202
217
  # @option [String] namespace set a namespace to be prepended to every metric name
203
- # @option [Array<String>] tags tags to be added to every metric
204
- # @option [Loger] logger for debugging
218
+ # @option [Array<String>|Hash] tags tags to be added to every metric
219
+ # @option [Logger] logger for debugging
205
220
  # @option [Integer] max_buffer_bytes max bytes to buffer when using #batch
206
221
  # @option [String] socket_path unix socket path
222
+ # @option [Float] default sample rate if not overridden
207
223
  def initialize(
208
224
  host = nil,
209
225
  port = nil,
@@ -211,17 +227,31 @@ module Datadog
211
227
  tags: nil,
212
228
  max_buffer_bytes: 8192,
213
229
  socket_path: nil,
214
- logger: nil
230
+ logger: nil,
231
+ sample_rate: nil
215
232
  )
216
- @connection = Connection.new(host, port, socket_path, logger)
233
+ if socket_path.nil?
234
+ @connection = UDPConnection.new(host, port, logger)
235
+ else
236
+ @connection = UDSConnection.new(socket_path, logger)
237
+ end
217
238
  @logger = logger
218
239
 
219
240
  @namespace = namespace
220
241
  @prefix = @namespace ? "#{@namespace}.".freeze : nil
221
242
 
222
- raise ArgumentError, 'tags must be a Array<String>' unless tags.nil? or tags.is_a? Array
243
+ @sample_rate = sample_rate
244
+
245
+ unless tags.nil? or tags.is_a? Array or tags.is_a? Hash
246
+ raise ArgumentError, 'tags must be a Array<String> or a Hash'
247
+ end
248
+
249
+ tags = tag_hash_to_array(tags) if tags.is_a? Hash
223
250
  @tags = (tags || []).compact.map! {|tag| escape_tag_content(tag)}
224
251
 
252
+ # append the entity id to tags if DD_ENTITY_ID env var is not nil
253
+ @tags << 'dd.internal.entity_id:' + escape_tag_content(ENV.fetch('DD_ENTITY_ID', nil)) unless ENV.fetch('DD_ENTITY_ID', nil).nil?
254
+
225
255
  @batch = Batch.new @connection, max_buffer_bytes
226
256
  end
227
257
 
@@ -394,7 +424,7 @@ module Datadog
394
424
  # it will be grouped with other events that don't have an event type.
395
425
  #
396
426
  # @param [String] title Event title
397
- # @param [String] text Event text. Supports \n
427
+ # @param [String] text Event text. Supports newlines (+\n+)
398
428
  # @param [Hash] opts the additional data about the event
399
429
  # @option opts [Integer, nil] :date_happened (nil) Assign a timestamp to the event. Default is now when none
400
430
  # @option opts [String, nil] :hostname (nil) Assign a hostname to the event.
@@ -466,7 +496,7 @@ module Datadog
466
496
  def format_event(title, text, opts=EMPTY_OPTIONS)
467
497
  escaped_title = escape_event_content(title)
468
498
  escaped_text = escape_event_content(text)
469
- event_string_data = "_e{#{escaped_title.length},#{escaped_text.length}}:#{escaped_title}|#{escaped_text}".dup
499
+ event_string_data = "_e{#{escaped_title.bytesize},#{escaped_text.bytesize}}:#{escaped_title}|#{escaped_text}".dup
470
500
 
471
501
  # We construct the string to be sent by adding '|key:value' parts to it when needed
472
502
  # All pipes ('|') in the metadata are removed. Title and Text can keep theirs
@@ -482,12 +512,13 @@ module Datadog
482
512
  event_string_data << "|##{tags_string}"
483
513
  end
484
514
 
485
- raise "Event #{title} payload is too big (more that 8KB), event discarded" if event_string_data.length > MAX_EVENT_SIZE
515
+ raise "Event #{title} payload is too big (more that 8KB), event discarded" if event_string_data.bytesize > MAX_EVENT_SIZE
486
516
  event_string_data
487
517
  end
488
518
 
489
519
  def tags_as_string(opts)
490
520
  if tag_arr = opts[:tags]
521
+ tag_arr = tag_hash_to_array(tag_arr) if tag_arr.is_a? Hash
491
522
  tag_arr = tag_arr.map { |tag| escape_tag_content(tag) }
492
523
  tag_arr = tags + tag_arr # @tags are normalized when set, so not need to normalize them again
493
524
  else
@@ -496,6 +527,10 @@ module Datadog
496
527
  tag_arr.join(COMMA) unless tag_arr.empty?
497
528
  end
498
529
 
530
+ def tag_hash_to_array(tag_hash)
531
+ tag_hash.to_a.map {|pair| pair.compact.join(":")}
532
+ end
533
+
499
534
  def escape_event_content(msg)
500
535
  msg.gsub NEW_LINE, ESC_NEW_LINE
501
536
  end
@@ -515,8 +550,8 @@ module Datadog
515
550
  end
516
551
 
517
552
  def send_stats(stat, delta, type, opts=EMPTY_OPTIONS)
518
- sample_rate = opts[:sample_rate] || 1
519
- if sample_rate == 1 or rand < sample_rate
553
+ sample_rate = opts[:sample_rate] || @sample_rate || 1
554
+ if sample_rate == 1 or rand <= sample_rate
520
555
  full_stat = ''.dup
521
556
  full_stat << @prefix if @prefix
522
557
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dogstatsd-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.0
4
+ version: 4.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rein Henrichs
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-08-20 00:00:00.000000000 Z
11
+ date: 2019-06-24 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A Ruby DogStastd client
14
14
  email: code@datadoghq.com
@@ -41,7 +41,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
41
41
  version: '0'
42
42
  requirements: []
43
43
  rubyforge_project:
44
- rubygems_version: 2.7.7
44
+ rubygems_version: 2.7.6
45
45
  signing_key:
46
46
  specification_version: 4
47
47
  summary: A Ruby DogStatsd client