appoptics-api-ruby 2.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +23 -0
- data/.rspec +2 -0
- data/.travis.yml +25 -0
- data/CHANGELOG.md +184 -0
- data/Gemfile +36 -0
- data/LICENSE +24 -0
- data/README.md +271 -0
- data/Rakefile +63 -0
- data/appoptics-api-ruby.gemspec +31 -0
- data/benchmarks/array_vs_set.rb +29 -0
- data/certs/librato-public.pem +20 -0
- data/examples/simple.rb +24 -0
- data/examples/submit_every.rb +27 -0
- data/lib/appoptics/metrics.rb +95 -0
- data/lib/appoptics/metrics/aggregator.rb +138 -0
- data/lib/appoptics/metrics/annotator.rb +145 -0
- data/lib/appoptics/metrics/client.rb +361 -0
- data/lib/appoptics/metrics/collection.rb +43 -0
- data/lib/appoptics/metrics/connection.rb +101 -0
- data/lib/appoptics/metrics/errors.rb +32 -0
- data/lib/appoptics/metrics/middleware/count_requests.rb +28 -0
- data/lib/appoptics/metrics/middleware/expects_status.rb +38 -0
- data/lib/appoptics/metrics/middleware/request_body.rb +18 -0
- data/lib/appoptics/metrics/middleware/retry.rb +31 -0
- data/lib/appoptics/metrics/persistence.rb +2 -0
- data/lib/appoptics/metrics/persistence/direct.rb +73 -0
- data/lib/appoptics/metrics/persistence/test.rb +27 -0
- data/lib/appoptics/metrics/processor.rb +130 -0
- data/lib/appoptics/metrics/queue.rb +191 -0
- data/lib/appoptics/metrics/smart_json.rb +43 -0
- data/lib/appoptics/metrics/util.rb +25 -0
- data/lib/appoptics/metrics/version.rb +5 -0
- data/spec/integration/metrics/annotator_spec.rb +190 -0
- data/spec/integration/metrics/connection_spec.rb +14 -0
- data/spec/integration/metrics/middleware/count_requests_spec.rb +28 -0
- data/spec/integration/metrics/queue_spec.rb +96 -0
- data/spec/integration/metrics_spec.rb +375 -0
- data/spec/rackups/status.ru +30 -0
- data/spec/spec_helper.rb +88 -0
- data/spec/unit/metrics/aggregator_spec.rb +417 -0
- data/spec/unit/metrics/client_spec.rb +127 -0
- data/spec/unit/metrics/connection_spec.rb +113 -0
- data/spec/unit/metrics/queue/autosubmission_spec.rb +57 -0
- data/spec/unit/metrics/queue_spec.rb +593 -0
- data/spec/unit/metrics/smart_json_spec.rb +79 -0
- data/spec/unit/metrics/util_spec.rb +23 -0
- data/spec/unit/metrics_spec.rb +63 -0
- metadata +135 -0
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
module Appoptics
|
|
2
|
+
module Metrics
|
|
3
|
+
|
|
4
|
+
class Client
|
|
5
|
+
extend Forwardable
|
|
6
|
+
|
|
7
|
+
def_delegator :annotator, :add, :annotate
|
|
8
|
+
|
|
9
|
+
attr_accessor :api_key, :proxy
|
|
10
|
+
|
|
11
|
+
# @example Have the gem build your identifier string
|
|
12
|
+
# Appoptics::Metrics.agent_identifier 'flintstone', '0.5', 'fred'
|
|
13
|
+
#
|
|
14
|
+
# @example Provide your own identifier string
|
|
15
|
+
# Appoptics::Metrics.agent_identifier 'flintstone/0.5 (dev_id:fred)'
|
|
16
|
+
#
|
|
17
|
+
# @example Remove identifier string
|
|
18
|
+
# Appoptics::Metrics.agent_identifier ''
|
|
19
|
+
def agent_identifier(*args)
|
|
20
|
+
if args.length == 1
|
|
21
|
+
@agent_identifier = args.first
|
|
22
|
+
elsif args.length == 3
|
|
23
|
+
@agent_identifier = "#{args[0]}/#{args[1]} (dev_id:#{args[2]})"
|
|
24
|
+
elsif ![0,1,3].include?(args.length)
|
|
25
|
+
raise ArgumentError, 'invalid arguments, see method documentation'
|
|
26
|
+
end
|
|
27
|
+
@agent_identifier ||= ''
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def annotator
|
|
31
|
+
@annotator ||= Annotator.new(client: self)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# API endpoint to use for queries and direct
|
|
35
|
+
# persistence.
|
|
36
|
+
#
|
|
37
|
+
# @return [String] api_endpoint
|
|
38
|
+
def api_endpoint
|
|
39
|
+
@api_endpoint ||= 'https://api.appoptics.com'
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Set API endpoint for use with queries and direct
|
|
43
|
+
# persistence. Generally you should not need to set this
|
|
44
|
+
# as it will default to the current Appoptics endpoint.
|
|
45
|
+
#
|
|
46
|
+
def api_endpoint=(endpoint)
|
|
47
|
+
@api_endpoint = endpoint
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Authenticate for direct persistence
|
|
51
|
+
#
|
|
52
|
+
# @param [String] email
|
|
53
|
+
# @param [String] api_key
|
|
54
|
+
def authenticate(api_key)
|
|
55
|
+
flush_authentication
|
|
56
|
+
self.api_key = api_key
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Current connection object
|
|
60
|
+
#
|
|
61
|
+
def connection
|
|
62
|
+
# prevent successful creation if no credentials set
|
|
63
|
+
raise CredentialsMissing unless (self.api_key)
|
|
64
|
+
@connection ||= Connection.new(client: self, api_endpoint: api_endpoint,
|
|
65
|
+
adapter: faraday_adapter, proxy: self.proxy)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Overrride user agent for this client's connections. If you
|
|
69
|
+
# are trying to specify an agent identifier for developer
|
|
70
|
+
# program, see #agent_identifier.
|
|
71
|
+
#
|
|
72
|
+
def custom_user_agent=(agent)
|
|
73
|
+
@user_agent = agent
|
|
74
|
+
@connection = nil
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def custom_user_agent
|
|
78
|
+
@user_agent
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Completely delete metrics with the given names. Be
|
|
82
|
+
# careful with this, this is instant and permanent.
|
|
83
|
+
#
|
|
84
|
+
# @example Delete metric 'temperature'
|
|
85
|
+
# Appoptics::Metrics.delete_metrics :temperature
|
|
86
|
+
#
|
|
87
|
+
# @example Delete metrics 'foo' and 'bar'
|
|
88
|
+
# Appoptics::Metrics.delete_metrics :foo, :bar
|
|
89
|
+
#
|
|
90
|
+
# @example Delete metrics that start with 'foo' except 'foobar'
|
|
91
|
+
# Appoptics::Metrics.delete_metrics names: 'foo*', exclude: ['foobar']
|
|
92
|
+
#
|
|
93
|
+
def delete_metrics(*metric_names)
|
|
94
|
+
raise(NoMetricsProvided, 'Metric name missing.') if metric_names.empty?
|
|
95
|
+
if metric_names[0].respond_to?(:keys) # hash form
|
|
96
|
+
params = metric_names[0]
|
|
97
|
+
else
|
|
98
|
+
params = { names: metric_names.map(&:to_s) }
|
|
99
|
+
end
|
|
100
|
+
connection.delete do |request|
|
|
101
|
+
request.url connection.build_url("metrics")
|
|
102
|
+
request.body = SmartJSON.write(params)
|
|
103
|
+
end
|
|
104
|
+
# expects 204, middleware will raise exception otherwise.
|
|
105
|
+
true
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Return current adapter this client will use.
|
|
109
|
+
# Defaults to Metrics.faraday_adapter if set, otherwise
|
|
110
|
+
# Faraday.default_adapter
|
|
111
|
+
def faraday_adapter
|
|
112
|
+
@faraday_adapter ||= default_faraday_adapter
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Set faraday adapter this client will use
|
|
116
|
+
def faraday_adapter=(adapter)
|
|
117
|
+
@faraday_adapter = adapter
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Retrieve measurements for a given composite metric definition.
|
|
121
|
+
# :start_time and :resolution are required options, :end_time is
|
|
122
|
+
# optional.
|
|
123
|
+
#
|
|
124
|
+
# @example Get 5m moving average of 'foo'
|
|
125
|
+
# measurements = Appoptics::Metrics.get_composite
|
|
126
|
+
# 'moving_average(mean(series("foo", "*"), {size: "5"}))',
|
|
127
|
+
# start_time: Time.now.to_i - 60*60, resolution: 300
|
|
128
|
+
#
|
|
129
|
+
# @param [String] definition Composite definition
|
|
130
|
+
# @param [hash] options Query options
|
|
131
|
+
def get_composite(definition, options={})
|
|
132
|
+
unless options[:start_time] && options[:resolution]
|
|
133
|
+
raise "You must provide a :start_time and :resolution"
|
|
134
|
+
end
|
|
135
|
+
query = options.dup
|
|
136
|
+
query[:compose] = definition
|
|
137
|
+
url = connection.build_url("metrics", query)
|
|
138
|
+
response = connection.get(url)
|
|
139
|
+
parsed = SmartJSON.read(response.body)
|
|
140
|
+
# TODO: pagination support
|
|
141
|
+
parsed
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# Retrieve a specific metric by name, optionally including data points
|
|
145
|
+
#
|
|
146
|
+
# @example Get attributes for a metric
|
|
147
|
+
# metric = Appoptics::Metrics.get_metric :temperature
|
|
148
|
+
#
|
|
149
|
+
# @example Get a metric and its 20 most recent data points
|
|
150
|
+
# metric = Appoptics::Metrics.get_metric :temperature, count: 20
|
|
151
|
+
# metric['measurements'] # => {...}
|
|
152
|
+
#
|
|
153
|
+
# A full list of query parameters can be found in the API
|
|
154
|
+
# documentation: {http://docs.appoptics.com/api/#retrieve-a-metric}
|
|
155
|
+
#
|
|
156
|
+
# @param [Symbol|String] name Metric name
|
|
157
|
+
# @param [Hash] options Query options
|
|
158
|
+
def get_metric(name, options = {})
|
|
159
|
+
query = options.dup
|
|
160
|
+
if query[:start_time].respond_to?(:year)
|
|
161
|
+
query[:start_time] = query[:start_time].to_i
|
|
162
|
+
end
|
|
163
|
+
if query[:end_time].respond_to?(:year)
|
|
164
|
+
query[:end_time] = query[:end_time].to_i
|
|
165
|
+
end
|
|
166
|
+
unless query.empty?
|
|
167
|
+
query[:resolution] ||= 1
|
|
168
|
+
end
|
|
169
|
+
# expects 200
|
|
170
|
+
url = connection.build_url("metrics/#{name}", query)
|
|
171
|
+
response = connection.get(url)
|
|
172
|
+
parsed = SmartJSON.read(response.body)
|
|
173
|
+
# TODO: pagination support
|
|
174
|
+
parsed
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Retrieve series of measurements for a given metric
|
|
178
|
+
#
|
|
179
|
+
# @example Get series for metric
|
|
180
|
+
# series = Appoptics::Metrics.get_series :requests, resolution: 1, duration: 3600
|
|
181
|
+
#
|
|
182
|
+
# @example Get series for metric grouped by tag
|
|
183
|
+
# query = { duration: 3600, resolution: 1, group_by: "environment", group_by_function: "sum" }
|
|
184
|
+
# series = Appoptics::Metrics.get_series :requests, query
|
|
185
|
+
#
|
|
186
|
+
# @example Get series for metric grouped by tag and negated by tag filter
|
|
187
|
+
# query = { duration: 3600, resolution: 1, group_by: "environment", group_by_function: "sum", tags_search: "environment=!staging" }
|
|
188
|
+
# series = Appoptics::Metrics.get_series :requests, query
|
|
189
|
+
#
|
|
190
|
+
# @param [Symbol|String] metric_name Metric name
|
|
191
|
+
# @param [Hash] options Query options
|
|
192
|
+
def get_series(metric_name, options={})
|
|
193
|
+
raise ArgumentError, ":resolution and :duration or :start_time must be set" if options.empty?
|
|
194
|
+
query = options.dup
|
|
195
|
+
if query[:start_time].respond_to?(:year)
|
|
196
|
+
query[:start_time] = query[:start_time].to_i
|
|
197
|
+
end
|
|
198
|
+
if query[:end_time].respond_to?(:year)
|
|
199
|
+
query[:end_time] = query[:end_time].to_i
|
|
200
|
+
end
|
|
201
|
+
query[:resolution] ||= 1
|
|
202
|
+
unless query[:start_time] || query[:end_time]
|
|
203
|
+
query[:duration] ||= 3600
|
|
204
|
+
end
|
|
205
|
+
url = connection.build_url("measurements/#{metric_name}", query)
|
|
206
|
+
response = connection.get(url)
|
|
207
|
+
parsed = SmartJSON.read(response.body)
|
|
208
|
+
parsed["series"]
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# Retrieve data points for a specific metric
|
|
212
|
+
#
|
|
213
|
+
# @example Get 20 most recent data points for metric
|
|
214
|
+
# data = Appoptics::Metrics.get_measurements :temperature, count: 20
|
|
215
|
+
#
|
|
216
|
+
# @example Get the 20 most recent 15 minute data point rollups
|
|
217
|
+
# data = Appoptics::Metrics.get_measurements :temperature, count: 20,
|
|
218
|
+
# resolution: 900
|
|
219
|
+
#
|
|
220
|
+
# @example Get data points for the last hour
|
|
221
|
+
# data = Appoptics::Metrics.get_measurements start_time: Time.now-3600
|
|
222
|
+
#
|
|
223
|
+
# @example Get 15 min data points from two hours to an hour ago
|
|
224
|
+
# data = Appoptics::Metrics.get_measurements start_time: Time.now-7200,
|
|
225
|
+
# end_time: Time.now-3600,
|
|
226
|
+
# resolution: 900
|
|
227
|
+
#
|
|
228
|
+
# A full list of query parameters can be found in the API
|
|
229
|
+
# documentation: {http://docs.appoptics.com/api/#retrieve-a-metric}
|
|
230
|
+
#
|
|
231
|
+
# @param [Symbol|String] metric_name Metric name
|
|
232
|
+
# @param [Hash] options Query options
|
|
233
|
+
def get_measurements(metric_name, options = {})
|
|
234
|
+
raise ArgumentError, "you must provide at least a :start_time or :count" if options.empty?
|
|
235
|
+
get_metric(metric_name, options)["measurements"]
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
# Purge current credentials and connection.
|
|
239
|
+
#
|
|
240
|
+
def flush_authentication
|
|
241
|
+
self.api_key = nil
|
|
242
|
+
@connection = nil
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
# List currently existing metrics
|
|
246
|
+
#
|
|
247
|
+
# @example List all metrics
|
|
248
|
+
# Appoptics::Metrics.metrics
|
|
249
|
+
#
|
|
250
|
+
# @example List metrics with 'foo' in the name
|
|
251
|
+
# Appoptics::Metrics.metrics name: 'foo'
|
|
252
|
+
#
|
|
253
|
+
# @param [Hash] options
|
|
254
|
+
def metrics(options={})
|
|
255
|
+
query = {}
|
|
256
|
+
query[:name] = options[:name] if options[:name]
|
|
257
|
+
offset = 0
|
|
258
|
+
path = "metrics"
|
|
259
|
+
Collection.paginated_metrics(connection, path, query)
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
# Create a new queue which uses this client.
|
|
263
|
+
#
|
|
264
|
+
# @return [Queue]
|
|
265
|
+
def new_queue(options={})
|
|
266
|
+
options[:client] = self
|
|
267
|
+
Queue.new(options)
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
# Persistence type to use when saving metrics.
|
|
271
|
+
# Default is :direct.
|
|
272
|
+
#
|
|
273
|
+
# @return [Symbol]
|
|
274
|
+
def persistence
|
|
275
|
+
@persistence ||= :direct
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
# Set persistence type to use when saving metrics.
|
|
279
|
+
#
|
|
280
|
+
# @param [Symbol] persist_method
|
|
281
|
+
def persistence=(persist_method)
|
|
282
|
+
@persistence = persist_method
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
# Current persister object.
|
|
286
|
+
def persister
|
|
287
|
+
@queue ? @queue.persister : nil
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
# Submit all queued metrics.
|
|
291
|
+
#
|
|
292
|
+
def submit(args)
|
|
293
|
+
@queue ||= Queue.new(client: self,
|
|
294
|
+
skip_measurement_times: true,
|
|
295
|
+
clear_failures: true)
|
|
296
|
+
@queue.add args
|
|
297
|
+
@queue.submit
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
# Update a single metric with new attributes.
|
|
301
|
+
#
|
|
302
|
+
# @example Update metric 'temperature'
|
|
303
|
+
# Appoptics::Metrics.update_metric :temperature, period: 15, attributes: { color: 'F00' }
|
|
304
|
+
#
|
|
305
|
+
# @example Update metric 'humidity', creating it if it doesn't exist
|
|
306
|
+
# Appoptics::Metrics.update_metric 'humidity', type: :gauge, period: 60, display_name: 'Humidity'
|
|
307
|
+
#
|
|
308
|
+
def update_metric(metric, options = {})
|
|
309
|
+
url = "metrics/#{metric}"
|
|
310
|
+
connection.put do |request|
|
|
311
|
+
request.url connection.build_url(url)
|
|
312
|
+
request.body = SmartJSON.write(options)
|
|
313
|
+
end
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
# Update multiple metrics.
|
|
317
|
+
#
|
|
318
|
+
# @example Update multiple metrics by name
|
|
319
|
+
# Appoptics::Metrics.update_metrics names: ["foo", "bar"], period: 60
|
|
320
|
+
#
|
|
321
|
+
# @example Update all metrics that start with 'foo' that aren't 'foobar'
|
|
322
|
+
# Appoptics::Metrics.update_metrics names: 'foo*', exclude: ['foobar'], display_min: 0
|
|
323
|
+
#
|
|
324
|
+
def update_metrics(metrics)
|
|
325
|
+
url = "metrics" # update multiple metrics
|
|
326
|
+
connection.put do |request|
|
|
327
|
+
request.url connection.build_url(url)
|
|
328
|
+
request.body = SmartJSON.write(metrics)
|
|
329
|
+
end
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
# Retrive a snapshot, to check its progress or find its image_href
|
|
333
|
+
#
|
|
334
|
+
# @example Get a snapshot identified by 42
|
|
335
|
+
# Appoptics::Metrics.get_snapshot 42
|
|
336
|
+
#
|
|
337
|
+
# @param [Integer|String] id
|
|
338
|
+
def get_snapshot(id)
|
|
339
|
+
url = "snapshots/#{id}"
|
|
340
|
+
response = connection.get(url)
|
|
341
|
+
parsed = SmartJSON.read(response.body)
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
private
|
|
345
|
+
|
|
346
|
+
def default_faraday_adapter
|
|
347
|
+
if Metrics.client == self
|
|
348
|
+
Faraday.default_adapter
|
|
349
|
+
else
|
|
350
|
+
Metrics.faraday_adapter
|
|
351
|
+
end
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
def flush_persistence
|
|
355
|
+
@persistence = nil
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
end
|
|
361
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module Appoptics
|
|
2
|
+
module Metrics
|
|
3
|
+
|
|
4
|
+
# An internal class used for extracting pagination logic
|
|
5
|
+
#
|
|
6
|
+
# @api private
|
|
7
|
+
class Collection
|
|
8
|
+
|
|
9
|
+
MAX_RESULTS = 100
|
|
10
|
+
|
|
11
|
+
# Aggregates all results of paginated elements, requesting more collections as needed
|
|
12
|
+
#
|
|
13
|
+
# @param [Excon] connection Connection to Metrics service
|
|
14
|
+
# @param [String] path API uri
|
|
15
|
+
# @param [Hash] query Query options
|
|
16
|
+
def self.paginated_metrics(connection, path, query)
|
|
17
|
+
paginated_collection("metrics", connection, path, query)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.paginated_collection(name, connection, path, query)
|
|
21
|
+
results = []
|
|
22
|
+
# expects 200
|
|
23
|
+
url = connection.build_url(path, query)
|
|
24
|
+
response = connection.get(url)
|
|
25
|
+
parsed = SmartJSON.read(response.body)
|
|
26
|
+
results = parsed[name]
|
|
27
|
+
return results if parsed["query"]["found"] <= MAX_RESULTS
|
|
28
|
+
query[:offset] = MAX_RESULTS
|
|
29
|
+
begin
|
|
30
|
+
# expects 200
|
|
31
|
+
url = connection.build_url(path, query)
|
|
32
|
+
response = connection.get(url)
|
|
33
|
+
parsed = SmartJSON.read(response.body)
|
|
34
|
+
results.push(*parsed[name])
|
|
35
|
+
query[:offset] += MAX_RESULTS
|
|
36
|
+
end while query[:offset] < parsed["query"]["found"]
|
|
37
|
+
results
|
|
38
|
+
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
require 'faraday'
|
|
2
|
+
require 'metrics/middleware/count_requests'
|
|
3
|
+
require 'metrics/middleware/expects_status'
|
|
4
|
+
require 'metrics/middleware/request_body'
|
|
5
|
+
require 'metrics/middleware/retry'
|
|
6
|
+
|
|
7
|
+
module Appoptics
|
|
8
|
+
module Metrics
|
|
9
|
+
|
|
10
|
+
class Connection
|
|
11
|
+
extend Forwardable
|
|
12
|
+
|
|
13
|
+
DEFAULT_API_ENDPOINT = 'https://api.appoptics.com'
|
|
14
|
+
|
|
15
|
+
def_delegators :transport, :get, :post, :head, :put, :delete,
|
|
16
|
+
:build_url
|
|
17
|
+
|
|
18
|
+
def initialize(options={})
|
|
19
|
+
@client = options[:client]
|
|
20
|
+
@api_endpoint = options[:api_endpoint]
|
|
21
|
+
@adapter = options[:adapter]
|
|
22
|
+
@proxy = options[:proxy]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# API endpoint that will be used for requests.
|
|
26
|
+
#
|
|
27
|
+
def api_endpoint
|
|
28
|
+
@api_endpoint || DEFAULT_API_ENDPOINT
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def transport
|
|
32
|
+
raise(NoClientProvided, "No client provided.") unless @client
|
|
33
|
+
@transport ||= Faraday::Connection.new(
|
|
34
|
+
url: api_endpoint + "/v1/",
|
|
35
|
+
request: {open_timeout: 20, timeout: 30}) do |f|
|
|
36
|
+
|
|
37
|
+
f.use Appoptics::Metrics::Middleware::RequestBody
|
|
38
|
+
f.use Appoptics::Metrics::Middleware::Retry
|
|
39
|
+
f.use Appoptics::Metrics::Middleware::CountRequests
|
|
40
|
+
f.use Appoptics::Metrics::Middleware::ExpectsStatus
|
|
41
|
+
|
|
42
|
+
f.adapter @adapter || Metrics.faraday_adapter
|
|
43
|
+
f.proxy @proxy if @proxy
|
|
44
|
+
end.tap do |transport|
|
|
45
|
+
transport.headers[:user_agent] = user_agent
|
|
46
|
+
transport.headers[:content_type] = 'application/json'
|
|
47
|
+
transport.basic_auth @client.api_key, nil
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# User-agent used when making requests.
|
|
52
|
+
#
|
|
53
|
+
def user_agent
|
|
54
|
+
return @client.custom_user_agent if @client.custom_user_agent
|
|
55
|
+
ua_chunks = []
|
|
56
|
+
agent_identifier = @client.agent_identifier
|
|
57
|
+
if agent_identifier && !agent_identifier.empty?
|
|
58
|
+
ua_chunks << agent_identifier
|
|
59
|
+
end
|
|
60
|
+
ua_chunks << "appoptics-api-ruby/#{Metrics::VERSION}"
|
|
61
|
+
ua_chunks << "(#{ruby_engine}; #{RUBY_VERSION}p#{RUBY_PATCHLEVEL}; #{RUBY_PLATFORM})"
|
|
62
|
+
ua_chunks << "direct-faraday/#{Faraday::VERSION}"
|
|
63
|
+
# TODO: include adapter information
|
|
64
|
+
#ua_chunks << "(#{transport_adapter})"
|
|
65
|
+
ua_chunks.join(' ')
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
private
|
|
69
|
+
|
|
70
|
+
def adapter_version
|
|
71
|
+
adapter = transport_adapter
|
|
72
|
+
case adapter
|
|
73
|
+
when "NetHttp"
|
|
74
|
+
"Net::HTTP/#{Net::HTTP::Revision}"
|
|
75
|
+
when "Typhoeus"
|
|
76
|
+
"typhoeus/#{Typhoeus::VERSION}"
|
|
77
|
+
when "Excon"
|
|
78
|
+
"excon/#{Excon::VERSION}"
|
|
79
|
+
else
|
|
80
|
+
adapter
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def ruby_engine
|
|
85
|
+
return RUBY_ENGINE if Object.constants.include?(:RUBY_ENGINE)
|
|
86
|
+
RUBY_DESCRIPTION.split[0]
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# figure out which adapter faraday is using
|
|
90
|
+
def transport_adapter
|
|
91
|
+
transport.builder.handlers.each do |handler|
|
|
92
|
+
if handler.name[0,16] == "Faraday::Adapter"
|
|
93
|
+
return handler.name[18..-1]
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
end
|
|
101
|
+
end
|