dogstatsd-ruby 4.0.0 → 5.2.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 +176 -56
- data/lib/datadog/statsd.rb +169 -333
- data/lib/datadog/statsd/connection.rb +59 -0
- data/lib/datadog/statsd/forwarder.rb +122 -0
- data/lib/datadog/statsd/message_buffer.rb +88 -0
- data/lib/datadog/statsd/sender.rb +117 -0
- data/lib/datadog/statsd/serialization.rb +15 -0
- data/lib/datadog/statsd/serialization/event_serializer.rb +71 -0
- data/lib/datadog/statsd/serialization/serializer.rb +41 -0
- data/lib/datadog/statsd/serialization/service_check_serializer.rb +60 -0
- data/lib/datadog/statsd/serialization/stat_serializer.rb +55 -0
- data/lib/datadog/statsd/serialization/tag_serializer.rb +96 -0
- data/lib/datadog/statsd/single_thread_sender.rb +31 -0
- data/lib/datadog/statsd/telemetry.rb +96 -0
- data/lib/datadog/statsd/udp_connection.rb +37 -0
- data/lib/datadog/statsd/uds_connection.rb +38 -0
- data/lib/datadog/statsd/version.rb +9 -0
- metadata +30 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9abfaabd9be58a320dd8cc8d1d4998ac287daa08e68ab894054cf2910f5f3133
|
4
|
+
data.tar.gz: 88ebf4ef472f7663897c06fa3e5753a17c12722bc1a58f8aa4e9fb0a3ace07c6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 199527bd5e9d39d94be3cabf28dc5f4d8913c4d3f746a6018a22c9ed13440c34d77fc11b363f47f9e2fd325974005fdc3567a223de4669b388ced99c3cd0750f
|
7
|
+
data.tar.gz: 0da25bafef540e4d36be8cae9c1fbb1f11c6aea94415828941aa9c34877db75166574f41b5e1a0829c71285f958162133d0f592a34619ce066e14c97ea86fd4d
|
data/README.md
CHANGED
@@ -1,97 +1,217 @@
|
|
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
|
-
|
5
|
+
[![Build Status](https://secure.travis-ci.org/DataDog/dogstatsd-ruby.svg)](http://travis-ci.org/DataDog/dogstatsd-ruby)
|
6
6
|
|
7
|
-
[
|
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
|
-
|
10
|
-
-----------------
|
9
|
+
## Installation
|
11
10
|
|
12
11
|
First install the library:
|
13
12
|
|
14
|
-
|
13
|
+
```
|
14
|
+
gem install dogstatsd-ruby
|
15
|
+
```
|
16
|
+
|
17
|
+
## Configuration
|
15
18
|
|
16
|
-
|
19
|
+
To instantiate a DogStatsd client:
|
17
20
|
|
18
|
-
```
|
19
|
-
#
|
21
|
+
```ruby
|
22
|
+
# Import the library
|
20
23
|
require 'datadog/statsd'
|
21
24
|
|
22
|
-
# Create a
|
25
|
+
# Create a DogStatsD client instance.
|
23
26
|
statsd = Datadog::Statsd.new('localhost', 8125)
|
27
|
+
...
|
28
|
+
# release resources used by the client instance
|
29
|
+
statsd.close()
|
30
|
+
```
|
31
|
+
Or if you want to connect over Unix Domain Socket:
|
32
|
+
```ruby
|
33
|
+
# Connection over Unix Domain Socket
|
34
|
+
statsd = Datadog::Statsd.new(socket_path: '/path/to/socket/file')
|
35
|
+
...
|
36
|
+
# release resources used by the client instance
|
37
|
+
statsd.close()
|
38
|
+
```
|
39
|
+
|
40
|
+
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=ruby#client-instantiation-parameters).
|
41
|
+
|
42
|
+
### Migrating from v4.x to v5.x
|
43
|
+
|
44
|
+
If you are already using DogStatsD-ruby v4.x and you want to migrate to a version v5.x, the major
|
45
|
+
change concerning you is the new threading model (please see section Threading model):
|
46
|
+
|
47
|
+
In practice, it means two things:
|
48
|
+
|
49
|
+
1. Now that the client is buffering metrics before sending them, you have to manually
|
50
|
+
call the method `Datadog::Statsd#flush` if you want to force the sending of metrics. Note that the companion thread will automatically flush the buffered metrics if the buffer gets full or when you are closing the instance.
|
51
|
+
|
52
|
+
2. You have to make sure you are either:
|
53
|
+
|
54
|
+
* using singletons instances of the DogStatsD client and not allocating one each time you need one, letting the buffering mechanism flush metrics, it's still a bad solution if the process later forks (see related section below). Or,
|
55
|
+
* properly closing your DogStatsD client instance when it is not needed anymore using the method `Datadog::Statsd#close` to release the resources used by the instance and to close the socket
|
56
|
+
|
57
|
+
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):
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
# Import the library
|
61
|
+
require 'datadog/statsd'
|
62
|
+
|
63
|
+
# Create a DogStatsD client instance using UDP
|
64
|
+
statsd = Datadog::Statsd.new('localhost', 8125, single_thread: true, buffer_max_payload_size: 1)
|
65
|
+
...
|
66
|
+
# to close the instance is not necessary in this case since metrics are flushed on submission
|
67
|
+
# but it is still a good practice and it explicitely closes the socket
|
68
|
+
statsd.close()
|
69
|
+
```
|
70
|
+
|
71
|
+
or
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
# Import the library
|
75
|
+
require 'datadog/statsd'
|
76
|
+
|
77
|
+
# Create a DogStatsD client instance using UDS
|
78
|
+
statsd = Datadog::Statsd.new(socket_path: '/path/to/socket/file', single_thread: true, buffer_max_payload_size: 1)
|
79
|
+
...
|
80
|
+
# to close the instance is not necessary in this case since metrics are flushed on submission
|
81
|
+
# but it is still a good practice and it explicitely closes the socket
|
82
|
+
statsd.close()
|
83
|
+
```
|
84
|
+
|
85
|
+
### v5.x Common Pitfalls
|
24
86
|
|
25
|
-
|
26
|
-
# class Statsd < Datadog::Statsd
|
27
|
-
# end
|
87
|
+
Version v5.x of `dogstatsd-ruby` is using a companion thread for preemptive flushing, it brings better performances for application having a high-throughput of statsd metrics, but it comes with new pitfalls:
|
28
88
|
|
29
|
-
|
30
|
-
|
89
|
+
* Applications forking after having created the dogstatsd instance: forking a process can't duplicate the existing threads, meaning that one of the processes won't have a companion thread to flush the metrics and will lead to missing metrics.
|
90
|
+
* Applications creating a lot of different instances of the client without closing them: it is important to close the instance to free the thread and the socket it is using or it will lead to thread leaks.
|
31
91
|
|
32
|
-
|
33
|
-
statsd.gauge('users.online', 123, :sample_rate=>0.5)
|
92
|
+
If you are using [Sidekiq](https://github.com/mperham/sidekiq), please make sure to close the client instances that are instantiated. [See this example on using DogStatsD-ruby v5.x with Sidekiq](https://github.com/DataDog/dogstatsd-ruby/blob/master/examples/sidekiq_example.rb).
|
34
93
|
|
35
|
-
|
36
|
-
statsd.histogram('file.upload.size', 1234)
|
94
|
+
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).
|
37
95
|
|
38
|
-
|
39
|
-
statsd.time('page.render') do
|
40
|
-
render_page('home.html')
|
41
|
-
end
|
96
|
+
Applications that are in these situations but can't apply these recommendations should enable the `single_thread` mode which does not use a companion thread. Here is how to instantiate a client in this mode:
|
42
97
|
|
43
|
-
|
44
|
-
#
|
45
|
-
statsd
|
46
|
-
|
47
|
-
|
48
|
-
|
98
|
+
```ruby
|
99
|
+
# Import the library
|
100
|
+
require 'datadog/statsd'
|
101
|
+
|
102
|
+
# Create a DogStatsD client instance.
|
103
|
+
statsd = Datadog::Statsd.new('localhost', 8125, single_thread: true)
|
104
|
+
...
|
105
|
+
# release resources used by the client instance and flush last metrics
|
106
|
+
statsd.close()
|
107
|
+
```
|
49
108
|
|
50
|
-
|
51
|
-
statsd.histogram('query.time', 10, :tags => ["version:1"])
|
109
|
+
### Origin detection over UDP
|
52
110
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
111
|
+
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.
|
112
|
+
|
113
|
+
To enable origin detection over UDP, add the following lines to your application manifest
|
114
|
+
```yaml
|
115
|
+
env:
|
116
|
+
- name: DD_ENTITY_ID
|
117
|
+
valueFrom:
|
118
|
+
fieldRef:
|
119
|
+
fieldPath: metadata.uid
|
57
120
|
```
|
121
|
+
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.
|
122
|
+
|
123
|
+
## Usage
|
124
|
+
|
125
|
+
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).
|
126
|
+
|
127
|
+
### Metrics
|
128
|
+
|
129
|
+
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:
|
130
|
+
|
131
|
+
* [Submit a COUNT metric](https://docs.datadoghq.com/developers/metrics/dogstatsd_metrics_submission/?tab=ruby#count).
|
132
|
+
* [Submit a GAUGE metric](https://docs.datadoghq.com/developers/metrics/dogstatsd_metrics_submission/?tab=ruby#gauge).
|
133
|
+
* [Submit a SET metric](https://docs.datadoghq.com/developers/metrics/dogstatsd_metrics_submission/?tab=ruby#set)
|
134
|
+
* [Submit a HISTOGRAM metric](https://docs.datadoghq.com/developers/metrics/dogstatsd_metrics_submission/?tab=ruby#histogram)
|
135
|
+
* [Submit a DISTRIBUTION metric](https://docs.datadoghq.com/developers/metrics/dogstatsd_metrics_submission/?tab=ruby#distribution)
|
136
|
+
|
137
|
+
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).
|
138
|
+
|
139
|
+
### Events
|
140
|
+
|
141
|
+
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.
|
58
142
|
|
59
|
-
|
143
|
+
### Service Checks
|
60
144
|
|
61
|
-
|
145
|
+
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.
|
62
146
|
|
63
|
-
|
64
|
-
# Post a simple message
|
65
|
-
statsd.event("There might be a storm tomorrow", "A friend warned me earlier.")
|
147
|
+
### Maximum packets size in high-throughput scenarios
|
66
148
|
|
67
|
-
|
68
|
-
|
149
|
+
In order to have the most efficient use of this library in high-throughput scenarios,
|
150
|
+
default values for the maximum packets size have already been set for both UDS (8192 bytes)
|
151
|
+
and UDP (1432 bytes) in order to have the best usage of the underlying network.
|
152
|
+
However, if you perfectly know your network and you know that a different value for the maximum packets
|
153
|
+
size should be used, you can set it with the parameter `buffer_max_payload_size`. Example:
|
154
|
+
|
155
|
+
```ruby
|
156
|
+
# Create a DogStatsD client instance.
|
157
|
+
statsd = Datadog::Statsd.new('localhost', 8125, buffer_max_payload_size: 4096)
|
69
158
|
```
|
70
159
|
|
160
|
+
## Threading model
|
161
|
+
|
162
|
+
On versions greater than 5.0, we changed the threading model of the library so that one instance of `Datadog::Statsd` could be shared between threads and so that the writes in the socket are non blocking.
|
163
|
+
|
164
|
+
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. Please use `single_thread: true` while creating an instance if you don't want to or can't use a companion thread.
|
165
|
+
|
166
|
+
This thread is stopped when you close the statsd client (`Datadog::Statsd#close`). It also means that allocating a lot of statsd clients without closing them properly when not used anymore
|
167
|
+
could lead to a thread leak (even though they will be sleeping, blocked on IO).
|
168
|
+
The communication between the current thread is managed through a standard Ruby Queue.
|
169
|
+
|
170
|
+
The sender thread has the following logic (Code present in the method `Datadog::Statsd::Sender#send_loop`):
|
171
|
+
|
172
|
+
```
|
173
|
+
while the sender message queue is not closed do
|
174
|
+
read message from sender message queue
|
175
|
+
|
176
|
+
if message is a Control message to flush
|
177
|
+
flush buffer in connection
|
178
|
+
else if message is a Control message to synchronize
|
179
|
+
synchronize with calling thread
|
180
|
+
else
|
181
|
+
add message to the buffer
|
182
|
+
end
|
183
|
+
end while
|
184
|
+
```
|
185
|
+
|
186
|
+
Most of the time, the sender thread is blocked and sleeping when doing a blocking read from the sender message queue.
|
187
|
+
|
188
|
+
We can see that there is 3 different kind of messages:
|
189
|
+
|
190
|
+
* a control message to flush the buffer in the connection
|
191
|
+
* a control message to synchronize any thread with the sender thread
|
192
|
+
* a message to append to the buffer
|
71
193
|
|
194
|
+
There is also an implicit message which is closing the queue as it will stop blocking read from the message queue (if happening) and thus, stop the sender thread.
|
72
195
|
|
73
|
-
|
74
|
-
-------------
|
196
|
+
### Usual workflow
|
75
197
|
|
76
|
-
|
77
|
-
[here](http://www.rubydoc.info/github/DataDog/dogstatsd-ruby/master/frames).
|
198
|
+
You push metrics to the statsd client which writes them quickly to the sender message queue. The sender thread receives those message, buffers them and flushes them to the connection when the buffer limit is reached.
|
78
199
|
|
200
|
+
### Flushing
|
79
201
|
|
80
|
-
|
81
|
-
--------
|
202
|
+
When calling a flush, a specific control message (the `:flush` symbol) is sent to the sender thread. When finding it, it flushes its internal buffer into the connection.
|
82
203
|
|
83
|
-
|
84
|
-
[here](http://github.com/DataDog/dogstatsd-ruby/issues/).
|
204
|
+
### Rendez-vous
|
85
205
|
|
206
|
+
It is possible to ensure a message has been consumed by the sender thread and written to the buffer by simply calling a rendez-vous right after. This is done when you are doing a synchronized flush (calling `Datadog::Statsd#flush` with the `sync: true` option).
|
86
207
|
|
87
|
-
|
88
|
-
----------------------------
|
208
|
+
This means the current thread is going to sleep and wait for a Queue which is given to the sender thread. When the sender thread reads this queue from its own message queue, it puts a placeholder message in it so that it wakes up the calling thread.
|
89
209
|
|
210
|
+
This is useful when closing the application or when checking unit tests.
|
90
211
|
|
91
|
-
Credits
|
92
|
-
-------
|
212
|
+
## Credits
|
93
213
|
|
94
|
-
dogstatsd-ruby is forked from
|
214
|
+
dogstatsd-ruby is forked from Rein Henrichs [original Statsd
|
95
215
|
client](https://github.com/reinh/statsd).
|
96
216
|
|
97
217
|
Copyright (c) 2011 Rein Henrichs. See LICENSE.txt for
|
data/lib/datadog/statsd.rb
CHANGED
@@ -1,6 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require 'socket'
|
3
3
|
|
4
|
+
require_relative 'statsd/version'
|
5
|
+
require_relative 'statsd/telemetry'
|
6
|
+
require_relative 'statsd/udp_connection'
|
7
|
+
require_relative 'statsd/uds_connection'
|
8
|
+
require_relative 'statsd/message_buffer'
|
9
|
+
require_relative 'statsd/serialization'
|
10
|
+
require_relative 'statsd/sender'
|
11
|
+
require_relative 'statsd/single_thread_sender'
|
12
|
+
require_relative 'statsd/forwarder'
|
13
|
+
|
4
14
|
# = Datadog::Statsd: A DogStatsd client (https://www.datadoghq.com)
|
5
15
|
#
|
6
16
|
# @example Set up a global Statsd client for a server on localhost:8125
|
@@ -19,216 +29,101 @@ require 'socket'
|
|
19
29
|
# statsd = Datadog::Statsd.new 'localhost', 8125, tags: 'tag1:true'
|
20
30
|
module Datadog
|
21
31
|
class Statsd
|
22
|
-
|
23
|
-
class Connection
|
24
|
-
DEFAULT_HOST = '127.0.0.1'
|
25
|
-
DEFAULT_PORT = 8125
|
26
|
-
|
27
|
-
# StatsD host. Defaults to 127.0.0.1.
|
28
|
-
attr_reader :host
|
29
|
-
|
30
|
-
# StatsD port. Defaults to 8125.
|
31
|
-
attr_reader :port
|
32
|
-
|
33
|
-
# DogStatsd unix socket path. Not used by default.
|
34
|
-
attr_reader :socket_path
|
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
|
41
|
-
end
|
42
|
-
|
43
|
-
def write(message)
|
44
|
-
@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
|
61
|
-
|
62
|
-
# Try once to reconnect if the socket has been closed
|
63
|
-
retries ||= 1
|
64
|
-
if retries <= 1 && boom.is_a?(IOError) && boom.message =~ /closed stream/i
|
65
|
-
retries += 1
|
66
|
-
begin
|
67
|
-
@socket = connect
|
68
|
-
retry
|
69
|
-
rescue StandardError => e
|
70
|
-
boom = e
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
@logger.error { "Statsd: #{boom.class} #{boom}" } if @logger
|
75
|
-
nil
|
76
|
-
end
|
77
|
-
|
78
|
-
# Close the underlying socket
|
79
|
-
def close
|
80
|
-
@socket && @socket.close
|
81
|
-
end
|
82
|
-
|
83
|
-
private
|
84
|
-
|
85
|
-
def socket
|
86
|
-
@socket ||= connect
|
87
|
-
end
|
88
|
-
|
89
|
-
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
|
97
|
-
socket
|
98
|
-
end
|
32
|
+
class Error < StandardError
|
99
33
|
end
|
100
34
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
end
|
120
|
-
|
121
|
-
def add(message)
|
122
|
-
message_bytes = message.bytesize
|
123
|
-
|
124
|
-
unless @buffer_bytes == 0
|
125
|
-
if @buffer_bytes + 1 + message_bytes >= @max_buffer_bytes
|
126
|
-
flush
|
127
|
-
else
|
128
|
-
@buffer << NEW_LINE
|
129
|
-
@buffer_bytes += 1
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
@buffer << message
|
134
|
-
@buffer_bytes += message_bytes
|
135
|
-
end
|
136
|
-
|
137
|
-
def flush
|
138
|
-
return if @buffer_bytes == 0
|
139
|
-
@connection.write @buffer
|
140
|
-
reset
|
141
|
-
end
|
142
|
-
|
143
|
-
private
|
144
|
-
|
145
|
-
def reset
|
146
|
-
@buffer = String.new
|
147
|
-
@buffer_bytes = 0
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
# Create a dictionary to assign a key to every parameter's name, except for tags (treated differently)
|
152
|
-
# Goal: Simple and fast to add some other parameters
|
153
|
-
OPTS_KEYS = {
|
154
|
-
:date_happened => :d,
|
155
|
-
:hostname => :h,
|
156
|
-
:aggregation_key => :k,
|
157
|
-
:priority => :p,
|
158
|
-
:source_type_name => :s,
|
159
|
-
:alert_type => :t,
|
160
|
-
}
|
161
|
-
|
162
|
-
# Service check options
|
163
|
-
SC_OPT_KEYS = {
|
164
|
-
:timestamp => 'd:'.freeze,
|
165
|
-
:hostname => 'h:'.freeze,
|
166
|
-
:tags => '#'.freeze,
|
167
|
-
:message => 'm:'.freeze,
|
168
|
-
}
|
169
|
-
|
170
|
-
OK = 0
|
171
|
-
WARNING = 1
|
172
|
-
CRITICAL = 2
|
173
|
-
UNKNOWN = 3
|
174
|
-
|
175
|
-
MAX_EVENT_SIZE = 8 * 1024
|
176
|
-
|
177
|
-
COUNTER_TYPE = 'c'.freeze
|
178
|
-
GAUGE_TYPE = 'g'.freeze
|
179
|
-
HISTOGRAM_TYPE = 'h'.freeze
|
180
|
-
DISTRIBUTION_TYPE = 'd'.freeze
|
181
|
-
TIMING_TYPE = 'ms'.freeze
|
182
|
-
SET_TYPE = 's'.freeze
|
183
|
-
VERSION = "4.0.0".freeze
|
35
|
+
OK = 0
|
36
|
+
WARNING = 1
|
37
|
+
CRITICAL = 2
|
38
|
+
UNKNOWN = 3
|
39
|
+
|
40
|
+
UDP_DEFAULT_BUFFER_SIZE = 1_432
|
41
|
+
UDS_DEFAULT_BUFFER_SIZE = 8_192
|
42
|
+
DEFAULT_BUFFER_POOL_SIZE = Float::INFINITY
|
43
|
+
MAX_EVENT_SIZE = 8 * 1_024
|
44
|
+
# minimum flush interval for the telemetry in seconds
|
45
|
+
DEFAULT_TELEMETRY_FLUSH_INTERVAL = 10
|
46
|
+
|
47
|
+
COUNTER_TYPE = 'c'
|
48
|
+
GAUGE_TYPE = 'g'
|
49
|
+
HISTOGRAM_TYPE = 'h'
|
50
|
+
DISTRIBUTION_TYPE = 'd'
|
51
|
+
TIMING_TYPE = 'ms'
|
52
|
+
SET_TYPE = 's'
|
184
53
|
|
185
54
|
# A namespace to prepend to all statsd calls. Defaults to no namespace.
|
186
55
|
attr_reader :namespace
|
187
56
|
|
188
57
|
# Global tags to be added to every statsd call. Defaults to no tags.
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
attr_reader :buffer
|
193
|
-
|
194
|
-
# Maximum buffer size in bytes before it is flushed
|
195
|
-
attr_reader :max_buffer_bytes
|
58
|
+
def tags
|
59
|
+
serializer.global_tags
|
60
|
+
end
|
196
61
|
|
197
|
-
#
|
198
|
-
attr_reader :
|
62
|
+
# Default sample rate
|
63
|
+
attr_reader :sample_rate
|
199
64
|
|
200
65
|
# @param [String] host your statsd host
|
201
66
|
# @param [Integer] port your statsd port
|
202
67
|
# @option [String] namespace set a namespace to be prepended to every metric name
|
203
|
-
# @option [Array<String
|
204
|
-
# @option [
|
205
|
-
# @option [Integer]
|
68
|
+
# @option [Array<String>|Hash] tags tags to be added to every metric
|
69
|
+
# @option [Logger] logger for debugging
|
70
|
+
# @option [Integer] buffer_max_payload_size max bytes to buffer
|
71
|
+
# @option [Integer] buffer_max_pool_size max messages to buffer
|
206
72
|
# @option [String] socket_path unix socket path
|
73
|
+
# @option [Float] default sample rate if not overridden
|
74
|
+
# @option [Boolean] single_thread flushes the metrics on the main thread instead of in a companion thread
|
207
75
|
def initialize(
|
208
76
|
host = nil,
|
209
77
|
port = nil,
|
78
|
+
socket_path: nil,
|
79
|
+
|
210
80
|
namespace: nil,
|
211
81
|
tags: nil,
|
212
|
-
|
213
|
-
|
214
|
-
|
82
|
+
sample_rate: nil,
|
83
|
+
|
84
|
+
buffer_max_payload_size: nil,
|
85
|
+
buffer_max_pool_size: nil,
|
86
|
+
buffer_overflowing_stategy: :drop,
|
87
|
+
|
88
|
+
logger: nil,
|
89
|
+
|
90
|
+
single_thread: false,
|
91
|
+
|
92
|
+
telemetry_enable: true,
|
93
|
+
telemetry_flush_interval: DEFAULT_TELEMETRY_FLUSH_INTERVAL
|
215
94
|
)
|
216
|
-
|
217
|
-
|
95
|
+
unless tags.nil? || tags.is_a?(Array) || tags.is_a?(Hash)
|
96
|
+
raise ArgumentError, 'tags must be an array of string tags or a Hash'
|
97
|
+
end
|
218
98
|
|
219
99
|
@namespace = namespace
|
220
100
|
@prefix = @namespace ? "#{@namespace}.".freeze : nil
|
101
|
+
@serializer = Serialization::Serializer.new(prefix: @prefix, global_tags: tags)
|
102
|
+
@sample_rate = sample_rate
|
103
|
+
|
104
|
+
@forwarder = Forwarder.new(
|
105
|
+
host: host,
|
106
|
+
port: port,
|
107
|
+
socket_path: socket_path,
|
221
108
|
|
222
|
-
|
223
|
-
|
109
|
+
global_tags: tags,
|
110
|
+
logger: logger,
|
224
111
|
|
225
|
-
|
112
|
+
single_thread: single_thread,
|
113
|
+
|
114
|
+
buffer_max_payload_size: buffer_max_payload_size,
|
115
|
+
buffer_max_pool_size: buffer_max_pool_size,
|
116
|
+
buffer_overflowing_stategy: buffer_overflowing_stategy,
|
117
|
+
|
118
|
+
telemetry_flush_interval: telemetry_enable ? telemetry_flush_interval : nil,
|
119
|
+
)
|
226
120
|
end
|
227
121
|
|
228
122
|
# yield a new instance to a block and close it when done
|
229
123
|
# for short-term use-cases that don't want to close the socket manually
|
230
124
|
def self.open(*args)
|
231
125
|
instance = new(*args)
|
126
|
+
|
232
127
|
yield instance
|
233
128
|
ensure
|
234
129
|
instance.close
|
@@ -242,10 +137,10 @@ module Datadog
|
|
242
137
|
# @option opts [Array<String>] :tags An array of tags
|
243
138
|
# @option opts [Numeric] :by increment value, default 1
|
244
139
|
# @see #count
|
245
|
-
def increment(stat, opts=EMPTY_OPTIONS)
|
246
|
-
opts = {:
|
140
|
+
def increment(stat, opts = EMPTY_OPTIONS)
|
141
|
+
opts = { sample_rate: opts } if opts.is_a?(Numeric)
|
247
142
|
incr_value = opts.fetch(:by, 1)
|
248
|
-
count
|
143
|
+
count(stat, incr_value, opts)
|
249
144
|
end
|
250
145
|
|
251
146
|
# Sends a decrement (count = -1) for the given stat to the statsd server.
|
@@ -256,10 +151,10 @@ module Datadog
|
|
256
151
|
# @option opts [Array<String>] :tags An array of tags
|
257
152
|
# @option opts [Numeric] :by decrement value, default 1
|
258
153
|
# @see #count
|
259
|
-
def decrement(stat, opts=EMPTY_OPTIONS)
|
260
|
-
opts = {:
|
154
|
+
def decrement(stat, opts = EMPTY_OPTIONS)
|
155
|
+
opts = { sample_rate: opts } if opts.is_a?(Numeric)
|
261
156
|
decr_value = - opts.fetch(:by, 1)
|
262
|
-
count
|
157
|
+
count(stat, decr_value, opts)
|
263
158
|
end
|
264
159
|
|
265
160
|
# Sends an arbitrary count for the given stat to the statsd server.
|
@@ -269,9 +164,9 @@ module Datadog
|
|
269
164
|
# @param [Hash] opts the options to create the metric with
|
270
165
|
# @option opts [Numeric] :sample_rate sample rate, 1 for always
|
271
166
|
# @option opts [Array<String>] :tags An array of tags
|
272
|
-
def count(stat, count, opts=EMPTY_OPTIONS)
|
273
|
-
opts = {:
|
274
|
-
send_stats
|
167
|
+
def count(stat, count, opts = EMPTY_OPTIONS)
|
168
|
+
opts = { sample_rate: opts } if opts.is_a?(Numeric)
|
169
|
+
send_stats(stat, count, COUNTER_TYPE, opts)
|
275
170
|
end
|
276
171
|
|
277
172
|
# Sends an arbitary gauge value for the given stat to the statsd server.
|
@@ -287,9 +182,9 @@ module Datadog
|
|
287
182
|
# @option opts [Array<String>] :tags An array of tags
|
288
183
|
# @example Report the current user count:
|
289
184
|
# $statsd.gauge('user.count', User.count)
|
290
|
-
def gauge(stat, value, opts=EMPTY_OPTIONS)
|
291
|
-
opts = {:
|
292
|
-
send_stats
|
185
|
+
def gauge(stat, value, opts = EMPTY_OPTIONS)
|
186
|
+
opts = { sample_rate: opts } if opts.is_a?(Numeric)
|
187
|
+
send_stats(stat, value, GAUGE_TYPE, opts)
|
293
188
|
end
|
294
189
|
|
295
190
|
# Sends a value to be tracked as a histogram to the statsd server.
|
@@ -301,14 +196,11 @@ module Datadog
|
|
301
196
|
# @option opts [Array<String>] :tags An array of tags
|
302
197
|
# @example Report the current user count:
|
303
198
|
# $statsd.histogram('user.count', User.count)
|
304
|
-
def histogram(stat, value, opts=EMPTY_OPTIONS)
|
305
|
-
send_stats
|
199
|
+
def histogram(stat, value, opts = EMPTY_OPTIONS)
|
200
|
+
send_stats(stat, value, HISTOGRAM_TYPE, opts)
|
306
201
|
end
|
307
202
|
|
308
203
|
# Sends a value to be tracked as a distribution to the statsd server.
|
309
|
-
# Note: Distributions are a beta feature of Datadog and not generally
|
310
|
-
# available. Distributions must be specifically enabled for your
|
311
|
-
# organization.
|
312
204
|
#
|
313
205
|
# @param [String] stat stat name.
|
314
206
|
# @param [Numeric] value distribution value.
|
@@ -317,8 +209,8 @@ module Datadog
|
|
317
209
|
# @option opts [Array<String>] :tags An array of tags
|
318
210
|
# @example Report the current user count:
|
319
211
|
# $statsd.distribution('user.count', User.count)
|
320
|
-
def distribution(stat, value, opts=EMPTY_OPTIONS)
|
321
|
-
send_stats
|
212
|
+
def distribution(stat, value, opts = EMPTY_OPTIONS)
|
213
|
+
send_stats(stat, value, DISTRIBUTION_TYPE, opts)
|
322
214
|
end
|
323
215
|
|
324
216
|
# Sends a timing (in ms) for the given stat to the statsd server. The
|
@@ -331,9 +223,9 @@ module Datadog
|
|
331
223
|
# @param [Hash] opts the options to create the metric with
|
332
224
|
# @option opts [Numeric] :sample_rate sample rate, 1 for always
|
333
225
|
# @option opts [Array<String>] :tags An array of tags
|
334
|
-
def timing(stat, ms, opts=EMPTY_OPTIONS)
|
335
|
-
opts = {:
|
336
|
-
send_stats
|
226
|
+
def timing(stat, ms, opts = EMPTY_OPTIONS)
|
227
|
+
opts = { sample_rate: opts } if opts.is_a?(Numeric)
|
228
|
+
send_stats(stat, ms, TIMING_TYPE, opts)
|
337
229
|
end
|
338
230
|
|
339
231
|
# Reports execution time of the provided block using {#timing}.
|
@@ -349,13 +241,12 @@ module Datadog
|
|
349
241
|
# @see #timing
|
350
242
|
# @example Report the time (in ms) taken to activate an account
|
351
243
|
# $statsd.time('account.activate') { @account.activate! }
|
352
|
-
def time(stat, opts=EMPTY_OPTIONS)
|
353
|
-
opts = {:
|
354
|
-
start =
|
355
|
-
|
244
|
+
def time(stat, opts = EMPTY_OPTIONS)
|
245
|
+
opts = { sample_rate: opts } if opts.is_a?(Numeric)
|
246
|
+
start = now
|
247
|
+
yield
|
356
248
|
ensure
|
357
|
-
|
358
|
-
timing(stat, ((finished - start) * 1000).round, opts)
|
249
|
+
timing(stat, ((now - start) * 1000).round, opts)
|
359
250
|
end
|
360
251
|
|
361
252
|
# Sends a value to be tracked as a set to the statsd server.
|
@@ -367,9 +258,9 @@ module Datadog
|
|
367
258
|
# @option opts [Array<String>] :tags An array of tags
|
368
259
|
# @example Record a unique visitory by id:
|
369
260
|
# $statsd.set('visitors.uniques', User.id)
|
370
|
-
def set(stat, value, opts=EMPTY_OPTIONS)
|
371
|
-
opts = {:
|
372
|
-
send_stats
|
261
|
+
def set(stat, value, opts = EMPTY_OPTIONS)
|
262
|
+
opts = { sample_rate: opts } if opts.is_a?(Numeric)
|
263
|
+
send_stats(stat, value, SET_TYPE, opts)
|
373
264
|
end
|
374
265
|
|
375
266
|
# This method allows you to send custom service check statuses.
|
@@ -377,14 +268,16 @@ module Datadog
|
|
377
268
|
# @param [String] name Service check name
|
378
269
|
# @param [String] status Service check status.
|
379
270
|
# @param [Hash] opts the additional data about the service check
|
380
|
-
# @option opts [Integer, nil] :timestamp (nil) Assign a timestamp to the
|
381
|
-
# @option opts [String, nil] :hostname (nil) Assign a hostname to the
|
271
|
+
# @option opts [Integer, String, nil] :timestamp (nil) Assign a timestamp to the service check. Default is now when none
|
272
|
+
# @option opts [String, nil] :hostname (nil) Assign a hostname to the service check.
|
382
273
|
# @option opts [Array<String>, nil] :tags (nil) An array of tags
|
383
274
|
# @option opts [String, nil] :message (nil) A message to associate with this service check status
|
384
275
|
# @example Report a critical service check status
|
385
276
|
# $statsd.service_check('my.service.check', Statsd::CRITICAL, :tags=>['urgent'])
|
386
|
-
def service_check(name, status, opts=EMPTY_OPTIONS)
|
387
|
-
|
277
|
+
def service_check(name, status, opts = EMPTY_OPTIONS)
|
278
|
+
telemetry.sent(service_checks: 1) if telemetry
|
279
|
+
|
280
|
+
forwarder.send_message(serializer.to_service_check(name, status, opts))
|
388
281
|
end
|
389
282
|
|
390
283
|
# This end point allows you to post events to the stream. You can tag them, set priority and even aggregate them with other events.
|
@@ -394,23 +287,33 @@ module Datadog
|
|
394
287
|
# it will be grouped with other events that don't have an event type.
|
395
288
|
#
|
396
289
|
# @param [String] title Event title
|
397
|
-
# @param [String] text Event text. Supports
|
290
|
+
# @param [String] text Event text. Supports newlines (+\n+)
|
398
291
|
# @param [Hash] opts the additional data about the event
|
399
|
-
# @option opts [Integer, nil] :date_happened (nil) Assign a timestamp to the event. Default is now when none
|
292
|
+
# @option opts [Integer, String, nil] :date_happened (nil) Assign a timestamp to the event. Default is now when none
|
400
293
|
# @option opts [String, nil] :hostname (nil) Assign a hostname to the event.
|
401
294
|
# @option opts [String, nil] :aggregation_key (nil) Assign an aggregation key to the event, to group it with some others
|
402
295
|
# @option opts [String, nil] :priority ('normal') Can be "normal" or "low"
|
403
296
|
# @option opts [String, nil] :source_type_name (nil) Assign a source type to the event
|
404
297
|
# @option opts [String, nil] :alert_type ('info') Can be "error", "warning", "info" or "success".
|
298
|
+
# @option opts [Boolean, false] :truncate_if_too_long (false) Truncate the event if it is too long
|
405
299
|
# @option opts [Array<String>] :tags tags to be added to every metric
|
406
300
|
# @example Report an awful event:
|
407
301
|
# $statsd.event('Something terrible happened', 'The end is near if we do nothing', :alert_type=>'warning', :tags=>['end_of_times','urgent'])
|
408
|
-
def event(title, text, opts=EMPTY_OPTIONS)
|
409
|
-
|
302
|
+
def event(title, text, opts = EMPTY_OPTIONS)
|
303
|
+
telemetry.sent(events: 1) if telemetry
|
304
|
+
|
305
|
+
forwarder.send_message(serializer.to_event(title, text, opts))
|
410
306
|
end
|
411
307
|
|
412
|
-
# Send several metrics in the same
|
413
|
-
# They will be buffered and flushed when the block finishes
|
308
|
+
# Send several metrics in the same packet.
|
309
|
+
# They will be buffered and flushed when the block finishes.
|
310
|
+
#
|
311
|
+
# This method exists for compatibility with v4.x versions, it is not needed
|
312
|
+
# anymore since the batching is now automatically done internally.
|
313
|
+
# It also means that an automatic flush could occur if the buffer is filled
|
314
|
+
# during the execution of the batch block.
|
315
|
+
#
|
316
|
+
# This method is DEPRECATED and will be removed in future v6.x API.
|
414
317
|
#
|
415
318
|
# @example Send several metrics in one packet:
|
416
319
|
# $statsd.batch do |s|
|
@@ -418,140 +321,73 @@ module Datadog
|
|
418
321
|
# s.increment('page.views')
|
419
322
|
# end
|
420
323
|
def batch
|
421
|
-
|
324
|
+
yield self
|
325
|
+
flush(sync: true)
|
422
326
|
end
|
423
327
|
|
424
328
|
# Close the underlying socket
|
425
|
-
|
426
|
-
|
329
|
+
#
|
330
|
+
# @param [Boolean, true] flush Should we flush the metrics before closing
|
331
|
+
def close(flush: true)
|
332
|
+
flush(sync: true) if flush
|
333
|
+
forwarder.close
|
427
334
|
end
|
428
335
|
|
429
|
-
|
430
|
-
|
431
|
-
NEW_LINE = "\n".freeze
|
432
|
-
ESC_NEW_LINE = "\\n".freeze
|
433
|
-
COMMA = ",".freeze
|
434
|
-
PIPE = "|".freeze
|
435
|
-
DOT = ".".freeze
|
436
|
-
DOUBLE_COLON = "::".freeze
|
437
|
-
UNDERSCORE = "_".freeze
|
438
|
-
PROCESS_TIME_SUPPORTED = (RUBY_VERSION >= "2.1.0")
|
439
|
-
EMPTY_OPTIONS = {}.freeze
|
440
|
-
|
441
|
-
private_constant :NEW_LINE, :ESC_NEW_LINE, :COMMA, :PIPE, :DOT,
|
442
|
-
:DOUBLE_COLON, :UNDERSCORE, :EMPTY_OPTIONS
|
443
|
-
|
444
|
-
def format_service_check(name, status, opts=EMPTY_OPTIONS)
|
445
|
-
sc_string = "_sc|#{name}|#{status}".dup
|
446
|
-
|
447
|
-
SC_OPT_KEYS.each do |key, shorthand_key|
|
448
|
-
next unless opts[key]
|
449
|
-
|
450
|
-
if key == :tags
|
451
|
-
if tags_string = tags_as_string(opts)
|
452
|
-
sc_string << "|##{tags_string}"
|
453
|
-
end
|
454
|
-
elsif key == :message
|
455
|
-
message = remove_pipes(opts[:message])
|
456
|
-
escaped_message = escape_service_check_message(message)
|
457
|
-
sc_string << "|m:#{escaped_message}"
|
458
|
-
else
|
459
|
-
value = remove_pipes(opts[key])
|
460
|
-
sc_string << "|#{shorthand_key}#{value}"
|
461
|
-
end
|
462
|
-
end
|
463
|
-
sc_string
|
336
|
+
def sync_with_outbound_io
|
337
|
+
forwarder.sync_with_outbound_io
|
464
338
|
end
|
465
339
|
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
event_string_data = "_e{#{escaped_title.length},#{escaped_text.length}}:#{escaped_title}|#{escaped_text}".dup
|
470
|
-
|
471
|
-
# We construct the string to be sent by adding '|key:value' parts to it when needed
|
472
|
-
# All pipes ('|') in the metadata are removed. Title and Text can keep theirs
|
473
|
-
OPTS_KEYS.each do |key, shorthand_key|
|
474
|
-
if key != :tags && opts[key]
|
475
|
-
value = remove_pipes(opts[key])
|
476
|
-
event_string_data << "|#{shorthand_key}:#{value}"
|
477
|
-
end
|
478
|
-
end
|
479
|
-
|
480
|
-
# Tags are joined and added as last part to the string to be sent
|
481
|
-
if tags_string = tags_as_string(opts)
|
482
|
-
event_string_data << "|##{tags_string}"
|
483
|
-
end
|
484
|
-
|
485
|
-
raise "Event #{title} payload is too big (more that 8KB), event discarded" if event_string_data.length > MAX_EVENT_SIZE
|
486
|
-
event_string_data
|
340
|
+
# Flush the buffer into the connection
|
341
|
+
def flush(flush_telemetry: false, sync: false)
|
342
|
+
forwarder.flush(flush_telemetry: flush_telemetry, sync: sync)
|
487
343
|
end
|
488
344
|
|
489
|
-
def
|
490
|
-
|
491
|
-
tag_arr = tag_arr.map { |tag| escape_tag_content(tag) }
|
492
|
-
tag_arr = tags + tag_arr # @tags are normalized when set, so not need to normalize them again
|
493
|
-
else
|
494
|
-
tag_arr = tags
|
495
|
-
end
|
496
|
-
tag_arr.join(COMMA) unless tag_arr.empty?
|
345
|
+
def telemetry
|
346
|
+
forwarder.telemetry
|
497
347
|
end
|
498
348
|
|
499
|
-
def
|
500
|
-
|
349
|
+
def host
|
350
|
+
forwarder.host
|
501
351
|
end
|
502
352
|
|
503
|
-
def
|
504
|
-
|
505
|
-
tag.delete! COMMA
|
506
|
-
tag
|
353
|
+
def port
|
354
|
+
forwarder.port
|
507
355
|
end
|
508
356
|
|
509
|
-
def
|
510
|
-
|
357
|
+
def socket_path
|
358
|
+
forwarder.socket_path
|
511
359
|
end
|
512
360
|
|
513
|
-
def
|
514
|
-
|
361
|
+
def transport_type
|
362
|
+
forwarder.transport_type
|
515
363
|
end
|
516
364
|
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
full_stat << PIPE
|
532
|
-
full_stat << type
|
533
|
-
|
534
|
-
unless sample_rate == 1
|
535
|
-
full_stat << PIPE
|
536
|
-
full_stat << '@'.freeze
|
537
|
-
full_stat << sample_rate.to_s
|
538
|
-
end
|
539
|
-
|
540
|
-
if tags_string = tags_as_string(opts)
|
541
|
-
full_stat << PIPE
|
542
|
-
full_stat << '#'.freeze
|
543
|
-
full_stat << tags_string
|
544
|
-
end
|
545
|
-
|
546
|
-
send_stat(full_stat)
|
365
|
+
private
|
366
|
+
attr_reader :serializer
|
367
|
+
attr_reader :forwarder
|
368
|
+
|
369
|
+
PROCESS_TIME_SUPPORTED = (RUBY_VERSION >= '2.1.0')
|
370
|
+
EMPTY_OPTIONS = {}.freeze
|
371
|
+
|
372
|
+
if PROCESS_TIME_SUPPORTED
|
373
|
+
def now
|
374
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
375
|
+
end
|
376
|
+
else
|
377
|
+
def now
|
378
|
+
Time.now.to_f
|
547
379
|
end
|
548
380
|
end
|
549
381
|
|
550
|
-
def
|
551
|
-
if
|
552
|
-
|
553
|
-
|
554
|
-
|
382
|
+
def send_stats(stat, delta, type, opts = EMPTY_OPTIONS)
|
383
|
+
telemetry.sent(metrics: 1) if telemetry
|
384
|
+
|
385
|
+
sample_rate = opts[:sample_rate] || @sample_rate || 1
|
386
|
+
|
387
|
+
if sample_rate == 1 || rand <= sample_rate
|
388
|
+
full_stat = serializer.to_stat(stat, delta, type, tags: opts[:tags], sample_rate: sample_rate)
|
389
|
+
|
390
|
+
forwarder.send_message(full_stat)
|
555
391
|
end
|
556
392
|
end
|
557
393
|
end
|