dogstatsd-ruby 4.1.0 → 4.6.0

Sign up to get free protection for your applications and to get access to all the features.
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