Class: Datadog::Statsd

Inherits:
Object
  • Object
show all
Defined in:
lib/datadog/statsd.rb,
lib/datadog/statsd/batch.rb,
lib/datadog/statsd/telemetry.rb,
lib/datadog/statsd/connection.rb,
lib/datadog/statsd/udp_connection.rb,
lib/datadog/statsd/uds_connection.rb

Defined Under Namespace

Classes: Batch, Connection, Telemetry, UDPConnection, UDSConnection

Constant Summary collapse

OPTS_KEYS =

Create a dictionary to assign a key to every parameter’s name, except for tags (treated differently) Goal: Simple and fast to add some other parameters

{
  date_happened:    :d,
  hostname:         :h,
  aggregation_key:  :k,
  priority:         :p,
  source_type_name: :s,
  alert_type:       :t,
}.freeze
SC_OPT_KEYS =

Service check options

{
  timestamp: 'd:',
  hostname:  'h:',
  tags:      '#',
  message:   'm:',
}.freeze
OK =
0
WARNING =
1
CRITICAL =
2
UNKNOWN =
3
DEFAULT_BUFFER_SIZE =
8 * 1_024
MAX_EVENT_SIZE =
8 * 1_024
DEFAULT_TELEMETRY_FLUSH_INTERVAL =

minimum flush interval for the telemetry in seconds

10
COUNTER_TYPE =
'c'
GAUGE_TYPE =
'g'
HISTOGRAM_TYPE =
'h'
DISTRIBUTION_TYPE =
'd'
TIMING_TYPE =
'ms'
SET_TYPE =
's'
VERSION =
'4.7.0'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(host = nil, port = nil, namespace: nil, tags: nil, max_buffer_bytes: DEFAULT_BUFFER_SIZE, socket_path: nil, logger: nil, sample_rate: nil, disable_telemetry: false, telemetry_flush_interval: DEFAULT_TELEMETRY_FLUSH_INTERVAL) ⇒ Statsd

Returns a new instance of Statsd.

Parameters:

  • host (String) (defaults to: nil)

    your statsd host

  • port (Integer) (defaults to: nil)

    your statsd port

  • [String] (Hash)

    a customizable set of options

  • [Array<String>|Hash] (Hash)

    a customizable set of options

  • [Logger] (Hash)

    a customizable set of options

  • [Integer] (Hash)

    a customizable set of options

  • [Float] (Hash)

    a customizable set of options



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/datadog/statsd.rb', line 90

def initialize(
  host = nil,
  port = nil,
  namespace: nil,
  tags: nil,
  max_buffer_bytes: DEFAULT_BUFFER_SIZE,
  socket_path: nil,
  logger: nil,
  sample_rate: nil,
  disable_telemetry: false,
  telemetry_flush_interval: DEFAULT_TELEMETRY_FLUSH_INTERVAL
)
  unless tags.nil? || tags.is_a?(Array) || tags.is_a?(Hash)
    raise ArgumentError, 'tags must be a Array<String> or a Hash'
  end

  tags = tag_hash_to_array(tags) if tags.is_a?(Hash)
  @tags = (tags || []).compact.map! do |tag|
    escape_tag_content(tag)
  end

  # append the entity id to tags if DD_ENTITY_ID env var is not nil
  unless ENV.fetch('DD_ENTITY_ID', nil).nil?
    dd_entity = escape_tag_content(ENV.fetch('DD_ENTITY_ID', nil))
    @tags << 'dd.internal.entity_id:' + dd_entity
  end

  # init telemetry
  transport_type = socket_path.nil? ? 'udp': 'uds'
  telemetry_tags = (["client:ruby", "client_version:#{VERSION}", "client_transport:#{transport_type}"] + @tags).join(COMMA).freeze
  @telemetry = Telemetry.new(disable_telemetry, telemetry_tags, telemetry_flush_interval)

  if socket_path.nil?
    @connection = UDPConnection.new(host, port, logger, @telemetry)
  else
    @connection = UDSConnection.new(socket_path, logger, @telemetry)
  end
  @logger = logger

  @namespace = namespace
  @prefix = @namespace ? "#{@namespace}.".freeze : nil

  @sample_rate = sample_rate

  # we reduce max_buffer_bytes by a the rough estimate of the telemetry payload
  @batch = Batch.new(@connection, (max_buffer_bytes - @telemetry.estimate_max_size))
end

Instance Attribute Details

#bufferObject (readonly)

Buffer containing the statsd message before they are sent in batch



71
72
73
# File 'lib/datadog/statsd.rb', line 71

def buffer
  @buffer
end

#connectionObject (readonly)

Connection



80
81
82
# File 'lib/datadog/statsd.rb', line 80

def connection
  @connection
end

#max_buffer_bytesObject (readonly)

Maximum buffer size in bytes before it is flushed



74
75
76
# File 'lib/datadog/statsd.rb', line 74

def max_buffer_bytes
  @max_buffer_bytes
end

#namespaceObject (readonly)

A namespace to prepend to all statsd calls. Defaults to no namespace.



65
66
67
# File 'lib/datadog/statsd.rb', line 65

def namespace
  @namespace
end

#sample_rateObject (readonly)

Default sample rate



77
78
79
# File 'lib/datadog/statsd.rb', line 77

def sample_rate
  @sample_rate
end

#tagsObject (readonly)

Global tags to be added to every statsd call. Defaults to no tags.



68
69
70
# File 'lib/datadog/statsd.rb', line 68

def tags
  @tags
end

Class Method Details

.open(*args) ⇒ Object

yield a new instance to a block and close it when done for short-term use-cases that don’t want to close the socket manually



140
141
142
143
144
145
146
# File 'lib/datadog/statsd.rb', line 140

def self.open(*args)
  instance = new(*args)

  yield instance
ensure
  instance.close
end

Instance Method Details

#batchObject

Send several metrics in the same UDP Packet They will be buffered and flushed when the block finishes

Examples:

Send several metrics in one packet:

$statsd.batch do |s|
   s.gauge('users.online',156)
   s.increment('page.views')
 end


339
340
341
342
343
# File 'lib/datadog/statsd.rb', line 339

def batch
  @batch.open do
    yield self
  end
end

#closeObject

Close the underlying socket



346
347
348
# File 'lib/datadog/statsd.rb', line 346

def close
  @connection.close
end

#count(stat, count, opts = EMPTY_OPTIONS) ⇒ Object

Sends an arbitrary count for the given stat to the statsd server.

Parameters:

  • stat (String)

    stat name

  • count (Integer)

    count

  • opts (Hash) (defaults to: EMPTY_OPTIONS)

    the options to create the metric with

Options Hash (opts):

  • :sample_rate (Numeric)

    sample rate, 1 for always

  • :tags (Array<String>)

    An array of tags



183
184
185
186
# File 'lib/datadog/statsd.rb', line 183

def count(stat, count, opts = EMPTY_OPTIONS)
  opts = { sample_rate: opts } if opts.is_a?(Numeric)
  send_stats(stat, count, COUNTER_TYPE, opts)
end

#decrement(stat, opts = EMPTY_OPTIONS) ⇒ Object

Sends a decrement (count = -1) for the given stat to the statsd server.

Parameters:

  • stat (String)

    stat name

  • opts (Hash) (defaults to: EMPTY_OPTIONS)

    the options to create the metric with

Options Hash (opts):

  • :sample_rate (Numeric)

    sample rate, 1 for always

  • :tags (Array<String>)

    An array of tags

  • :by (Numeric)

    decrement value, default 1

See Also:



170
171
172
173
174
# File 'lib/datadog/statsd.rb', line 170

def decrement(stat, opts = EMPTY_OPTIONS)
  opts = { sample_rate: opts } if opts.is_a?(Numeric)
  decr_value = - opts.fetch(:by, 1)
  count(stat, decr_value, opts)
end

#distribution(stat, value, opts = EMPTY_OPTIONS) ⇒ Object

Sends a value to be tracked as a distribution to the statsd server.

Examples:

Report the current user count:

$statsd.distribution('user.count', User.count)

Parameters:

  • stat (String)

    stat name.

  • value (Numeric)

    distribution value.

  • opts (Hash) (defaults to: EMPTY_OPTIONS)

    the options to create the metric with

Options Hash (opts):

  • :sample_rate (Numeric)

    sample rate, 1 for always

  • :tags (Array<String>)

    An array of tags



228
229
230
# File 'lib/datadog/statsd.rb', line 228

def distribution(stat, value, opts = EMPTY_OPTIONS)
  send_stats(stat, value, DISTRIBUTION_TYPE, opts)
end

#event(title, text, opts = EMPTY_OPTIONS) ⇒ Object

This end point allows you to post events to the stream. You can tag them, set priority and even aggregate them with other events.

Aggregation in the stream is made on hostname/event_type/source_type/aggregation_key. If there’s no event type, for example, then that won’t matter; it will be grouped with other events that don’t have an event type.

Examples:

Report an awful event:

$statsd.event('Something terrible happened', 'The end is near if we do nothing', :alert_type=>'warning', :tags=>['end_of_times','urgent'])

Parameters:

  • title (String)

    Event title

  • text (String)

    Event text. Supports newlines (\n)

  • opts (Hash) (defaults to: EMPTY_OPTIONS)

    the additional data about the event

Options Hash (opts):

  • :date_happened (Integer, String, nil) — default: nil

    Assign a timestamp to the event. Default is now when none

  • :hostname (String, nil) — default: nil

    Assign a hostname to the event.

  • :aggregation_key (String, nil) — default: nil

    Assign an aggregation key to the event, to group it with some others

  • :priority (String, nil) — default: 'normal'

    Can be “normal” or “low”

  • :source_type_name (String, nil) — default: nil

    Assign a source type to the event

  • :alert_type (String, nil) — default: 'info'

    Can be “error”, “warning”, “info” or “success”.

  • :tags (Array<String>)

    tags to be added to every metric



326
327
328
329
# File 'lib/datadog/statsd.rb', line 326

def event(title, text, opts = EMPTY_OPTIONS)
  @telemetry.events += 1
  send_stat(format_event(title, text, opts))
end

#gauge(stat, value, opts = EMPTY_OPTIONS) ⇒ Object

Sends an arbitary gauge value for the given stat to the statsd server.

This is useful for recording things like available disk space, memory usage, and the like, which have different semantics than counters.

Examples:

Report the current user count:

$statsd.gauge('user.count', User.count)

Parameters:

  • stat (String)

    stat name.

  • value (Numeric)

    gauge value.

  • opts (Hash) (defaults to: EMPTY_OPTIONS)

    the options to create the metric with

Options Hash (opts):

  • :sample_rate (Numeric)

    sample rate, 1 for always

  • :tags (Array<String>)

    An array of tags



201
202
203
204
# File 'lib/datadog/statsd.rb', line 201

def gauge(stat, value, opts = EMPTY_OPTIONS)
  opts = { sample_rate: opts } if opts.is_a?(Numeric)
  send_stats(stat, value, GAUGE_TYPE, opts)
end

#histogram(stat, value, opts = EMPTY_OPTIONS) ⇒ Object

Sends a value to be tracked as a histogram to the statsd server.

Examples:

Report the current user count:

$statsd.histogram('user.count', User.count)

Parameters:

  • stat (String)

    stat name.

  • value (Numeric)

    histogram value.

  • opts (Hash) (defaults to: EMPTY_OPTIONS)

    the options to create the metric with

Options Hash (opts):

  • :sample_rate (Numeric)

    sample rate, 1 for always

  • :tags (Array<String>)

    An array of tags



215
216
217
# File 'lib/datadog/statsd.rb', line 215

def histogram(stat, value, opts = EMPTY_OPTIONS)
  send_stats(stat, value, HISTOGRAM_TYPE, opts)
end

#increment(stat, opts = EMPTY_OPTIONS) ⇒ Object

Sends an increment (count = 1) for the given stat to the statsd server.

Parameters:

  • stat (String)

    stat name

  • opts (Hash) (defaults to: EMPTY_OPTIONS)

    the options to create the metric with

Options Hash (opts):

  • :sample_rate (Numeric)

    sample rate, 1 for always

  • :tags (Array<String>)

    An array of tags

  • :by (Numeric)

    increment value, default 1

See Also:



156
157
158
159
160
# File 'lib/datadog/statsd.rb', line 156

def increment(stat, opts = EMPTY_OPTIONS)
  opts = { sample_rate: opts } if opts.is_a?(Numeric)
  incr_value = opts.fetch(:by, 1)
  count(stat, incr_value, opts)
end

#service_check(name, status, opts = EMPTY_OPTIONS) ⇒ Object

Examples:

Report a critical service check status

$statsd.service_check('my.service.check', Statsd::CRITICAL, :tags=>['urgent'])


303
304
305
306
# File 'lib/datadog/statsd.rb', line 303

def service_check(name, status, opts = EMPTY_OPTIONS)
  @telemetry.service_checks += 1
  send_stat(format_service_check(name, status, opts))
end

#set(stat, value, opts = EMPTY_OPTIONS) ⇒ Object

Sends a value to be tracked as a set to the statsd server.

Examples:

Record a unique visitory by id:

$statsd.set('visitors.uniques', User.id)

Parameters:

  • stat (String)

    stat name.

  • value (Numeric)

    set value.

  • opts (Hash) (defaults to: EMPTY_OPTIONS)

    the options to create the metric with

Options Hash (opts):

  • :sample_rate (Numeric)

    sample rate, 1 for always

  • :tags (Array<String>)

    An array of tags



287
288
289
290
# File 'lib/datadog/statsd.rb', line 287

def set(stat, value, opts = EMPTY_OPTIONS)
  opts = { sample_rate: opts } if opts.is_a?(Numeric)
  send_stats(stat, value, SET_TYPE, opts)
end

#time(stat, opts = EMPTY_OPTIONS) { ... } ⇒ Object

Reports execution time of the provided block using #timing.

If the block fails, the stat is still reported, then the error is reraised

Examples:

Report the time (in ms) taken to activate an account

$statsd.time('account.activate') { @account.activate! }

Parameters:

  • stat (String)

    stat name

  • opts (Hash) (defaults to: EMPTY_OPTIONS)

    the options to create the metric with

Options Hash (opts):

  • :sample_rate (Numeric)

    sample rate, 1 for always

  • :tags (Array<String>)

    An array of tags

Yields:

  • The operation to be timed

See Also:



260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
# File 'lib/datadog/statsd.rb', line 260

def time(stat, opts = EMPTY_OPTIONS)
  opts = { sample_rate: opts } if opts.is_a?(Numeric)
  start = if PROCESS_TIME_SUPPORTED
            Process.clock_gettime(Process::CLOCK_MONOTONIC) # uncovered
          else
            Time.now.to_f # uncovered
          end
  yield
ensure
  finished =  if PROCESS_TIME_SUPPORTED
                Process.clock_gettime(Process::CLOCK_MONOTONIC) # uncovered
              else
                Time.now.to_f # uncovered
              end

  timing(stat, ((finished - start) * 1000).round, opts)
end

#timing(stat, ms, opts = EMPTY_OPTIONS) ⇒ Object

Sends a timing (in ms) for the given stat to the statsd server. The sample_rate determines what percentage of the time this report is sent. The statsd server then uses the sample_rate to correctly track the average timing for the stat.

Parameters:

  • stat (String)

    stat name

  • ms (Integer)

    timing in milliseconds

  • opts (Hash) (defaults to: EMPTY_OPTIONS)

    the options to create the metric with

Options Hash (opts):

  • :sample_rate (Numeric)

    sample rate, 1 for always

  • :tags (Array<String>)

    An array of tags



242
243
244
245
# File 'lib/datadog/statsd.rb', line 242

def timing(stat, ms, opts = EMPTY_OPTIONS)
  opts = { sample_rate: opts } if opts.is_a?(Numeric)
  send_stats(stat, ms, TIMING_TYPE, opts)
end