pisoni 1.23.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +9 -0
  3. data/Gemfile +16 -0
  4. data/LICENSE +202 -0
  5. data/Makefile +73 -0
  6. data/NOTICE +15 -0
  7. data/README.md +47 -0
  8. data/Rakefile +27 -0
  9. data/lib/3scale/core/alert_limit.rb +32 -0
  10. data/lib/3scale/core/api_client/attributes.rb +56 -0
  11. data/lib/3scale/core/api_client/collection.rb +19 -0
  12. data/lib/3scale/core/api_client/operations.rb +233 -0
  13. data/lib/3scale/core/api_client/resource.rb +52 -0
  14. data/lib/3scale/core/api_client/support.rb +55 -0
  15. data/lib/3scale/core/api_client.rb +5 -0
  16. data/lib/3scale/core/application.rb +67 -0
  17. data/lib/3scale/core/application_key.rb +34 -0
  18. data/lib/3scale/core/application_referrer_filter.rb +33 -0
  19. data/lib/3scale/core/errors.rb +130 -0
  20. data/lib/3scale/core/event.rb +26 -0
  21. data/lib/3scale/core/logger.rb +12 -0
  22. data/lib/3scale/core/metric.rb +32 -0
  23. data/lib/3scale/core/service.rb +82 -0
  24. data/lib/3scale/core/service_error.rb +34 -0
  25. data/lib/3scale/core/service_token.rb +39 -0
  26. data/lib/3scale/core/transaction.rb +26 -0
  27. data/lib/3scale/core/usage_limit.rb +40 -0
  28. data/lib/3scale/core/user.rb +47 -0
  29. data/lib/3scale/core/utilization.rb +28 -0
  30. data/lib/3scale/core/version.rb +5 -0
  31. data/lib/3scale/core.rb +63 -0
  32. data/lib/3scale_core.rb +1 -0
  33. data/lib/pisoni.rb +5 -0
  34. data/pisoni.gemspec +43 -0
  35. data/spec/alert_limit_spec.rb +72 -0
  36. data/spec/application_key_spec.rb +97 -0
  37. data/spec/application_referrer_filter_spec.rb +57 -0
  38. data/spec/application_spec.rb +188 -0
  39. data/spec/event_spec.rb +82 -0
  40. data/spec/metric_spec.rb +115 -0
  41. data/spec/private_endpoints/event.rb +9 -0
  42. data/spec/private_endpoints/service_error.rb +10 -0
  43. data/spec/private_endpoints/transaction.rb +16 -0
  44. data/spec/service_error_spec.rb +128 -0
  45. data/spec/service_spec.rb +159 -0
  46. data/spec/service_token_spec.rb +121 -0
  47. data/spec/spec_helper.rb +15 -0
  48. data/spec/transaction_spec.rb +71 -0
  49. data/spec/usagelimit_spec.rb +52 -0
  50. data/spec/user_spec.rb +164 -0
  51. data/spec/utilization_spec.rb +113 -0
  52. metadata +182 -0
@@ -0,0 +1,233 @@
1
+ module ThreeScale
2
+ module Core
3
+ module APIClient
4
+ module Operations
5
+ def self.included(base)
6
+ base.extend ClassMethods
7
+ base.prepend Initializer
8
+ end
9
+
10
+ private
11
+
12
+ attr_accessor :persisted
13
+
14
+ def api_save(api_options = {})
15
+ if persisted
16
+ ret = self.class.api_do_put attributes, api_options
17
+ else
18
+ ret = self.class.api_do_post attributes, api_options
19
+ self.persisted = ret[:ok]
20
+ end
21
+ if ret[:ok]
22
+ update_attributes(ret[:attributes])
23
+ self.dirty = false
24
+ true
25
+ else
26
+ false
27
+ end
28
+ end
29
+
30
+ def api_delete(api_options = {})
31
+ ok = self.class.api_delete attributes, api_options
32
+ self.persisted = false if ok
33
+ ok
34
+ end
35
+
36
+ module Initializer
37
+ def initialize(*args)
38
+ self.persisted = false
39
+ super
40
+ end
41
+ end
42
+
43
+ module ClassMethods
44
+ include ThreeScale::Core::Logger
45
+
46
+ # CRUD methods
47
+
48
+ def api_create(attributes, api_options = {}, &blk)
49
+ api_create_object :api_do_post, attributes, api_options, &blk
50
+ end
51
+ alias_method :api_save, :api_create
52
+
53
+ def api_read(attributes, api_options = {}, &blk)
54
+ api_create_object :api_do_get, attributes, api_options, &blk
55
+ end
56
+ alias_method :api_load, :api_read
57
+
58
+ def api_update(attributes, api_options = {}, &blk)
59
+ api_create_object :api_do_put, attributes, api_options, &blk
60
+ end
61
+
62
+ def api_delete(attributes, api_options = {}, &blk)
63
+ api_do_delete(attributes, api_options, &blk)[:ok]
64
+ end
65
+
66
+ # Helpers
67
+
68
+ def api_do_get(attributes, api_options = {}, &blk)
69
+ blk = filter_404 if blk.nil?
70
+ api :get, attributes, api_options, &blk
71
+ end
72
+
73
+ def api_do_put(attributes, api_options = {}, &blk)
74
+ api :put, attributes, api_options, &blk
75
+ end
76
+
77
+ def api_do_post(attributes, api_options = {}, &blk)
78
+ api :post, attributes, api_options, &blk
79
+ end
80
+
81
+ def api_do_delete(attributes, api_options = {}, &blk)
82
+ blk = filter_404 if blk.nil?
83
+ api :delete, attributes, api_options, &blk
84
+ end
85
+
86
+ def api_create_object(method, attributes, api_options = {}, &blk)
87
+ ret = send method, attributes, api_options.merge(build: true), &blk
88
+ ret[:object].send :persisted=, true if ret[:object]
89
+ ret[:object]
90
+ end
91
+
92
+ def filter_404
93
+ @filter_404_proc ||= proc do |result|
94
+ result[:response].status != 404
95
+ end
96
+ end
97
+ private :filter_404
98
+
99
+ def api_http(method, uri, attributes)
100
+ # GET, DELETE and HEAD are treated differently by Faraday. We need
101
+ # to set the body in there.
102
+ if method == :get or method == :delete
103
+ Core.faraday.send method, uri do |req|
104
+ req.body = attributes.to_json
105
+ end
106
+ else
107
+ Core.faraday.send method, uri, attributes.to_json
108
+ end
109
+ rescue Faraday::Error::ClientError, SystemCallError => e
110
+ raise ConnectionError, e
111
+ end
112
+ private :api_http
113
+
114
+ def api_parse_json(response)
115
+ raise JSONError, "unacceptable content-type #{response.headers['content-type']} (#{response.headers['server']}): #{response.body[0,512]}" unless response.headers['content-type'].include? 'json'
116
+ parse_json(response.body)
117
+ rescue JSON::ParserError => e
118
+ # you can obtain the error message with
119
+ # rescue JSONError => e
120
+ # puts(e.cause ? e.cause.message : e.message)
121
+ #
122
+ # e.message will always return a trimmed (bounded) message, while
123
+ # e.cause.message, when a cause is present, may return a long
124
+ # message including the whole response body.
125
+ raise JSONError, e
126
+ end
127
+ private :api_parse_json
128
+
129
+ # Our current HTTP client (Faraday wrapper) does not expose HTTP
130
+ # version, which would be convenient for determining whether we have
131
+ # a keep-alive connection. For that we would probably need to write a
132
+ # Faraday middleware.
133
+ #
134
+ # Anyway, in HTTP/1.0 we are not guaranteed to have a Connection:
135
+ # response field, so it does not always use Connection: close (they
136
+ # are closed by default). HTTP/1.1 OTOH does keep-alive by default, so
137
+ # it will close the connection when actually sending a Connection:
138
+ # close. So:
139
+ # HTTP/1.1: KA if no Connection field or if present and not 'close'
140
+ # HTTP/1.0: no KA unless Connection: keep-alive.
141
+ # XXX UNDEFINED: no Connection header, depends on HTTP version:
142
+ # 1.1: keep-alive
143
+ # 1.0: close
144
+ def keep_alive_response?(response)
145
+ response.headers['connection'] != 'close'
146
+ end
147
+ private :keep_alive_response?
148
+
149
+ def api_response_inspect(method, uri, response, attributes, after, before)
150
+ "<#{keep_alive_response?(response) ? '=' : '/'}= #{response.status} #{method.upcase} #{uri} [#{attributes}] (#{after - before})"
151
+ end
152
+ private :api_response_inspect
153
+
154
+ # api method - talk with the remote HTTP service
155
+ #
156
+ # method - HTTP method to use
157
+ # attributes - HTTP request body parameters
158
+ # options:
159
+ # :prefix => string/symbol - an attribute prefix, '' for none, else default_prefix
160
+ # :rprefix => string/symbol - same as above, but for parsing responses
161
+ # :uri => string - sets the uri for this particular request
162
+ # :raise => boolean - raise APIError on error, defaults to true
163
+ # :build => boolean - create a new object with response's JSON if response is ok, defaults to false
164
+ # block (optional) - receives two params: http status code and attributes
165
+ # this block if present handles error responses, invalidates :raise option,
166
+ # you should return an array of [raise (boolean), built_object (if any) or nil]
167
+ #
168
+ # returns:
169
+ # a hash consisting of:
170
+ # :response - http response
171
+ # :response_json - http response parsed JSON
172
+ # :ok - whether the response code was ok when related to the http method
173
+ # :object - nil or the object created if applicable
174
+ # :attributes - JSON parsed attributes of the response's body
175
+
176
+ def api(method, attributes, options = {})
177
+ prefix = options.fetch(:prefix, default_prefix)
178
+ attributes = { prefix => attributes } unless prefix.empty? or attributes.empty?
179
+ uri = options.fetch(:uri, default_uri)
180
+
181
+ logger.debug do
182
+ "==> #{method.upcase} #{uri} [#{attributes}]"
183
+ end
184
+
185
+ before = Time.now
186
+ response = api_http method, uri, attributes
187
+ after = Time.now
188
+
189
+ ok = status_ok? method, uri, response
190
+
191
+ response_json = begin
192
+ api_parse_json(response)
193
+ rescue JSONError => e
194
+ logger.error do
195
+ "#{api_response_inspect(method, uri, response, '', after, before)} - #{e.message}"
196
+ end
197
+ raise e
198
+ end
199
+
200
+ ret = { response: response, response_json: response_json, ok: ok }
201
+
202
+ logger.debug do
203
+ api_response_inspect(method, uri, response, response_json, after, before)
204
+ end
205
+
206
+ if ok
207
+ prefix = options.fetch(:rprefix, prefix)
208
+ attributes = response_json.fetch(prefix, nil) unless prefix.empty?
209
+
210
+ ret[:object] = if attributes and options[:build]
211
+ new attributes
212
+ else
213
+ nil
214
+ end
215
+ else
216
+ # something went wrong. let's either let the user fix it, and ask him to provide us
217
+ # with directions returned from block or just use :raise
218
+ do_raise = if block_given?
219
+ yield(ret)
220
+ else
221
+ options.fetch(:raise, true)
222
+ end
223
+ raise APIError.new(method, uri, response, response_json) if do_raise
224
+ end
225
+
226
+ ret[:attributes] = attributes
227
+ ret
228
+ end
229
+ end
230
+ end
231
+ end
232
+ end
233
+ end
@@ -0,0 +1,52 @@
1
+ module ThreeScale
2
+ module Core
3
+ module APIClient
4
+ Error = Class.new StandardError
5
+
6
+ class APIError < Error
7
+ attr_reader :method, :uri, :response, :attributes
8
+
9
+ def initialize(method, uri, response, attributes)
10
+ @method, @uri, @response, @attributes = method, uri, response, attributes
11
+ super "#{self.class}: #{response.status} #{method.upcase} #{uri}, attributes:" \
12
+ " #{attributes.inspect}, response.body: #{response.body[0,256]}"
13
+ end
14
+ end
15
+
16
+ class APIServerError < APIError
17
+ def initialize(method, uri, response, attributes = {})
18
+ super
19
+ end
20
+ end
21
+
22
+ APIInternalServerError = Class.new APIServerError
23
+ APIBadGatewayError = Class.new APIServerError
24
+ APIServiceUnavailableError = Class.new APIServerError
25
+
26
+ class ConnectionError < Error
27
+ def initialize(error)
28
+ super "#{self.class}: #{error.message}"
29
+ end
30
+ end
31
+
32
+ class JSONError < Error
33
+ def initialize(error)
34
+ msg = error.respond_to?(:message) ? error.message : error
35
+ super "#{self.class}: #{msg[0,512]}"
36
+ end
37
+ end
38
+
39
+ class Resource
40
+
41
+ include Attributes
42
+ include Support
43
+ include Operations
44
+
45
+ def initialize(attributes)
46
+ update_attributes(attributes)
47
+ end
48
+
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,55 @@
1
+ module ThreeScale
2
+ module Core
3
+ module APIClient
4
+ module Support
5
+ def self.included(base)
6
+ base.extend ClassMethods
7
+ end
8
+
9
+ module ClassMethods
10
+ def status_ok?(method, uri, response)
11
+ status = response.status
12
+ # handle server errors here, since we will not be expecting JSON
13
+ raise internal_api_error(status).new(method, uri, response) if status >= 500
14
+ case method
15
+ when :post then [200, 201]
16
+ when :put then [200, 204, 202]
17
+ when :delete then [200, 204, 202]
18
+ else [200]
19
+ end.include? status
20
+ end
21
+
22
+ def parse_json(body)
23
+ JSON.parse(body, symbolize_names: true)
24
+ end
25
+
26
+ def default_uri(uri = nil)
27
+ return @default_uri ||= "/internal/#{self.to_s.split(':').last.downcase!}s/" unless uri
28
+ @default_uri = uri
29
+ end
30
+
31
+ def default_http_error_exception(exception = nil)
32
+ return @default_http_error_exception ||= APIError unless exception
33
+ @default_http_error_exception = exception
34
+ end
35
+
36
+ def default_prefix(prefix = nil)
37
+ return @default_prefix ||= self.to_s.split(':').last.downcase.to_sym unless prefix
38
+ @default_prefix = prefix
39
+ end
40
+
41
+ private
42
+
43
+ def internal_api_error(status)
44
+ case status
45
+ when 503 then APIServiceUnavailableError
46
+ when 502 then APIBadGatewayError
47
+ when 500 then APIInternalServerError
48
+ else APIServerError
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,5 @@
1
+ require '3scale/core/api_client/attributes'
2
+ require '3scale/core/api_client/support'
3
+ require '3scale/core/api_client/operations'
4
+ require '3scale/core/api_client/resource'
5
+ require '3scale/core/api_client/collection'
@@ -0,0 +1,67 @@
1
+ module ThreeScale
2
+ module Core
3
+ class Application < APIClient::Resource
4
+ ## added the :user_required to distinguish between types of application:
5
+ ## false is the default value, do not expect user_id or ignore it if it happends
6
+ ## true, the user_id must be defined + the user of the service (service_id#user_id),
7
+ ## user_id is typically the UUID of a cellphone, or the twitter account
8
+ attributes :service_id, :id, :state, :plan_id, :plan_name,
9
+ :redirect_url, :user_required
10
+
11
+ default_uri '/internal/services/'
12
+
13
+ def self.base_uri(service_id)
14
+ "#{default_uri}#{service_id}/applications/"
15
+ end
16
+ private_class_method :base_uri
17
+
18
+ def self.app_uri(service_id, id)
19
+ "#{base_uri(service_id)}#{id}"
20
+ end
21
+ private_class_method :app_uri
22
+
23
+ def self.key_uri(service_id, key)
24
+ "#{base_uri(service_id)}key/#{key}"
25
+ end
26
+ private_class_method :key_uri
27
+
28
+ def self.load(service_id, id)
29
+ api_read({}, uri: app_uri(service_id, id))
30
+ end
31
+
32
+ def self.save(attributes)
33
+ service_id, id = attributes.fetch(:service_id), attributes.fetch(:id)
34
+ api_update attributes, uri: app_uri(service_id, id)
35
+ end
36
+
37
+ def self.delete(service_id, id)
38
+ api_delete({}, uri: app_uri(service_id, id))
39
+ end
40
+
41
+ def save
42
+ api_save uri: self.class.send(:app_uri, service_id, id)
43
+ end
44
+
45
+ def user_required?
46
+ user_required
47
+ end
48
+
49
+ # XXX Old API. Just returns an id. DEPRECATED.
50
+ def self.load_id_by_key(service_id, user_key)
51
+ ret = api_do_get({}, uri: key_uri(service_id, user_key))
52
+ ret[:ok] ? ret[:attributes][:id] : nil
53
+ end
54
+
55
+ def self.save_id_by_key(service_id, user_key, id)
56
+ raise ApplicationHasInconsistentData.new(id, user_key) if (service_id.nil? || id.nil? || user_key.nil? || service_id=="" || id=="" || user_key=="")
57
+ ret = api_do_put({}, uri: "#{app_uri(service_id, id)}/key/#{user_key}")
58
+ ret[:ok]
59
+ end
60
+
61
+ def self.delete_id_by_key(service_id, user_key)
62
+ api_delete({}, uri: key_uri(service_id, user_key))
63
+ end
64
+
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,34 @@
1
+ module ThreeScale
2
+ module Core
3
+ class ApplicationKey < APIClient::Resource
4
+ attributes :service_id, :application_id, :value
5
+
6
+ default_uri '/internal/services/'
7
+
8
+ def self.load_all(service_id, application_id)
9
+ results = api_do_get({}, rprefix: :application_keys, uri: application_key_uri(service_id, application_id))
10
+ return [] if results[:attributes].is_a?(Hash) && results[:attributes][:error]
11
+
12
+ results[:attributes].map { |attrs| new(attrs) }
13
+ end
14
+
15
+ def self.save(service_id, application_id, value)
16
+ api_save({value: value}, uri: application_key_uri(service_id, application_id), prefix: :application_key)
17
+ end
18
+
19
+ def self.delete(service_id, application_id, value)
20
+ api_delete({}, uri: application_key_uri(service_id, application_id, value))
21
+ end
22
+
23
+ def self.base_uri(service_id, application_id)
24
+ "#{default_uri}#{service_id}/applications/#{application_id}/keys/"
25
+ end
26
+ private_class_method :base_uri
27
+
28
+ def self.application_key_uri(service_id, application_id, value = nil)
29
+ "#{base_uri(service_id, application_id)}#{value}"
30
+ end
31
+ private_class_method :application_key_uri
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,33 @@
1
+ require 'base64'
2
+
3
+ module ThreeScale
4
+ module Core
5
+ class ApplicationReferrerFilter < APIClient::Resource
6
+ default_uri '/internal/services/'
7
+
8
+ def self.load_all(service_id, application_id)
9
+ results = api_do_get({},
10
+ rprefix: :referrer_filters,
11
+ uri: base_uri(service_id, application_id))
12
+ results[:attributes]
13
+ end
14
+
15
+ def self.save(service_id, application_id, value)
16
+ result = api_do_post({ referrer_filter: value },
17
+ uri: base_uri(service_id, application_id),
18
+ prefix: '')
19
+ result[:response_json][:referrer_filter]
20
+ end
21
+
22
+ def self.delete(service_id, application_id, value)
23
+ encoded_value = Base64.urlsafe_encode64(value)
24
+ api_delete({}, uri: base_uri(service_id, application_id) + "/#{encoded_value}")
25
+ end
26
+
27
+ def self.base_uri(service_id, application_id)
28
+ "#{default_uri}#{service_id}/applications/#{application_id}/referrer_filters"
29
+ end
30
+ private_class_method :base_uri
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,130 @@
1
+ module ThreeScale
2
+ module Core
3
+ class UnknownAPIEndpoint < RuntimeError; end
4
+
5
+ class Error < RuntimeError
6
+ def to_xml(options = {})
7
+ xml = Builder::XmlMarkup.new
8
+ xml.instruct! unless options[:skip_instruct]
9
+ xml.error(message, :code => code)
10
+
11
+ xml.target!
12
+ end
13
+
14
+ def code
15
+ self.class.code
16
+ end
17
+
18
+ def self.code
19
+ underscore(name[/[^:]*$/])
20
+ end
21
+
22
+ # TODO: move this over to some utility module.
23
+ def self.underscore(string)
24
+ # Code stolen from ActiveSupport
25
+ string.gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
26
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
27
+ downcase
28
+ end
29
+ end
30
+
31
+ NotFound = Class.new(Error)
32
+ Invalid = Class.new(Error)
33
+
34
+ class ApplicationHasInconsistentData < Error
35
+ def initialize(id, user_key)
36
+ super %(Application id="#{id}" with user_key="#{user_key}" has inconsistent data and could not be saved)
37
+ end
38
+ end
39
+
40
+ class ServiceRequiresDefaultUserPlan < Error
41
+ def initialize
42
+ super %(Services without the need for registered users require a default user plan)
43
+ end
44
+ end
45
+
46
+ class ServiceIsDefaultService < Error
47
+ def initialize(id = nil)
48
+ super %(Service id="#{id}" is the default service, must be removed forcefully or make it not default before removal)
49
+ end
50
+ end
51
+
52
+ class ServiceRequiresRegisteredUser < Error
53
+ def initialize(id = nil)
54
+ super %(Service id="#{id}" requires users to be registered before hand)
55
+ end
56
+ end
57
+
58
+ class UserRequiresUsername < Error
59
+ def initialize
60
+ super %(User requires username)
61
+ end
62
+ end
63
+
64
+ class UserRequiresServiceId < Error
65
+ def initialize
66
+ super %(User requires a service id)
67
+ end
68
+ end
69
+
70
+ class UserRequiresValidServiceId < Error
71
+ def initialize(id)
72
+ super %(Service id #{id} is invalid, user requires a valid id)
73
+ end
74
+ end
75
+
76
+ class UserRequiresDefinedPlan < Error
77
+ def initialize(plan_id, plan_name)
78
+ super %(User requires a defined plan, plan id: #{plan_id} plan name: #{plan_name})
79
+ end
80
+ end
81
+
82
+ class InvalidProviderKeys < Error
83
+ def initialize
84
+ super %(Provider keys are not valid, must be not nil and different)
85
+ end
86
+ end
87
+
88
+ class ProviderKeyExists < Error
89
+ def initialize(key)
90
+ super %(Provider key="#{key}" already exists)
91
+ end
92
+ end
93
+
94
+ class ProviderKeyNotFound < Error
95
+ def initialize(key)
96
+ super %(Provider key="#{key}" does not exist)
97
+ end
98
+ end
99
+
100
+ class UsageLimitInvalidPeriods < Error
101
+ def initialize(periods)
102
+ super %(UsageLimit invalid periods #{periods})
103
+ end
104
+ end
105
+
106
+ class InvalidPerPage < Error
107
+ def initialize
108
+ super %(per_page is not valid, must be positive)
109
+ end
110
+ end
111
+
112
+ class ServiceTokenRequiresServiceId < Error
113
+ def initialize
114
+ super 'ServiceToken is invalid, service ID cannot be blank'
115
+ end
116
+ end
117
+
118
+ class ServiceTokenRequiresToken < Error
119
+ def initialize
120
+ super 'ServiceToken is invalid, token cannot be blank'
121
+ end
122
+ end
123
+
124
+ class ServiceTokenMissingParameter < Error
125
+ def initialize(error_text)
126
+ super %(ServiceToken is invalid, #{error_text})
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,26 @@
1
+ module ThreeScale
2
+ module Core
3
+ class Event < APIClient::Resource
4
+ attributes :id, :type, :timestamp, :object
5
+
6
+ def self.load_all
7
+ results = api_do_get({}, rprefix: :events)
8
+ results[:attributes].map { |attrs| new attrs }
9
+ end
10
+
11
+ def self.delete(id)
12
+ api_delete({}, uri: event_uri(id))
13
+ end
14
+
15
+ def self.delete_upto(id)
16
+ results = api_do_delete({ upto_id: id }, prefix: '')
17
+ results[:response_json][:num_events]
18
+ end
19
+
20
+ def self.event_uri(id)
21
+ "#{default_uri}#{id}"
22
+ end
23
+ private_class_method :event_uri
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,12 @@
1
+ require 'injectedlogger'
2
+
3
+ module ThreeScale
4
+ module Core
5
+ module Logger
6
+ InjectedLogger.use(:error, :info, :debug) {}
7
+ InjectedLogger.after_injection do |logger|
8
+ logger.prefix = '[core]' unless logger.prefix
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,32 @@
1
+ module ThreeScale
2
+ module Core
3
+ class Metric < APIClient::Resource
4
+ attributes :service_id, :id, :parent_id, :name
5
+
6
+ default_uri '/internal/services/'
7
+
8
+ def self.base_uri(service_id)
9
+ "#{default_uri}#{service_id}/metrics/"
10
+ end
11
+ private_class_method :base_uri
12
+
13
+ def self.metric_uri(service_id, id)
14
+ "#{base_uri(service_id)}#{id}"
15
+ end
16
+ private_class_method :metric_uri
17
+
18
+ def self.load(service_id, id)
19
+ api_read({}, uri: metric_uri(service_id, id))
20
+ end
21
+
22
+ def self.save(attributes)
23
+ service_id, id = attributes.fetch(:service_id), attributes.fetch(:id)
24
+ api_update attributes, uri: metric_uri(service_id, id)
25
+ end
26
+
27
+ def self.delete(service_id, id)
28
+ api_delete({}, uri: metric_uri(service_id, id))
29
+ end
30
+ end
31
+ end
32
+ end