dogstatsd-ruby 4.1.0 → 4.6.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 +40 -63
  3. data/lib/datadog/statsd.rb +177 -64
  4. metadata +10 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fdab85fe0b81950fd3e672109edd29b4e9d9a4362e567ed9e9a14e2f95f46ec8
4
- data.tar.gz: 4b6040d520cc243cb045a970f7011d3cd878e2a6e8a9f7be2a496d1994c07214
3
+ metadata.gz: 7d521571f811d6206670773db4ac3808c02513d8761445ecf917f831578e2614
4
+ data.tar.gz: 97d68494f8520a777569dc8f7b3c04070152aa0924edabc67ffa0ae1f16cb615
5
5
  SHA512:
6
- metadata.gz: 1d73c1e3e5c9d7d27fc965f79137dee176ea7bc6d7a520e8a4658329bfbd780b9aadd71d636e4f9652d675f888cce1c24902ebb79c3af7aebb39b4b730bb0c7b
7
- data.tar.gz: 1f5ae46a3955844f74748e3fdacac487685efbfa2f270c178e9a2e99791cf00bce9e2200809276ca263f9d2dda1b606a593a4e33a44bb3c2cbfef2f33341f330
6
+ metadata.gz: f43fb9314373873b5d436824a3cae0a5dc0ef4fcc2a458b8a98b98dbd8b12cb28d3b32293436451829a53da8cb70f17c6104aa64403cfb6000822e59a74ca29a
7
+ data.tar.gz: a796456e38da22047d952b7a1bebaf1f923a0847c29a9e7548020c8b658144e729133e7e90a16453d0f48a815353734523870e2e391371d8699f1d6574bd8379
data/README.md CHANGED
@@ -1,95 +1,72 @@
1
+ # dogstatsd-ruby
1
2
 
2
- dogstatsd-ruby
3
- ==============
3
+ A client for DogStatsD, an extension of the StatsD metric server for Datadog. Full API documentation is available in [DogStatsD-ruby rubydoc](https://www.rubydoc.info/github/DataDog/dogstatsd-ruby/master/Datadog/Statsd).
4
4
 
5
- A client for DogStatsD, an extension of the StatsD metric server for Datadog.
5
+ [![Build Status](https://secure.travis-ci.org/DataDog/dogstatsd-ruby.svg)](http://travis-ci.org/DataDog/dogstatsd-ruby)
6
6
 
7
- [![Build Status](https://secure.travis-ci.org/DataDog/dogstatsd-ruby.png)](http://travis-ci.org/DataDog/dogstatsd-ruby)
7
+ See [CHANGELOG.md](CHANGELOG.md) for changes. To suggest a feature, report a bug, or general discussion, [open an issue](http://github.com/DataDog/dogstatsd-ruby/issues/).
8
8
 
9
- Quick Start Guide
10
- -----------------
9
+ ## Installation
11
10
 
12
11
  First install the library:
13
12
 
14
- gem install dogstatsd-ruby
13
+ ```
14
+ gem install dogstatsd-ruby
15
+ ```
16
+
17
+ ## Configuration
15
18
 
16
- Then start instrumenting your code:
19
+ To instantiate a DogStatsd client:
17
20
 
18
- ``` ruby
19
- # Load the dogstats module.
21
+ ```ruby
22
+ # Import the library
20
23
  require 'datadog/statsd'
21
24
 
22
- # Create a stats instance.
25
+ # Create a DogStatsD client instance.
23
26
  statsd = Datadog::Statsd.new('localhost', 8125)
24
-
25
- # you could also create a statsd class if you need a drop in replacement
26
- # class Statsd < Datadog::Statsd
27
- # end
28
-
29
- # Increment a counter.
30
- statsd.increment('page.views')
31
-
32
- # Record a gauge 50% of the time.
33
- statsd.gauge('users.online', 123, :sample_rate=>0.5)
34
-
35
- # Sample a histogram
36
- statsd.histogram('file.upload.size', 1234)
37
-
38
- # Time a block of code
39
- statsd.time('page.render') do
40
- render_page('home.html')
41
- end
42
-
43
- # Send several metrics at the same time
44
- # All metrics will be buffered and sent in one packet when the block completes
45
- statsd.batch do |s|
46
- s.increment('page.views')
47
- s.gauge('users.online', 123)
48
- end
49
-
50
- # Tag a metric.
51
- statsd.histogram('query.time', 10, :tags => ["version:1"])
52
-
53
- # Auto-close socket after end of block
54
- Datadog::Statsd.open('localhost', 8125) do |s|
55
- s.increment('page.views')
56
- end
57
27
  ```
58
28
 
59
- You can also post events to your stream. You can tag them, set priority and even aggregate them with other events.
29
+ Find a list of all the available options for your DogStatsD Client in the [DogStatsD-ruby rubydoc](https://www.rubydoc.info/github/DataDog/dogstatsd-ruby/master/Datadog/Statsd) or in the [Datadog public DogStatsD documentation](https://docs.datadoghq.com/developers/dogstatsd/?tab=go#client-instantiation-parameters).
60
30
 
61
- Aggregation in the stream is made on hostname/event_type/source_type/aggregation_key.
31
+ ### Origin detection over UDP
62
32
 
63
- ``` ruby
64
- # Post a simple message
65
- statsd.event("There might be a storm tomorrow", "A friend warned me earlier.")
33
+ 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.
66
34
 
67
- # Cry for help
68
- statsd.event("SO MUCH SNOW", "Started yesterday and it won't stop !!", :alert_type => "error", :tags => ["urgent", "endoftheworld"])
35
+ To enable origin detection over UDP, add the following lines to your application manifest
36
+ ```yaml
37
+ env:
38
+ - name: DD_ENTITY_ID
39
+ valueFrom:
40
+ fieldRef:
41
+ fieldPath: metadata.uid
69
42
  ```
43
+ 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.
70
44
 
45
+ ## Usage
71
46
 
47
+ In order to use DogStatsD metrics, events, and Service Checks the Agent must be [running and available](https://docs.datadoghq.com/developers/dogstatsd/?tab=ruby).
72
48
 
73
- Documentation
74
- -------------
49
+ ### Metrics
75
50
 
76
- Full API documentation is available
77
- [here](http://www.rubydoc.info/github/DataDog/dogstatsd-ruby/master/frames).
51
+ After the client is created, you can start sending custom metrics to Datadog. See the dedicated [Metric Submission: DogStatsD documentation](https://docs.datadoghq.com/developers/metrics/dogstatsd_metrics_submission/?tab=ruby) to see how to submit all supported metric types to Datadog with working code examples:
78
52
 
53
+ * [Submit a COUNT metric](https://docs.datadoghq.com/developers/metrics/dogstatsd_metrics_submission/?tab=ruby#count).
54
+ * [Submit a GAUGE metric](https://docs.datadoghq.com/developers/metrics/dogstatsd_metrics_submission/?tab=ruby#gauge).
55
+ * [Submit a SET metric](https://docs.datadoghq.com/developers/metrics/dogstatsd_metrics_submission/?tab=ruby#set)
56
+ * [Submit a HISTOGRAM metric](https://docs.datadoghq.com/developers/metrics/dogstatsd_metrics_submission/?tab=ruby#histogram)
57
+ * [Submit a DISTRIBUTION metric](https://docs.datadoghq.com/developers/metrics/dogstatsd_metrics_submission/?tab=ruby#distribution)
79
58
 
80
- Feedback
81
- --------
59
+ Some options are suppported when submitting metrics, like [applying a Sample Rate to your metrics](https://docs.datadoghq.com/developers/metrics/dogstatsd_metrics_submission/?tab=ruby#metric-submission-options) or [tagging your metrics with your custom tags](https://docs.datadoghq.com/developers/metrics/dogstatsd_metrics_submission/?tab=ruby#metric-tagging). Find all the available functions to report metrics in the [DogStatsD-ruby rubydoc](https://www.rubydoc.info/github/DataDog/dogstatsd-ruby/master/Datadog/Statsd).
82
60
 
83
- To suggest a feature, report a bug, or general discussion, head over
84
- [here](http://github.com/DataDog/dogstatsd-ruby/issues/).
61
+ ### Events
85
62
 
63
+ After the client is created, you can start sending events to your Datadog Event Stream. See the dedicated [Event Submission: DogStatsD documentation](https://docs.datadoghq.com/developers/events/dogstatsd/?tab=ruby) to see how to submit an event to Datadog your Event Stream.
86
64
 
87
- [Change Log](CHANGELOG.md)
88
- ----------------------------
65
+ ### Service Checks
89
66
 
67
+ After the client is created, you can start sending Service Checks to Datadog. See the dedicated [Service Check Submission: DogStatsD documentation](https://docs.datadoghq.com/developers/service_checks/dogstatsd_service_checks_submission/?tab=ruby) to see how to submit a Service Check to Datadog.
90
68
 
91
- Credits
92
- -------
69
+ ## Credits
93
70
 
94
71
  dogstatsd-ruby is forked from Rien Henrichs [original Statsd
95
72
  client](https://github.com/reinh/statsd).
@@ -20,6 +20,56 @@ require 'socket'
20
20
  module Datadog
21
21
  class Statsd
22
22
 
23
+ class Telemetry
24
+ attr_accessor :metrics
25
+ attr_accessor :events
26
+ attr_accessor :service_checks
27
+ attr_accessor :bytes_sent
28
+ attr_accessor :bytes_dropped
29
+ attr_accessor :packets_sent
30
+ attr_accessor :packets_dropped
31
+ attr_reader :estimate_max_size
32
+
33
+ def initialize(disabled, tags)
34
+ @disabled = disabled
35
+ @tags = tags
36
+ reset
37
+
38
+ # estimate_max_size is an estimation or the maximum size of the
39
+ # telemetry payload. Since we don't want our packet to go over
40
+ # 'max_buffer_bytes', we have to adjust with the size of the telemetry
41
+ # (and any tags used). The telemetry payload size will change depending
42
+ # on the actual value of metrics: metrics received, packet dropped,
43
+ # etc. This is why we add a 63bytes margin: 9 bytes for each of the 7
44
+ # telemetry metrics.
45
+ @estimate_max_size = @disabled ? 0 : flush().length + 9 * 7
46
+ end
47
+
48
+ def reset
49
+ @metrics = 0
50
+ @events = 0
51
+ @service_checks = 0
52
+ @bytes_sent = 0
53
+ @bytes_dropped = 0
54
+ @packets_sent = 0
55
+ @packets_dropped = 0
56
+ end
57
+
58
+ def flush
59
+ return '' if @disabled
60
+
61
+ # using shorthand syntax to reduce the garbage collection
62
+ return %Q(
63
+ datadog.dogstatsd.client.metrics:#{@metrics}|#{COUNTER_TYPE}|##{@tags}
64
+ datadog.dogstatsd.client.events:#{@events}|#{COUNTER_TYPE}|##{@tags}
65
+ datadog.dogstatsd.client.service_checks:#{@service_checks}|#{COUNTER_TYPE}|##{@tags}
66
+ datadog.dogstatsd.client.bytes_sent:#{@bytes_sent}|#{COUNTER_TYPE}|##{@tags}
67
+ datadog.dogstatsd.client.bytes_dropped:#{@bytes_dropped}|#{COUNTER_TYPE}|##{@tags}
68
+ datadog.dogstatsd.client.packets_sent:#{@packets_sent}|#{COUNTER_TYPE}|##{@tags}
69
+ datadog.dogstatsd.client.packets_dropped:#{@packets_dropped}|#{COUNTER_TYPE}|##{@tags})
70
+ end
71
+ end
72
+
23
73
  class Connection
24
74
  DEFAULT_HOST = '127.0.0.1'
25
75
  DEFAULT_PORT = 8125
@@ -33,36 +83,30 @@ module Datadog
33
83
  # DogStatsd unix socket path. Not used by default.
34
84
  attr_reader :socket_path
35
85
 
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
86
+ def initialize(telemetry)
87
+ @telemetry = telemetry
88
+ end
89
+
90
+ # Close the underlying socket
91
+ def close
92
+ @socket && @socket.close
41
93
  end
42
94
 
43
95
  def write(message)
44
96
  @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
50
- 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
97
+ payload = message + @telemetry.flush()
98
+ send_message(payload)
61
99
 
100
+ @telemetry.reset
101
+ @telemetry.bytes_sent += payload.length
102
+ @telemetry.packets_sent += 1
103
+ rescue StandardError => boom
62
104
  # Try once to reconnect if the socket has been closed
63
105
  retries ||= 1
64
- if retries <= 1 && boom.is_a?(Errno::ENOTCONN) or
65
- retries <= 1 && boom.is_a?(IOError) && boom.message =~ /closed stream/i
106
+ if retries <= 1 &&
107
+ (boom.is_a?(Errno::ENOTCONN) or
108
+ boom.is_a?(Errno::ECONNREFUSED) or
109
+ boom.is_a?(IOError) && boom.message =~ /closed stream/i)
66
110
  retries += 1
67
111
  begin
68
112
  @socket = connect
@@ -72,31 +116,63 @@ module Datadog
72
116
  end
73
117
  end
74
118
 
119
+ @telemetry.bytes_dropped += payload.length
120
+ @telemetry.packets_dropped += 1
75
121
  @logger.error { "Statsd: #{boom.class} #{boom}" } if @logger
76
122
  nil
77
123
  end
78
124
 
79
- # Close the underlying socket
80
- def close
81
- @socket && @socket.close
82
- end
83
-
84
125
  private
85
126
 
86
127
  def socket
87
128
  @socket ||= connect
88
129
  end
130
+ end
131
+
132
+ class UDPConnection < Connection
133
+ def initialize(host, port, logger, telemetry)
134
+ super(telemetry)
135
+ @host = host || ENV.fetch('DD_AGENT_HOST', nil) || DEFAULT_HOST
136
+ @port = port || ENV.fetch('DD_DOGSTATSD_PORT', nil) || DEFAULT_PORT
137
+ @logger = logger
138
+ end
139
+
140
+ private
89
141
 
90
142
  def connect
91
- if @socket_path.nil?
92
- socket = UDPSocket.new
93
- socket.connect(@host, @port)
94
- else
95
- socket = Socket.new(Socket::AF_UNIX, Socket::SOCK_DGRAM)
96
- socket.connect(Socket.pack_sockaddr_un(@socket_path))
97
- end
143
+ socket = UDPSocket.new
144
+ socket.connect(@host, @port)
98
145
  socket
99
146
  end
147
+
148
+ def send_message(message)
149
+ socket.send(message, 0)
150
+ end
151
+ end
152
+
153
+ class UDSConnection < Connection
154
+ class BadSocketError < StandardError; end
155
+
156
+ def initialize(socket_path, logger, telemetry)
157
+ super(telemetry)
158
+ @socket_path = socket_path
159
+ @logger = logger
160
+ end
161
+
162
+ private
163
+
164
+ def connect
165
+ socket = Socket.new(Socket::AF_UNIX, Socket::SOCK_DGRAM)
166
+ socket.connect(Socket.pack_sockaddr_un(@socket_path))
167
+ socket
168
+ end
169
+
170
+ def send_message(message)
171
+ socket.sendmsg_nonblock(message)
172
+ rescue Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::ENOENT => e
173
+ @socket = nil
174
+ raise BadSocketError, "#{e.class}: #{e}"
175
+ end
100
176
  end
101
177
 
102
178
  class Batch
@@ -173,7 +249,8 @@ module Datadog
173
249
  CRITICAL = 2
174
250
  UNKNOWN = 3
175
251
 
176
- MAX_EVENT_SIZE = 8 * 1024
252
+ DEFAULT_BUFFER_SIZE = 8 * 1_024
253
+ MAX_EVENT_SIZE = 8 * 1_024
177
254
 
178
255
  COUNTER_TYPE = 'c'.freeze
179
256
  GAUGE_TYPE = 'g'.freeze
@@ -181,7 +258,7 @@ module Datadog
181
258
  DISTRIBUTION_TYPE = 'd'.freeze
182
259
  TIMING_TYPE = 'ms'.freeze
183
260
  SET_TYPE = 's'.freeze
184
- VERSION = "4.1.0".freeze
261
+ VERSION = "4.6.0".freeze
185
262
 
186
263
  # A namespace to prepend to all statsd calls. Defaults to no namespace.
187
264
  attr_reader :namespace
@@ -195,35 +272,60 @@ module Datadog
195
272
  # Maximum buffer size in bytes before it is flushed
196
273
  attr_reader :max_buffer_bytes
197
274
 
275
+ # Default sample rate
276
+ attr_reader :sample_rate
277
+
198
278
  # Connection
199
279
  attr_reader :connection
200
280
 
201
281
  # @param [String] host your statsd host
202
282
  # @param [Integer] port your statsd port
203
283
  # @option [String] namespace set a namespace to be prepended to every metric name
204
- # @option [Array<String>] tags tags to be added to every metric
205
- # @option [Loger] logger for debugging
284
+ # @option [Array<String>|Hash] tags tags to be added to every metric
285
+ # @option [Logger] logger for debugging
206
286
  # @option [Integer] max_buffer_bytes max bytes to buffer when using #batch
207
287
  # @option [String] socket_path unix socket path
288
+ # @option [Float] default sample rate if not overridden
208
289
  def initialize(
209
290
  host = nil,
210
291
  port = nil,
211
292
  namespace: nil,
212
293
  tags: nil,
213
- max_buffer_bytes: 8192,
294
+ max_buffer_bytes: DEFAULT_BUFFER_SIZE,
214
295
  socket_path: nil,
215
- logger: nil
296
+ logger: nil,
297
+ sample_rate: nil,
298
+ disable_telemetry: false
216
299
  )
217
- @connection = Connection.new(host, port, socket_path, logger)
300
+ unless tags.nil? or tags.is_a? Array or tags.is_a? Hash
301
+ raise ArgumentError, 'tags must be a Array<String> or a Hash'
302
+ end
303
+
304
+ tags = tag_hash_to_array(tags) if tags.is_a? Hash
305
+ @tags = (tags || []).compact.map! {|tag| escape_tag_content(tag)}
306
+
307
+ # append the entity id to tags if DD_ENTITY_ID env var is not nil
308
+ @tags << 'dd.internal.entity_id:' + escape_tag_content(ENV.fetch('DD_ENTITY_ID', nil)) unless ENV.fetch('DD_ENTITY_ID', nil).nil?
309
+
310
+ # init telemetry
311
+ transport_type = socket_path.nil? ? "udp": "uds"
312
+ telemetry_tags = (["client:ruby", "client_version:#{VERSION}", "client_transport:#{transport_type}"] + @tags).join(COMMA).freeze
313
+ @telemetry = Telemetry.new(disable_telemetry, telemetry_tags)
314
+
315
+ if socket_path.nil?
316
+ @connection = UDPConnection.new(host, port, logger, @telemetry)
317
+ else
318
+ @connection = UDSConnection.new(socket_path, logger, @telemetry)
319
+ end
218
320
  @logger = logger
219
321
 
220
322
  @namespace = namespace
221
323
  @prefix = @namespace ? "#{@namespace}.".freeze : nil
222
324
 
223
- raise ArgumentError, 'tags must be a Array<String>' unless tags.nil? or tags.is_a? Array
224
- @tags = (tags || []).compact.map! {|tag| escape_tag_content(tag)}
325
+ @sample_rate = sample_rate
225
326
 
226
- @batch = Batch.new @connection, max_buffer_bytes
327
+ # we reduce max_buffer_bytes by a the rough estimate of the telemetry payload
328
+ @batch = Batch.new(@connection, (max_buffer_bytes - @telemetry.estimate_max_size))
227
329
  end
228
330
 
229
331
  # yield a new instance to a block and close it when done
@@ -307,9 +409,6 @@ module Datadog
307
409
  end
308
410
 
309
411
  # Sends a value to be tracked as a distribution to the statsd server.
310
- # Note: Distributions are a beta feature of Datadog and not generally
311
- # available. Distributions must be specifically enabled for your
312
- # organization.
313
412
  #
314
413
  # @param [String] stat stat name.
315
414
  # @param [Numeric] value distribution value.
@@ -378,13 +477,14 @@ module Datadog
378
477
  # @param [String] name Service check name
379
478
  # @param [String] status Service check status.
380
479
  # @param [Hash] opts the additional data about the service check
381
- # @option opts [Integer, nil] :timestamp (nil) Assign a timestamp to the event. Default is now when none
382
- # @option opts [String, nil] :hostname (nil) Assign a hostname to the event.
480
+ # @option opts [Integer, String, nil] :timestamp (nil) Assign a timestamp to the service check. Default is now when none
481
+ # @option opts [String, nil] :hostname (nil) Assign a hostname to the service check.
383
482
  # @option opts [Array<String>, nil] :tags (nil) An array of tags
384
483
  # @option opts [String, nil] :message (nil) A message to associate with this service check status
385
484
  # @example Report a critical service check status
386
485
  # $statsd.service_check('my.service.check', Statsd::CRITICAL, :tags=>['urgent'])
387
486
  def service_check(name, status, opts=EMPTY_OPTIONS)
487
+ @telemetry.service_checks += 1
388
488
  send_stat format_service_check(name, status, opts)
389
489
  end
390
490
 
@@ -395,9 +495,9 @@ module Datadog
395
495
  # it will be grouped with other events that don't have an event type.
396
496
  #
397
497
  # @param [String] title Event title
398
- # @param [String] text Event text. Supports \n
498
+ # @param [String] text Event text. Supports newlines (+\n+)
399
499
  # @param [Hash] opts the additional data about the event
400
- # @option opts [Integer, nil] :date_happened (nil) Assign a timestamp to the event. Default is now when none
500
+ # @option opts [Integer, String, nil] :date_happened (nil) Assign a timestamp to the event. Default is now when none
401
501
  # @option opts [String, nil] :hostname (nil) Assign a hostname to the event.
402
502
  # @option opts [String, nil] :aggregation_key (nil) Assign an aggregation key to the event, to group it with some others
403
503
  # @option opts [String, nil] :priority ('normal') Can be "normal" or "low"
@@ -407,6 +507,7 @@ module Datadog
407
507
  # @example Report an awful event:
408
508
  # $statsd.event('Something terrible happened', 'The end is near if we do nothing', :alert_type=>'warning', :tags=>['end_of_times','urgent'])
409
509
  def event(title, text, opts=EMPTY_OPTIONS)
510
+ @telemetry.events += 1
410
511
  send_stat format_event(title, text, opts)
411
512
  end
412
513
 
@@ -457,7 +558,11 @@ module Datadog
457
558
  escaped_message = escape_service_check_message(message)
458
559
  sc_string << "|m:#{escaped_message}"
459
560
  else
460
- value = remove_pipes(opts[key])
561
+ if key == :timestamp && opts[key].is_a?(Integer)
562
+ value = opts[key]
563
+ else
564
+ value = remove_pipes(opts[key])
565
+ end
461
566
  sc_string << "|#{shorthand_key}#{value}"
462
567
  end
463
568
  end
@@ -467,13 +572,20 @@ module Datadog
467
572
  def format_event(title, text, opts=EMPTY_OPTIONS)
468
573
  escaped_title = escape_event_content(title)
469
574
  escaped_text = escape_event_content(text)
470
- event_string_data = "_e{#{escaped_title.length},#{escaped_text.length}}:#{escaped_title}|#{escaped_text}".dup
575
+ event_string_data = "_e{#{escaped_title.bytesize},#{escaped_text.bytesize}}:#{escaped_title}|#{escaped_text}".dup
471
576
 
472
577
  # We construct the string to be sent by adding '|key:value' parts to it when needed
473
578
  # All pipes ('|') in the metadata are removed. Title and Text can keep theirs
474
579
  OPTS_KEYS.each do |key, shorthand_key|
475
580
  if key != :tags && opts[key]
476
- value = remove_pipes(opts[key])
581
+ # :date_happened is the only key where the value is an Integer
582
+ # To not break backwards compatibility, we still accept a String
583
+ if key == :date_happened && opts[key].is_a?(Integer)
584
+ value = opts[key]
585
+ # All other keys only have String values
586
+ else
587
+ value = remove_pipes(opts[key])
588
+ end
477
589
  event_string_data << "|#{shorthand_key}:#{value}"
478
590
  end
479
591
  end
@@ -483,12 +595,13 @@ module Datadog
483
595
  event_string_data << "|##{tags_string}"
484
596
  end
485
597
 
486
- raise "Event #{title} payload is too big (more that 8KB), event discarded" if event_string_data.length > MAX_EVENT_SIZE
598
+ raise "Event #{title} payload is too big (more that 8KB), event discarded" if event_string_data.bytesize > MAX_EVENT_SIZE
487
599
  event_string_data
488
600
  end
489
601
 
490
602
  def tags_as_string(opts)
491
603
  if tag_arr = opts[:tags]
604
+ tag_arr = tag_hash_to_array(tag_arr) if tag_arr.is_a? Hash
492
605
  tag_arr = tag_arr.map { |tag| escape_tag_content(tag) }
493
606
  tag_arr = tags + tag_arr # @tags are normalized when set, so not need to normalize them again
494
607
  else
@@ -497,6 +610,10 @@ module Datadog
497
610
  tag_arr.join(COMMA) unless tag_arr.empty?
498
611
  end
499
612
 
613
+ def tag_hash_to_array(tag_hash)
614
+ tag_hash.to_a.map {|pair| pair.compact.join(":")}
615
+ end
616
+
500
617
  def escape_event_content(msg)
501
618
  msg.gsub NEW_LINE, ESC_NEW_LINE
502
619
  end
@@ -516,8 +633,9 @@ module Datadog
516
633
  end
517
634
 
518
635
  def send_stats(stat, delta, type, opts=EMPTY_OPTIONS)
519
- sample_rate = opts[:sample_rate] || 1
520
- if sample_rate == 1 or rand < sample_rate
636
+ @telemetry.metrics += 1
637
+ sample_rate = opts[:sample_rate] || @sample_rate || 1
638
+ if sample_rate == 1 or rand <= sample_rate
521
639
  full_stat = ''.dup
522
640
  full_stat << @prefix if @prefix
523
641
 
@@ -543,17 +661,12 @@ module Datadog
543
661
  full_stat << '#'.freeze
544
662
  full_stat << tags_string
545
663
  end
546
-
547
664
  send_stat(full_stat)
548
665
  end
549
666
  end
550
667
 
551
668
  def send_stat(message)
552
- if @batch.open?
553
- @batch.add message
554
- else
555
- @connection.write(message)
556
- end
669
+ @batch.open? ? @batch.add(message) : @connection.write(message)
557
670
  end
558
671
  end
559
672
  end
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.1.0
4
+ version: 4.6.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: 2019-03-08 00:00:00.000000000 Z
11
+ date: 2020-01-20 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A Ruby DogStastd client
14
14
  email: code@datadoghq.com
@@ -21,10 +21,14 @@ files:
21
21
  - LICENSE.txt
22
22
  - README.md
23
23
  - lib/datadog/statsd.rb
24
- homepage: http://github.com/datadog/dogstatsd-ruby
24
+ homepage: https://github.com/DataDog/dogstatsd-ruby
25
25
  licenses:
26
26
  - MIT
27
- metadata: {}
27
+ metadata:
28
+ bug_tracker_uri: https://github.com/DataDog/dogstatsd-ruby/issues
29
+ changelog_uri: https://github.com/DataDog/dogstatsd-ruby/blob/v4.6.0/CHANGELOG.md
30
+ documentation_uri: https://www.rubydoc.info/gems/dogstatsd-ruby/4.6.0
31
+ source_code_uri: https://github.com/DataDog/dogstatsd-ruby/tree/v4.6.0
28
32
  post_install_message:
29
33
  rdoc_options: []
30
34
  require_paths:
@@ -40,7 +44,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
40
44
  - !ruby/object:Gem::Version
41
45
  version: '0'
42
46
  requirements: []
43
- rubygems_version: 3.0.2
47
+ rubyforge_project:
48
+ rubygems_version: 2.7.10
44
49
  signing_key:
45
50
  specification_version: 4
46
51
  summary: A Ruby DogStatsd client