debian-mirror-gitlab/lib/gitlab/prometheus_client.rb

140 lines
3.9 KiB
Ruby
Raw Normal View History

2018-12-13 13:39:08 +05:30
# frozen_string_literal: true
2017-08-17 22:00:37 +05:30
module Gitlab
# Helper methods to interact with Prometheus network services & resources
2017-09-10 17:25:29 +05:30
class PrometheusClient
2018-03-27 19:54:05 +05:30
Error = Class.new(StandardError)
QueryError = Class.new(Gitlab::PrometheusClient::Error)
2019-05-18 00:54:41 +05:30
# Target number of data points for `query_range`.
# Please don't exceed the limit of 11000 data points
# See https://github.com/prometheus/prometheus/blob/91306bdf24f5395e2601773316945a478b4b263d/web/api/v1/api.go#L347
QUERY_RANGE_DATA_POINTS = 600
# Minimal value of the `step` parameter for `query_range` in seconds.
QUERY_RANGE_MIN_STEP = 60
2018-03-17 18:26:18 +05:30
attr_reader :rest_client, :headers
2017-08-17 22:00:37 +05:30
2018-03-17 18:26:18 +05:30
def initialize(rest_client)
@rest_client = rest_client
2017-08-17 22:00:37 +05:30
end
def ping
json_api_get('query', query: '1')
end
2019-05-18 00:54:41 +05:30
def proxy(type, args)
path = api_path(type)
get(path, args)
rescue RestClient::ExceptionWithResponse => ex
if ex.response
ex.response
else
raise PrometheusClient::Error, "Network connection error"
end
rescue RestClient::Exception
raise PrometheusClient::Error, "Network connection error"
end
2017-08-17 22:00:37 +05:30
def query(query, time: Time.now)
get_result('vector') do
2017-09-10 17:25:29 +05:30
json_api_get('query', query: query, time: time.to_f)
2017-08-17 22:00:37 +05:30
end
end
def query_range(query, start: 8.hours.ago, stop: Time.now)
2019-05-18 00:54:41 +05:30
start = start.to_f
stop = stop.to_f
step = self.class.compute_step(start, stop)
2017-08-17 22:00:37 +05:30
get_result('matrix') do
2019-05-18 00:54:41 +05:30
json_api_get(
'query_range',
query: query,
start: start,
end: stop,
step: step
)
2017-08-17 22:00:37 +05:30
end
end
2017-09-10 17:25:29 +05:30
def label_values(name = '__name__')
json_api_get("label/#{name}/values")
end
def series(*matches, start: 8.hours.ago, stop: Time.now)
json_api_get('series', 'match': matches, start: start.to_f, end: stop.to_f)
end
2019-05-18 00:54:41 +05:30
def self.compute_step(start, stop)
diff = stop - start
step = (diff / QUERY_RANGE_DATA_POINTS).ceil
[QUERY_RANGE_MIN_STEP, step].max
end
2017-08-17 22:00:37 +05:30
private
2019-05-18 00:54:41 +05:30
def api_path(type)
['api', 'v1', type].join('/')
2017-08-17 22:00:37 +05:30
end
2019-05-18 00:54:41 +05:30
def json_api_get(type, args = {})
path = api_path(type)
response = get(path, args)
2018-03-17 18:26:18 +05:30
handle_response(response)
rescue RestClient::ExceptionWithResponse => ex
2018-03-27 19:54:05 +05:30
if ex.response
handle_exception_response(ex.response)
else
raise PrometheusClient::Error, "Network connection error"
end
2018-03-17 18:26:18 +05:30
rescue RestClient::Exception
2018-03-27 19:54:05 +05:30
raise PrometheusClient::Error, "Network connection error"
2017-08-17 22:00:37 +05:30
end
2019-05-18 00:54:41 +05:30
def get(path, args)
rest_client[path].get(params: args)
rescue SocketError
raise PrometheusClient::Error, "Can't connect to #{rest_client.url}"
rescue OpenSSL::SSL::SSLError
raise PrometheusClient::Error, "#{rest_client.url} contains invalid SSL data"
rescue Errno::ECONNREFUSED
raise PrometheusClient::Error, 'Connection refused'
end
2017-08-17 22:00:37 +05:30
def handle_response(response)
2019-05-18 00:54:41 +05:30
json_data = parse_json(response.body)
2018-03-17 18:26:18 +05:30
if response.code == 200 && json_data['status'] == 'success'
json_data['data'] || {}
else
2018-03-27 19:54:05 +05:30
raise PrometheusClient::Error, "#{response.code} - #{response.body}"
2018-03-17 18:26:18 +05:30
end
end
def handle_exception_response(response)
2018-03-27 19:54:05 +05:30
if response.code == 200 && response['status'] == 'success'
response['data'] || {}
elsif response.code == 400
2019-05-18 00:54:41 +05:30
json_data = parse_json(response.body)
2018-03-27 19:54:05 +05:30
raise PrometheusClient::QueryError, json_data['error'] || 'Bad data received'
2017-08-17 22:00:37 +05:30
else
2018-03-27 19:54:05 +05:30
raise PrometheusClient::Error, "#{response.code} - #{response.body}"
2017-08-17 22:00:37 +05:30
end
end
def get_result(expected_type)
data = yield
data['result'] if data['resultType'] == expected_type
end
2019-05-18 00:54:41 +05:30
def parse_json(response_body)
JSON.parse(response_body)
rescue JSON::ParserError
raise PrometheusClient::Error, 'Parsing response failed'
end
2017-08-17 22:00:37 +05:30
end
end