atsd 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,11 @@
1
+ require 'atsd/errors/error'
2
+
3
+ module ATSD
4
+ class APIError < Error
5
+ attr_reader :status
6
+
7
+ def initialize(env)
8
+ @status = env.status
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ module ATSD
2
+ class Error < StandardError; end
3
+ end
@@ -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,7 @@
1
+ require 'atsd/models/base_model'
2
+
3
+ module ATSD
4
+ class Alert < BaseModel
5
+ end
6
+ end
7
+
@@ -0,0 +1,7 @@
1
+ require 'atsd/models/base_model'
2
+
3
+ module ATSD
4
+ class AlertHistory < BaseModel
5
+ end
6
+ end
7
+
@@ -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,7 @@
1
+ require 'atsd/models/base_model'
2
+
3
+ module ATSD
4
+ class Entity < BaseModel
5
+ end
6
+ end
7
+
@@ -0,0 +1,8 @@
1
+ require 'atsd/models/base_model'
2
+ require 'atsd/models/entity'
3
+
4
+ module ATSD
5
+ class EntityGroup < BaseModel
6
+ end
7
+ end
8
+
@@ -0,0 +1,7 @@
1
+ require 'atsd/models/base_model'
2
+
3
+ module ATSD
4
+ class Metric < BaseModel
5
+ end
6
+ end
7
+
@@ -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,8 @@
1
+ require 'atsd/models/base_model'
2
+
3
+ module ATSD
4
+ # Time Series model
5
+ class Series < BaseModel
6
+ end
7
+ end
8
+
@@ -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
+