dogstatsd-ruby 4.2.0 → 4.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +28 -4
- data/lib/datadog/statsd.rb +91 -49
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 25baf4b0dc57e8ed9a79bd2115224f22de9097200ccf4931b54fbb1e40905363
|
4
|
+
data.tar.gz: a51c91dc366316b6edbadc64eb5e7383b6b100c9a2a859eb9bc31b9bef9ec7e2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 225ef009dcb475534ec746d9eaa6e8b156ad7b50291c2894ba9171806bc91231150510a65a47ec754dbf519f80fe7381c589d34f35e983519fb8e991347e1a12
|
7
|
+
data.tar.gz: e8609033506332625db4a6655adceacfb7fd1b85346020c1582dd032815ea56158d46442cecafd40fdd7bf098745e41ab1e70323b323ff63dd8bb43be3be8b88
|
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, :
|
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, :
|
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(
|
69
|
+
statsd.event('There might be a storm tomorrow', 'A friend warned me earlier.')
|
66
70
|
|
67
71
|
# Cry for help
|
68
|
-
statsd.event(
|
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
|
|
data/lib/datadog/statsd.rb
CHANGED
@@ -33,32 +33,15 @@ module Datadog
|
|
33
33
|
# DogStatsd unix socket path. Not used by default.
|
34
34
|
attr_reader :socket_path
|
35
35
|
|
36
|
-
|
37
|
-
|
38
|
-
@
|
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
|
-
|
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
47
|
if retries <= 1 && boom.is_a?(Errno::ENOTCONN) or
|
@@ -76,27 +59,55 @@ module Datadog
|
|
76
59
|
nil
|
77
60
|
end
|
78
61
|
|
79
|
-
# Close the underlying socket
|
80
|
-
def close
|
81
|
-
@socket && @socket.close
|
82
|
-
end
|
83
|
-
|
84
62
|
private
|
85
63
|
|
86
64
|
def socket
|
87
65
|
@socket ||= connect
|
88
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
|
89
77
|
|
90
78
|
def connect
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
79
|
+
socket = UDPSocket.new
|
80
|
+
socket.connect(@host, @port)
|
81
|
+
socket
|
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))
|
98
102
|
socket
|
99
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
|
100
111
|
end
|
101
112
|
|
102
113
|
class Batch
|
@@ -181,7 +192,7 @@ module Datadog
|
|
181
192
|
DISTRIBUTION_TYPE = 'd'.freeze
|
182
193
|
TIMING_TYPE = 'ms'.freeze
|
183
194
|
SET_TYPE = 's'.freeze
|
184
|
-
VERSION = "4.
|
195
|
+
VERSION = "4.4.0".freeze
|
185
196
|
|
186
197
|
# A namespace to prepend to all statsd calls. Defaults to no namespace.
|
187
198
|
attr_reader :namespace
|
@@ -195,16 +206,20 @@ module Datadog
|
|
195
206
|
# Maximum buffer size in bytes before it is flushed
|
196
207
|
attr_reader :max_buffer_bytes
|
197
208
|
|
209
|
+
# Default sample rate
|
210
|
+
attr_reader :sample_rate
|
211
|
+
|
198
212
|
# Connection
|
199
213
|
attr_reader :connection
|
200
214
|
|
201
215
|
# @param [String] host your statsd host
|
202
216
|
# @param [Integer] port your statsd port
|
203
217
|
# @option [String] namespace set a namespace to be prepended to every metric name
|
204
|
-
# @option [Array<String
|
205
|
-
# @option [
|
218
|
+
# @option [Array<String>|Hash] tags tags to be added to every metric
|
219
|
+
# @option [Logger] logger for debugging
|
206
220
|
# @option [Integer] max_buffer_bytes max bytes to buffer when using #batch
|
207
221
|
# @option [String] socket_path unix socket path
|
222
|
+
# @option [Float] default sample rate if not overridden
|
208
223
|
def initialize(
|
209
224
|
host = nil,
|
210
225
|
port = nil,
|
@@ -212,15 +227,26 @@ module Datadog
|
|
212
227
|
tags: nil,
|
213
228
|
max_buffer_bytes: 8192,
|
214
229
|
socket_path: nil,
|
215
|
-
logger: nil
|
230
|
+
logger: nil,
|
231
|
+
sample_rate: nil
|
216
232
|
)
|
217
|
-
|
233
|
+
if socket_path.nil?
|
234
|
+
@connection = UDPConnection.new(host, port, logger)
|
235
|
+
else
|
236
|
+
@connection = UDSConnection.new(socket_path, logger)
|
237
|
+
end
|
218
238
|
@logger = logger
|
219
239
|
|
220
240
|
@namespace = namespace
|
221
241
|
@prefix = @namespace ? "#{@namespace}.".freeze : nil
|
222
242
|
|
223
|
-
|
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
|
224
250
|
@tags = (tags || []).compact.map! {|tag| escape_tag_content(tag)}
|
225
251
|
|
226
252
|
# append the entity id to tags if DD_ENTITY_ID env var is not nil
|
@@ -381,8 +407,8 @@ module Datadog
|
|
381
407
|
# @param [String] name Service check name
|
382
408
|
# @param [String] status Service check status.
|
383
409
|
# @param [Hash] opts the additional data about the service check
|
384
|
-
# @option opts [Integer, nil] :timestamp (nil) Assign a timestamp to the
|
385
|
-
# @option opts [String, nil] :hostname (nil) Assign a hostname to the
|
410
|
+
# @option opts [Integer, String, nil] :timestamp (nil) Assign a timestamp to the service check. Default is now when none
|
411
|
+
# @option opts [String, nil] :hostname (nil) Assign a hostname to the service check.
|
386
412
|
# @option opts [Array<String>, nil] :tags (nil) An array of tags
|
387
413
|
# @option opts [String, nil] :message (nil) A message to associate with this service check status
|
388
414
|
# @example Report a critical service check status
|
@@ -398,9 +424,9 @@ module Datadog
|
|
398
424
|
# it will be grouped with other events that don't have an event type.
|
399
425
|
#
|
400
426
|
# @param [String] title Event title
|
401
|
-
# @param [String] text Event text. Supports
|
427
|
+
# @param [String] text Event text. Supports newlines (+\n+)
|
402
428
|
# @param [Hash] opts the additional data about the event
|
403
|
-
# @option opts [Integer, nil] :date_happened (nil) Assign a timestamp to the event. Default is now when none
|
429
|
+
# @option opts [Integer, String, nil] :date_happened (nil) Assign a timestamp to the event. Default is now when none
|
404
430
|
# @option opts [String, nil] :hostname (nil) Assign a hostname to the event.
|
405
431
|
# @option opts [String, nil] :aggregation_key (nil) Assign an aggregation key to the event, to group it with some others
|
406
432
|
# @option opts [String, nil] :priority ('normal') Can be "normal" or "low"
|
@@ -460,7 +486,11 @@ module Datadog
|
|
460
486
|
escaped_message = escape_service_check_message(message)
|
461
487
|
sc_string << "|m:#{escaped_message}"
|
462
488
|
else
|
463
|
-
|
489
|
+
if key == :timestamp && opts[key].is_a?(Integer)
|
490
|
+
value = opts[key]
|
491
|
+
else
|
492
|
+
value = remove_pipes(opts[key])
|
493
|
+
end
|
464
494
|
sc_string << "|#{shorthand_key}#{value}"
|
465
495
|
end
|
466
496
|
end
|
@@ -470,13 +500,20 @@ module Datadog
|
|
470
500
|
def format_event(title, text, opts=EMPTY_OPTIONS)
|
471
501
|
escaped_title = escape_event_content(title)
|
472
502
|
escaped_text = escape_event_content(text)
|
473
|
-
event_string_data = "_e{#{escaped_title.
|
503
|
+
event_string_data = "_e{#{escaped_title.bytesize},#{escaped_text.bytesize}}:#{escaped_title}|#{escaped_text}".dup
|
474
504
|
|
475
505
|
# We construct the string to be sent by adding '|key:value' parts to it when needed
|
476
506
|
# All pipes ('|') in the metadata are removed. Title and Text can keep theirs
|
477
507
|
OPTS_KEYS.each do |key, shorthand_key|
|
478
508
|
if key != :tags && opts[key]
|
479
|
-
value
|
509
|
+
# :date_happened is the only key where the value is an Integer
|
510
|
+
# To not break backwards compatibility, we still accept a String
|
511
|
+
if key == :date_happened && opts[key].is_a?(Integer)
|
512
|
+
value = opts[key]
|
513
|
+
# All other keys only have String values
|
514
|
+
else
|
515
|
+
value = remove_pipes(opts[key])
|
516
|
+
end
|
480
517
|
event_string_data << "|#{shorthand_key}:#{value}"
|
481
518
|
end
|
482
519
|
end
|
@@ -486,12 +523,13 @@ module Datadog
|
|
486
523
|
event_string_data << "|##{tags_string}"
|
487
524
|
end
|
488
525
|
|
489
|
-
raise "Event #{title} payload is too big (more that 8KB), event discarded" if event_string_data.
|
526
|
+
raise "Event #{title} payload is too big (more that 8KB), event discarded" if event_string_data.bytesize > MAX_EVENT_SIZE
|
490
527
|
event_string_data
|
491
528
|
end
|
492
529
|
|
493
530
|
def tags_as_string(opts)
|
494
531
|
if tag_arr = opts[:tags]
|
532
|
+
tag_arr = tag_hash_to_array(tag_arr) if tag_arr.is_a? Hash
|
495
533
|
tag_arr = tag_arr.map { |tag| escape_tag_content(tag) }
|
496
534
|
tag_arr = tags + tag_arr # @tags are normalized when set, so not need to normalize them again
|
497
535
|
else
|
@@ -500,6 +538,10 @@ module Datadog
|
|
500
538
|
tag_arr.join(COMMA) unless tag_arr.empty?
|
501
539
|
end
|
502
540
|
|
541
|
+
def tag_hash_to_array(tag_hash)
|
542
|
+
tag_hash.to_a.map {|pair| pair.compact.join(":")}
|
543
|
+
end
|
544
|
+
|
503
545
|
def escape_event_content(msg)
|
504
546
|
msg.gsub NEW_LINE, ESC_NEW_LINE
|
505
547
|
end
|
@@ -519,8 +561,8 @@ module Datadog
|
|
519
561
|
end
|
520
562
|
|
521
563
|
def send_stats(stat, delta, type, opts=EMPTY_OPTIONS)
|
522
|
-
sample_rate = opts[:sample_rate] || 1
|
523
|
-
if sample_rate == 1 or rand
|
564
|
+
sample_rate = opts[:sample_rate] || @sample_rate || 1
|
565
|
+
if sample_rate == 1 or rand <= sample_rate
|
524
566
|
full_stat = ''.dup
|
525
567
|
full_stat << @prefix if @prefix
|
526
568
|
|
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.
|
4
|
+
version: 4.4.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-
|
11
|
+
date: 2019-07-15 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: A Ruby DogStastd client
|
14
14
|
email: code@datadoghq.com
|
@@ -40,7 +40,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
40
40
|
- !ruby/object:Gem::Version
|
41
41
|
version: '0'
|
42
42
|
requirements: []
|
43
|
-
|
43
|
+
rubyforge_project:
|
44
|
+
rubygems_version: 2.7.6
|
44
45
|
signing_key:
|
45
46
|
specification_version: 4
|
46
47
|
summary: A Ruby DogStatsd client
|