atsd 1.0.1
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 +11 -0
- data/.rspec +2 -0
- data/Gemfile +8 -0
- data/README.md +365 -0
- data/Rakefile +16 -0
- data/atsd.gemspec +36 -0
- data/lib/atsd.rb +19 -0
- data/lib/atsd/atsd.rb +54 -0
- data/lib/atsd/client.rb +469 -0
- data/lib/atsd/errors/api_error.rb +11 -0
- data/lib/atsd/errors/error.rb +3 -0
- data/lib/atsd/middleware/errors_handler.rb +88 -0
- data/lib/atsd/models/alert.rb +7 -0
- data/lib/atsd/models/alert_history.rb +7 -0
- data/lib/atsd/models/base_model.rb +23 -0
- data/lib/atsd/models/entity.rb +7 -0
- data/lib/atsd/models/entity_group.rb +8 -0
- data/lib/atsd/models/metric.rb +7 -0
- data/lib/atsd/models/property.rb +11 -0
- data/lib/atsd/models/series.rb +8 -0
- data/lib/atsd/queries/alerts_history_query.rb +31 -0
- data/lib/atsd/queries/alerts_query.rb +31 -0
- data/lib/atsd/queries/base_query.rb +40 -0
- data/lib/atsd/queries/properties_query.rb +31 -0
- data/lib/atsd/queries/series_query.rb +150 -0
- data/lib/atsd/services/alerts_service.rb +88 -0
- data/lib/atsd/services/base_service.rb +15 -0
- data/lib/atsd/services/entities_service.rb +130 -0
- data/lib/atsd/services/entity_groups_service.rb +186 -0
- data/lib/atsd/services/metrics_service.rb +122 -0
- data/lib/atsd/services/properties_service.rb +63 -0
- data/lib/atsd/services/series_service.rb +53 -0
- data/lib/atsd/utils.rb +20 -0
- data/lib/atsd/utils/camelize_keys.rb +41 -0
- data/lib/atsd/utils/underscore_keys.rb +21 -0
- data/lib/atsd/version.rb +3 -0
- metadata +264 -0
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'atsd/errors/api_error'
|
2
|
+
|
3
|
+
module ATSD
|
4
|
+
# Faraday Middleware
|
5
|
+
module Middleware
|
6
|
+
# Middleware to raise error on request fail and possibly catch error message from API.
|
7
|
+
class ErrorsHandlerMiddleware < Faraday::Response::Middleware
|
8
|
+
# HTTP status codes with messages generated by
|
9
|
+
#
|
10
|
+
# ```bash
|
11
|
+
# curl -s www.iana.org/assignments/http-status-codes/http-status-codes-1.csv | \
|
12
|
+
# ruby -ne 'm = /^(\d{3}),(?!Unassigned|\(Unused\))([^,]+)/.match($_) and \
|
13
|
+
# puts "#{m[1]} => \x27#{m[2].strip}\x27,"'
|
14
|
+
# ```
|
15
|
+
HTTP_STATUS_CODES = {
|
16
|
+
100 => 'Continue',
|
17
|
+
101 => 'Switching Protocols',
|
18
|
+
102 => 'Processing',
|
19
|
+
200 => 'OK',
|
20
|
+
201 => 'Created',
|
21
|
+
202 => 'Accepted',
|
22
|
+
203 => 'Non-Authoritative Information',
|
23
|
+
204 => 'No Content',
|
24
|
+
205 => 'Reset Content',
|
25
|
+
206 => 'Partial Content',
|
26
|
+
207 => 'Multi-Status',
|
27
|
+
208 => 'Already Reported',
|
28
|
+
226 => 'IM Used',
|
29
|
+
300 => 'Multiple Choices',
|
30
|
+
301 => 'Moved Permanently',
|
31
|
+
302 => 'Found',
|
32
|
+
303 => 'See Other',
|
33
|
+
304 => 'Not Modified',
|
34
|
+
305 => 'Use Proxy',
|
35
|
+
307 => 'Temporary Redirect',
|
36
|
+
308 => 'Permanent Redirect',
|
37
|
+
400 => 'Bad Request',
|
38
|
+
401 => 'Unauthorized',
|
39
|
+
402 => 'Payment Required',
|
40
|
+
403 => 'Forbidden',
|
41
|
+
404 => 'Not Found',
|
42
|
+
405 => 'Method Not Allowed',
|
43
|
+
406 => 'Not Acceptable',
|
44
|
+
407 => 'Proxy Authentication Required',
|
45
|
+
408 => 'Request Timeout',
|
46
|
+
409 => 'Conflict',
|
47
|
+
410 => 'Gone',
|
48
|
+
411 => 'Length Required',
|
49
|
+
412 => 'Precondition Failed',
|
50
|
+
413 => 'Payload Too Large',
|
51
|
+
414 => 'URI Too Long',
|
52
|
+
415 => 'Unsupported Media Type',
|
53
|
+
416 => 'Range Not Satisfiable',
|
54
|
+
417 => 'Expectation Failed',
|
55
|
+
421 => 'Misdirected Request',
|
56
|
+
422 => 'Unprocessable Entity',
|
57
|
+
423 => 'Locked',
|
58
|
+
424 => 'Failed Dependency',
|
59
|
+
426 => 'Upgrade Required',
|
60
|
+
428 => 'Precondition Required',
|
61
|
+
429 => 'Too Many Requests',
|
62
|
+
431 => 'Request Header Fields Too Large',
|
63
|
+
500 => 'Internal Server Error',
|
64
|
+
501 => 'Not Implemented',
|
65
|
+
502 => 'Bad Gateway',
|
66
|
+
503 => 'Service Unavailable',
|
67
|
+
504 => 'Gateway Timeout',
|
68
|
+
505 => 'HTTP Version Not Supported',
|
69
|
+
506 => 'Variant Also Negotiates',
|
70
|
+
507 => 'Insufficient Storage',
|
71
|
+
508 => 'Loop Detected',
|
72
|
+
510 => 'Not Extended',
|
73
|
+
511 => 'Network Authentication Required',
|
74
|
+
}
|
75
|
+
|
76
|
+
def call(environment)
|
77
|
+
@app.call(environment).on_complete do |env|
|
78
|
+
unless env.success?
|
79
|
+
message = env.body['error'] || HTTP_STATUS_CODES[env.status]
|
80
|
+
fail APIError.new(env), message
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
Faraday::Response.register_middleware :errors_handler => ATSD::Middleware::ErrorsHandlerMiddleware
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module ATSD
|
2
|
+
# Base class for all models
|
3
|
+
# @abstract
|
4
|
+
class BaseModel < ::Hash
|
5
|
+
include ::Hashie::Extensions::MethodAccess
|
6
|
+
include ::Hashie::Extensions::MergeInitializer
|
7
|
+
include Utils::UnderscoreKeys
|
8
|
+
|
9
|
+
# Converts model to hash usable for API
|
10
|
+
#
|
11
|
+
# @return [Hash]
|
12
|
+
def to_request_hash
|
13
|
+
hash = {}
|
14
|
+
keys.each do |k|
|
15
|
+
new_key = k.to_s.camelize(:lower)
|
16
|
+
new_key = new_key.to_sym if k.is_a? Symbol
|
17
|
+
hash[new_key] = self[k]
|
18
|
+
end
|
19
|
+
hash
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'atsd/models/base_model'
|
2
|
+
|
3
|
+
module ATSD
|
4
|
+
# Property model
|
5
|
+
#
|
6
|
+
# @note Please use `property[:key]` instead of `property.key` to access
|
7
|
+
# `key` attribute due to implementation details (`#key` is a Hash method).
|
8
|
+
class Property < BaseModel
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'atsd/queries/base_query'
|
2
|
+
|
3
|
+
module ATSD
|
4
|
+
# Class for building and executing Alerts History Query
|
5
|
+
# @see https://axibase.com/atsd/api/#alerts:-history-query
|
6
|
+
class AlertsHistoryQuery < BaseQuery
|
7
|
+
TO_MILLISECONDS_LAMBDA = ->(v) do
|
8
|
+
case v
|
9
|
+
when Time
|
10
|
+
v.to_i * 1_000
|
11
|
+
else
|
12
|
+
v.to_i
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
coerce_key :end_time, TO_MILLISECONDS_LAMBDA
|
17
|
+
coerce_key :start_time, TO_MILLISECONDS_LAMBDA
|
18
|
+
|
19
|
+
# @return [Array<AlertHistory>]
|
20
|
+
def result
|
21
|
+
super
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return (see #result)
|
25
|
+
def execute
|
26
|
+
result = @client.alerts_history_query to_request_hash
|
27
|
+
@result = result.map { |json| AlertHistory.new json }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'atsd/queries/base_query'
|
2
|
+
|
3
|
+
module ATSD
|
4
|
+
# Class for building and executing Alerts Query
|
5
|
+
# @see https://axibase.com/atsd/api/#alerts:-query
|
6
|
+
class AlertsQuery < BaseQuery
|
7
|
+
# `severity` levels
|
8
|
+
module Severity
|
9
|
+
UNDEFINED = 0
|
10
|
+
UNKNOWN = 1
|
11
|
+
NORMAL = 2
|
12
|
+
WARNING = 3
|
13
|
+
MINOR = 4
|
14
|
+
MAJOR = 5
|
15
|
+
CRITICAL = 6
|
16
|
+
FATAL = 7
|
17
|
+
end
|
18
|
+
|
19
|
+
# @return [Array<Alert>]
|
20
|
+
def result
|
21
|
+
super
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return (see #result)
|
25
|
+
def execute
|
26
|
+
result = @client.alerts_query to_request_hash
|
27
|
+
@result = result.map { |json| Alert.new json }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module ATSD
|
2
|
+
# Base class for API query builders
|
3
|
+
# @abstract
|
4
|
+
class BaseQuery < ::Hashie::Clash
|
5
|
+
include ::Hashie::Extensions::Coercion
|
6
|
+
|
7
|
+
# @return [Client]
|
8
|
+
attr_reader :client
|
9
|
+
|
10
|
+
# @param [Client] client
|
11
|
+
def initialize(client)
|
12
|
+
@client = client
|
13
|
+
end
|
14
|
+
|
15
|
+
# Build request parameters hash
|
16
|
+
# @return [Hash]
|
17
|
+
def to_request_hash
|
18
|
+
Utils::CamelizeKeys.camelize_keys(self)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Execute query on client
|
22
|
+
# @return (see #result)
|
23
|
+
# @raise [APIError]
|
24
|
+
def execute
|
25
|
+
raise NotImplementedError
|
26
|
+
end
|
27
|
+
|
28
|
+
# Result of query execution.
|
29
|
+
#
|
30
|
+
# @return [Object]
|
31
|
+
# @raise [APIError]
|
32
|
+
def result
|
33
|
+
@result ||= execute
|
34
|
+
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
|
38
|
+
attr_writer :result
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'atsd/queries/base_query'
|
2
|
+
|
3
|
+
module ATSD
|
4
|
+
# Class for building and executing Properties Query
|
5
|
+
# @see https://axibase.com/atsd/api/#properties:-query
|
6
|
+
class PropertiesQuery < BaseQuery
|
7
|
+
TO_MILLISECONDS_LAMBDA = ->(v) do
|
8
|
+
case v
|
9
|
+
when Time
|
10
|
+
v.to_i * 1_000
|
11
|
+
else
|
12
|
+
v.to_i
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
coerce_key :end_time, TO_MILLISECONDS_LAMBDA
|
17
|
+
coerce_key :start_time, TO_MILLISECONDS_LAMBDA
|
18
|
+
|
19
|
+
# @return [Array<Property>]
|
20
|
+
def result
|
21
|
+
super
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return (see #result)
|
25
|
+
def execute
|
26
|
+
result = @client.properties_query to_request_hash
|
27
|
+
@result = result.map { |json| Property.new json }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
@@ -0,0 +1,150 @@
|
|
1
|
+
require 'atsd/queries/base_query'
|
2
|
+
|
3
|
+
module ATSD
|
4
|
+
# Class for building and executing Series Query
|
5
|
+
# @see https://axibase.com/atsd/api/#series:-query
|
6
|
+
class SeriesQuery < BaseQuery
|
7
|
+
|
8
|
+
# @!method type(type)
|
9
|
+
# specifies source for underlying data
|
10
|
+
# @param [String] type see {Type} for possible values
|
11
|
+
# @return [self]
|
12
|
+
|
13
|
+
# `type` parameter possible values
|
14
|
+
module Type
|
15
|
+
HISTORY = 'HISTORY' # default
|
16
|
+
FORECAST = 'FORECAST'
|
17
|
+
FORECAST_DEVIATION = 'FORECAST_DEVIATION'
|
18
|
+
end
|
19
|
+
|
20
|
+
# `join.type` parameter possible values
|
21
|
+
module JoinType
|
22
|
+
COUNT = 'COUNT'
|
23
|
+
MIN = 'MIN'
|
24
|
+
MAX = 'MAX'
|
25
|
+
AVG = 'AVG'
|
26
|
+
SUM = 'SUM'
|
27
|
+
PERCENTILE_999 = 'PERCENTILE_999'
|
28
|
+
PERCENTILE_995 = 'PERCENTILE_995'
|
29
|
+
PERCENTILE_99 = 'PERCENTILE_99'
|
30
|
+
PERCENTILE_95 = 'PERCENTILE_95'
|
31
|
+
PERCENTILE_90 = 'PERCENTILE_90'
|
32
|
+
PERCENTILE_75 = 'PERCENTILE_75'
|
33
|
+
PERCENTILE_50 = 'PERCENTILE_50'
|
34
|
+
STANDARD_DEVIATION = 'STANDARD_DEVIATION'
|
35
|
+
end
|
36
|
+
|
37
|
+
# `join.interpolate` parameter possible values
|
38
|
+
module JoinInterpolate
|
39
|
+
STEP = 'STEP' # default
|
40
|
+
NONE = 'NONE'
|
41
|
+
LINEAR = 'LINEAR'
|
42
|
+
end
|
43
|
+
|
44
|
+
# `aggregate.type` parameter possible values
|
45
|
+
module AggregateType
|
46
|
+
DETAIL = 'DETAIL'
|
47
|
+
COUNT = 'COUNT'
|
48
|
+
MIN = 'MIN'
|
49
|
+
MAX = 'MAX'
|
50
|
+
AVG = 'AVG'
|
51
|
+
SUM = 'SUM'
|
52
|
+
PERCENTILE_999 = 'PERCENTILE_999'
|
53
|
+
PERCENTILE_995 = 'PERCENTILE_995'
|
54
|
+
PERCENTILE_99 = 'PERCENTILE_99'
|
55
|
+
PERCENTILE_95 = 'PERCENTILE_95'
|
56
|
+
PERCENTILE_90 = 'PERCENTILE_90'
|
57
|
+
PERCENTILE_75 = 'PERCENTILE_75'
|
58
|
+
PERCENTILE_50 = 'PERCENTILE_50'
|
59
|
+
STANDARD_DEVIATION = 'STANDARD_DEVIATION'
|
60
|
+
FIRST = 'FIRST'
|
61
|
+
LAST = 'LAST'
|
62
|
+
DELTA = 'DELTA'
|
63
|
+
WAVG = 'WAVG'
|
64
|
+
WTAVG = 'WTAVG'
|
65
|
+
THRESHOLD_COUNT = 'THRESHOLD_COUNT'
|
66
|
+
THRESHOLD_DURATION = 'THRESHOLD_DURATION'
|
67
|
+
THRESHOLD_PERCENT = 'THRESHOLD_PERCENT'
|
68
|
+
end
|
69
|
+
|
70
|
+
# `aggregate.interpolate` parameter possible values
|
71
|
+
module AggregateInterpolate
|
72
|
+
STEP = 'STEP'
|
73
|
+
NONE = 'NONE'
|
74
|
+
LINEAR = 'LINEAR'
|
75
|
+
end
|
76
|
+
|
77
|
+
# interval's unit possible values
|
78
|
+
module Interval
|
79
|
+
MILLISECOND = 'MILLISECOND'
|
80
|
+
SECOND = 'SECOND'
|
81
|
+
MINUTE = 'MINUTE'
|
82
|
+
HOUR = 'HOUR'
|
83
|
+
DAY = 'DAY'
|
84
|
+
WEEK = 'WEEK'
|
85
|
+
MONTH = 'MONTH'
|
86
|
+
QUARTER = 'QUARTER'
|
87
|
+
YEAR = 'YEAR'
|
88
|
+
end
|
89
|
+
|
90
|
+
TO_MILLISECONDS_LAMBDA = ->(v) do
|
91
|
+
case v
|
92
|
+
when Time
|
93
|
+
v.to_i * 1_000
|
94
|
+
else
|
95
|
+
v.to_i
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
coerce_key :end_time, TO_MILLISECONDS_LAMBDA
|
100
|
+
coerce_key :start_time, TO_MILLISECONDS_LAMBDA
|
101
|
+
|
102
|
+
# @return [Array<Series>]
|
103
|
+
def result
|
104
|
+
super
|
105
|
+
end
|
106
|
+
|
107
|
+
# Add tag to `tags` parameter
|
108
|
+
#
|
109
|
+
# @param [String] name tag name
|
110
|
+
# @param [String, Array<String>] values possible tag value of array of values.
|
111
|
+
# `*` and `?` wildcards allowed.
|
112
|
+
# @return [self]
|
113
|
+
def tag_add(name, values)
|
114
|
+
self[:tags][name] = Utils.ensure_array(values)
|
115
|
+
self
|
116
|
+
end
|
117
|
+
|
118
|
+
# Executes query and sets `result` attribute.
|
119
|
+
#
|
120
|
+
# @return (see #result)
|
121
|
+
def execute
|
122
|
+
result = @client.series_query to_request_hash
|
123
|
+
@result = result.map { |series_json| Series.new series_json }
|
124
|
+
end
|
125
|
+
|
126
|
+
# Executes multiple queries at the same time. Adds `request_id` parameter
|
127
|
+
# to each query if necessary. All queries will have a corresponding `series`
|
128
|
+
# attribute set.
|
129
|
+
#
|
130
|
+
# @param [SeriesQuery] others list of series query to execute with receiver
|
131
|
+
# @return [Array<Series>] all results
|
132
|
+
def execute_with(*others)
|
133
|
+
others ||= []
|
134
|
+
queries = [self] + others
|
135
|
+
queries_by_id = {}
|
136
|
+
if queries.count > 1
|
137
|
+
queries.each_with_index do |query, index|
|
138
|
+
query.request_id("query_#{index}") unless query.request_id
|
139
|
+
query.result = []
|
140
|
+
queries_by_id[query[:request_id]] = query
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
results = @client.series_query queries.map {|q| q.to_request_hash}
|
145
|
+
results.map! { |json| Series.new(json) }
|
146
|
+
results.each { |r| queries_by_id[r.request_id].result << r }
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|