-
Notifications
You must be signed in to change notification settings - Fork 375
/
client.rb
206 lines (169 loc) · 6.89 KB
/
client.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# frozen_string_literal: true
require_relative '../utils/time'
require_relative '../utils/only_once'
require_relative '../telemetry/logger'
require_relative '../configuration/ext'
require_relative 'ext'
require_relative 'options'
require_relative 'helpers'
require_relative 'logging'
require_relative 'metric'
module Datadog
module Core
module Metrics
# Acts as client for sending metrics (via Statsd)
# Wraps a Statsd client with default tags and additional configuration.
class Client
include Options
extend Options
extend Helpers
attr_reader :statsd
def initialize(statsd: nil, enabled: true, **_)
@statsd =
if supported?
statsd || default_statsd_client
else
ignored_statsd_warning if statsd
nil
end
@enabled = enabled
end
def supported?
version = dogstatsd_version
!version.nil? && version >= Gem::Version.new('3.3.0') &&
# dogstatsd-ruby >= 5.0 & < 5.2.0 has known issues with process forks
# and do not support the single thread mode we use to avoid this problem.
!(version >= Gem::Version.new('5.0') && version < Gem::Version.new('5.3'))
end
def enabled?
@enabled
end
def enabled=(enabled)
@enabled = (enabled == true)
end
def default_hostname
ENV.fetch(Configuration::Ext::Agent::ENV_DEFAULT_HOST, Ext::DEFAULT_HOST)
end
def default_port
ENV.fetch(Configuration::Ext::Metrics::ENV_DEFAULT_PORT, Ext::DEFAULT_PORT).to_i
end
def default_statsd_client
require 'datadog/statsd'
# Create a StatsD client that points to the agent.
#
# We use `single_thread: true`, as dogstatsd-ruby >= 5.0 creates a background thread
# by default, but does not handle forks correctly, causing resource leaks.
#
# Using dogstatsd-ruby >= 5.0 is still valuable, as it supports
# transparent batch metric submission, which reduces submission
# overhead.
#
# Versions < 5.0 are always single-threaded, but do not have the kwarg option.
options = if dogstatsd_version >= Gem::Version.new('5.2')
{ single_thread: true }
else
{}
end
Datadog::Statsd.new(default_hostname, default_port, **options)
end
def configure(options = {})
@statsd = options[:statsd] if options.key?(:statsd)
self.enabled = options[:enabled] if options.key?(:enabled)
end
def send_stats?
enabled? && !statsd.nil?
end
def count(stat, value = nil, options = nil, &block)
return unless send_stats? && statsd.respond_to?(:count)
value, options = yield if block
raise ArgumentError if value.nil?
statsd.count(stat, value, metric_options(options))
rescue StandardError => e
Datadog.logger.error(
"Failed to send count stat. Cause: #{e.class.name} #{e.message} Source: #{Array(e.backtrace).first}"
)
Telemetry::Logger.report(e, description: 'Failed to send count stat')
end
def distribution(stat, value = nil, options = nil, &block)
return unless send_stats? && statsd.respond_to?(:distribution)
value, options = yield if block
raise ArgumentError if value.nil?
statsd.distribution(stat, value, metric_options(options))
rescue StandardError => e
Datadog.logger.error(
"Failed to send distribution stat. Cause: #{e.class.name} #{e.message} Source: #{Array(e.backtrace).first}"
)
Telemetry::Logger.report(e, description: 'Failed to send distribution stat')
end
def increment(stat, options = nil)
return unless send_stats? && statsd.respond_to?(:increment)
options = yield if block_given?
statsd.increment(stat, metric_options(options))
rescue StandardError => e
Datadog.logger.error(
"Failed to send increment stat. Cause: #{e.class.name} #{e.message} Source: #{Array(e.backtrace).first}"
)
Telemetry::Logger.report(e, description: 'Failed to send increment stat')
end
def gauge(stat, value = nil, options = nil, &block)
return unless send_stats? && statsd.respond_to?(:gauge)
value, options = yield if block
raise ArgumentError if value.nil?
statsd.gauge(stat, value, metric_options(options))
rescue StandardError => e
Datadog.logger.error(
"Failed to send gauge stat. Cause: #{e.class.name} #{e.message} Source: #{Array(e.backtrace).first}"
)
Telemetry::Logger.report(e, description: 'Failed to send gauge stat')
end
def time(stat, options = nil)
return yield unless send_stats?
# Calculate time, send it as a distribution.
start = Utils::Time.get_time
yield
ensure
begin
if send_stats? && !start.nil?
finished = Utils::Time.get_time
distribution(stat, ((finished - start) * 1000), options)
end
rescue StandardError => e
# TODO: Likely to be redundant, since `distribution` handles its own errors.
Datadog.logger.error(
"Failed to send time stat. Cause: #{e.class.name} #{e.message} Source: #{Array(e.backtrace).first}"
)
Telemetry::Logger.report(e, description: 'Failed to send time stat')
end
end
def send_metrics(metrics)
metrics.each { |m| send(m.type, *[m.name, m.value, m.options].compact) }
end
def close
@statsd.close if @statsd && @statsd.respond_to?(:close)
end
private
def dogstatsd_version
return @dogstatsd_version if instance_variable_defined?(:@dogstatsd_version)
@dogstatsd_version = (
defined?(Datadog::Statsd::VERSION) &&
Datadog::Statsd::VERSION &&
Gem::Version.new(Datadog::Statsd::VERSION)
) || (
Gem.loaded_specs['dogstatsd-ruby'] &&
Gem.loaded_specs['dogstatsd-ruby'].version
)
end
IGNORED_STATSD_ONLY_ONCE = Utils::OnlyOnce.new
private_constant :IGNORED_STATSD_ONLY_ONCE
def ignored_statsd_warning
IGNORED_STATSD_ONLY_ONCE.run do
Datadog.logger.warn(
'Ignoring user-supplied statsd instance as currently-installed version of dogstastd-ruby is incompatible. ' \
"To fix this, ensure that you have `gem 'dogstatsd-ruby', '~> 5.3'` on your Gemfile or gems.rb file."
)
end
end
end
end
end
end