quiz_api_client 4.1.0 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f901bb687e405ab11127e8cbbe476f38c3578d122d838b25438cc106287b4d83
4
- data.tar.gz: 6bae389bad7c912f709747a00a562e42cd10e4b85d1d72f5a7c5ffff6564ae61
3
+ metadata.gz: 9191c8a80cb0e2a654139c30e5e6ad3662e7589f6bf34a5b9f00b4517de22f99
4
+ data.tar.gz: 875e4bc7336dac500bbf699438ce9ad457680d6d3ce736b6aff3077efc495dfd
5
5
  SHA512:
6
- metadata.gz: 519030cead9c1d820cf40bb489029433f751ce41e6488dcddfd7a8520ea2c47c5fa7a8a96e0aaea59640793f0efcc7fcd825c3d5e2fbe026533cb9d18208fd18
7
- data.tar.gz: b906985f27f6e78e734f248685ae071efde9414cc3198d5a214caf9d54d8c1d2f29e6cc7d9e53677eac2c1c1d4d9bbd3016f3cea210173c1cf00628784d18507
6
+ metadata.gz: bf91a4c19851e9c1e4569f25be567ffae06bb91666da2d56cfc28fea0569cf55ce2706e18ebbb5ad38ce1ea9246eb348806f2fd05243250baa8573379ac9a843
7
+ data.tar.gz: aa366eff458ec1045bab8abae45d5a99bc374327a2d085a70fce32963e730b31d7a1f58ad5150f8978326b0b7608bb27c74b4a4ddde5e5bf3cbd25717ed463ff
data/CHANGELOG.md CHANGED
@@ -6,6 +6,13 @@ project adheres to [Semantic Versioning](http://semver.org/).
6
6
 
7
7
  [TOC]
8
8
 
9
+ #TODO: Enter the date
10
+ ## 4.2.0 ()
11
+
12
+ ### Changed
13
+ * Internal refactor of request error handling
14
+ * Added `metric_handler` and `metrics_namespace` to work with InstStatsd gem
15
+
9
16
  ## 4.1.0 (2021-10-27)
10
17
 
11
18
  ### Breaking changes (potentially)
data/README.md CHANGED
@@ -41,6 +41,10 @@ client = QuizApiClient::Client.new(
41
41
 
42
42
  In order to set addition error information in your error handling system, you can set the `error_hander` property of the config. The list of valid values can be found in the `QuizApiClient::Config::ERROR_HANDLERS` constant.
43
43
 
44
+ ### Metrics
45
+
46
+ HTTP Request metrics will now be provided if the `setup_metrics` method is called. The list of valid values can be found in the `QuizApiClient::Config::METRICS_HANDLERS` constant. The count and duration metrics will be provided under the namespace provided.
47
+
44
48
  ### Creation of Tokens
45
49
 
46
50
  JWTs are created without hitting quiz_api and and they are validated on quiz_api. Tokens are created for a given scope, expiration, and an optional resource_id.
@@ -3,10 +3,13 @@ module QuizApiClient
3
3
  DEFAULT_ALLOWABLE_RESPONSE_CODES = [401, 422].freeze
4
4
  DEFAULT_PROTOCOL = 'https'.freeze
5
5
  ERROR_HANDLERS = %i[sentry_raven].freeze
6
+ METRICS_HANDLERS = %i[inststatsd].freeze
6
7
 
7
8
  class InvalidErrorHandler < StandardError; end
9
+ class InvalidMetricsHandler < StandardError; end
10
+ class InvalidMetricsNamespace < StandardError; end
8
11
 
9
- attr_reader :error_handler
12
+ attr_reader :error_handler, :metrics_handler, :metrics_namespace
10
13
  attr_writer :protocol, :allowable_response_codes
11
14
  attr_accessor :consumer_key, :consumer_request_id, :host, :shared_secret
12
15
 
@@ -19,9 +22,17 @@ module QuizApiClient
19
22
  end
20
23
 
21
24
  def error_handler=(handler)
22
- validate_error_hander!(handler)
25
+ validate_error_handler!(handler)
23
26
 
24
- @error_handler = handler
27
+ @error_handler = handler.to_sym
28
+ end
29
+
30
+ def setup_metrics(handler, namespace)
31
+ validate_metrics_handler!(handler)
32
+ validate_metrics_namespace!(namespace)
33
+
34
+ @metrics_handler = handler.to_sym
35
+ @metrics_namespace = namespace.to_s.strip
25
36
  end
26
37
 
27
38
  def allowable_response_codes
@@ -30,14 +41,24 @@ module QuizApiClient
30
41
 
31
42
  private
32
43
 
33
- def validate_error_hander!(handler)
44
+ def validate_error_handler!(handler)
34
45
  return unless handler
46
+ return if ERROR_HANDLERS.include?(handler)
35
47
 
36
- unless ERROR_HANDLERS.include?(handler)
37
- raise InvalidErrorHandler, "It must be one of the following: #{ERROR_HANDLERS.inspect}"
38
- end
48
+ raise InvalidErrorHandler, "It must be one of the following: #{ERROR_HANDLERS.inspect}"
49
+ end
39
50
 
40
- @error_handler = handler.to_sym
51
+ def validate_metrics_handler!(handler)
52
+ return unless handler
53
+ return if METRICS_HANDLERS.include?(handler)
54
+
55
+ raise InvalidMetricsHandler, "It must be one of the following: #{METRICS_HANDLERS.inspect}"
56
+ end
57
+
58
+ def validate_metrics_namespace!(namespace)
59
+ return unless namespace.nil? || namespace.to_s.strip == ''
60
+
61
+ raise InvalidMetricsNamespace, 'It must be present'
41
62
  end
42
63
  end
43
64
  end
@@ -82,6 +82,7 @@ module QuizApiClient
82
82
  end
83
83
 
84
84
  def make_request(method, url, request_options = {})
85
+ start_time = Time.now
85
86
  resp = self.class.send(
86
87
  method,
87
88
  url,
@@ -91,6 +92,8 @@ module QuizApiClient
91
92
  resp
92
93
  rescue HTTParty::Error, Errno::ECONNREFUSED, Net::ReadTimeout => e
93
94
  raise_error(method, url, current_error: e)
95
+ ensure
96
+ record_metrics(method, url, resp, start_time, Time.now)
94
97
  end
95
98
 
96
99
  def make_paginated_request(method, url, options)
@@ -146,50 +149,18 @@ module QuizApiClient
146
149
  [url, options.merge(query: query)]
147
150
  end
148
151
 
149
- def generate_error_context(method, url, response = nil)
150
- context = {
151
- quiz_api_client: {
152
- request: {
153
- method: method,
154
- url: url
155
- }
156
- }
157
- }
158
-
159
- if response
160
- context[:quiz_api_client][:response] = {
161
- body: response.body,
162
- code: response.code
163
- }
164
- end
165
-
166
- context
167
- end
168
-
169
- def record_error_context(context)
170
- case config.error_handler
171
- when :sentry_raven
172
- require 'sentry-raven'
173
- Raven.extra_context(context)
174
- end
175
- end
152
+ def raise_error(method, url, response: nil, current_error: nil)
153
+ failure = QuizApiClient::HttpRequest::Failure.new(config)
176
154
 
177
- def error_message(current_error, url, response)
178
- if current_error && response
179
- "#{current_error.message}: #{url} responded #{response.body} (#{response.code})"
180
- elsif current_error
181
- current_error.message
182
- elsif response
183
- "#{url} responded #{response.body} (#{response.code})"
184
- end
155
+ failure.raise_error(method, url, response: response, current_error: current_error)
185
156
  end
186
157
 
187
- def raise_error(method, url, response: nil, current_error: nil, error_class: RequestFailed)
188
- context = generate_error_context(method, url, response)
189
-
190
- record_error_context(context)
158
+ def record_metrics(method, url, resp, start_time, end_time)
159
+ code = resp&.code || 0
160
+ metrics = QuizApiClient::HttpRequest::Metrics.new(config, method, url, code)
191
161
 
192
- raise error_class.new(context), error_message(current_error, url, response)
162
+ metrics.increment
163
+ metrics.duration(start_time, end_time)
193
164
  end
194
165
 
195
166
  def successful_response?(resp)
@@ -0,0 +1,65 @@
1
+ module QuizApiClient
2
+ module HttpRequest
3
+ class Failure
4
+ attr_reader :config
5
+
6
+ def initialize(config)
7
+ @config = config
8
+ end
9
+
10
+ def raise_error(
11
+ method,
12
+ url,
13
+ response: nil,
14
+ current_error: nil,
15
+ error_class: QuizApiClient::HttpClient::RequestFailed
16
+ )
17
+ context = generate_error_context(method, url, response)
18
+
19
+ record_error_context(context)
20
+
21
+ raise error_class.new(context), error_message(current_error, url, response)
22
+ end
23
+
24
+ private
25
+
26
+ def generate_error_context(method, url, response = nil)
27
+ context = {
28
+ quiz_api_client: {
29
+ request: {
30
+ method: method,
31
+ url: url
32
+ }
33
+ }
34
+ }
35
+
36
+ if response
37
+ context[:quiz_api_client][:response] = {
38
+ body: response.body,
39
+ code: response.code
40
+ }
41
+ end
42
+
43
+ context
44
+ end
45
+
46
+ def record_error_context(context)
47
+ case config.error_handler
48
+ when :sentry_raven
49
+ require 'sentry-raven'
50
+ Raven.extra_context(context)
51
+ end
52
+ end
53
+
54
+ def error_message(current_error, url, response)
55
+ if current_error && response
56
+ "#{current_error.message}: #{url} responded #{response.body} (#{response.code})"
57
+ elsif current_error
58
+ current_error.message
59
+ elsif response
60
+ "#{url} responded #{response.body} (#{response.code})"
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,67 @@
1
+ module QuizApiClient
2
+ module HttpRequest
3
+ class Metrics
4
+ extend Forwardable
5
+
6
+ attr_reader :config, :method, :url, :code
7
+ def_delegators :config, :metrics_handler, :metrics_namespace
8
+
9
+ def initialize(config, method, url, code)
10
+ @config = config
11
+ @method = method
12
+ @url = url
13
+ @code = code
14
+ end
15
+
16
+ def increment
17
+ return unless configured?
18
+
19
+ case metrics_handler
20
+ when :inststatsd
21
+ InstStatsd::Statsd.increment count_metric_name, tags: tags
22
+ end
23
+ end
24
+
25
+ def duration(start_time, end_time)
26
+ return unless configured?
27
+
28
+ duration_ms = ((end_time - start_time) * 1_000).round
29
+
30
+ case metrics_handler
31
+ when :inststatsd
32
+ InstStatsd::Statsd.timing duration_metric_name, duration_ms, tags: tags
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def configured?
39
+ metrics_handler_present? && metrics_namespace_present?
40
+ end
41
+
42
+ def count_metric_name
43
+ "#{metrics_namespace}.quiz_api_client.request.count"
44
+ end
45
+
46
+ def duration_metric_name
47
+ "#{metrics_namespace}.quiz_api_client.request.duration_ms"
48
+ end
49
+
50
+ def metrics_handler_present?
51
+ !metrics_handler.nil?
52
+ end
53
+
54
+ def metrics_namespace_present?
55
+ !metrics_namespace.nil?
56
+ end
57
+
58
+ def tags
59
+ {
60
+ method: method,
61
+ status: code,
62
+ url: url
63
+ }
64
+ end
65
+ end
66
+ end
67
+ end
@@ -1,3 +1,3 @@
1
1
  module QuizApiClient
2
- VERSION = '4.1.0'.freeze
2
+ VERSION = '4.2.0'.freeze
3
3
  end
@@ -101,6 +101,8 @@ require 'quiz_api_client/version'
101
101
  require 'quiz_api_client/config'
102
102
  require 'quiz_api_client/http_client'
103
103
  require 'quiz_api_client/json_formatter'
104
+ require 'quiz_api_client/http_request/failure'
105
+ require 'quiz_api_client/http_request/metrics'
104
106
  require 'quiz_api_client/services/jwt_service'
105
107
  require 'quiz_api_client/services/base_api_service'
106
108
 
@@ -48,6 +48,7 @@ Gem::Specification.new do |spec|
48
48
  spec.add_dependency 'jwt', '~> 2.2'
49
49
  spec.add_dependency 'link_header', '~> 0.0'
50
50
 
51
+ spec.add_development_dependency 'inst_statsd'
51
52
  spec.add_development_dependency 'pact', '~> 1.41'
52
53
  spec.add_development_dependency 'pact_broker-client', '~> 1.19'
53
54
  spec.add_development_dependency 'rake', '~> 12.3'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: quiz_api_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.0
4
+ version: 4.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Wang
@@ -20,7 +20,7 @@ authors:
20
20
  autorequire:
21
21
  bindir: exe
22
22
  cert_chain: []
23
- date: 2021-10-27 00:00:00.000000000 Z
23
+ date: 2021-11-19 00:00:00.000000000 Z
24
24
  dependencies:
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: httparty
@@ -64,6 +64,20 @@ dependencies:
64
64
  - - "~>"
65
65
  - !ruby/object:Gem::Version
66
66
  version: '0.0'
67
+ - !ruby/object:Gem::Dependency
68
+ name: inst_statsd
69
+ requirement: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ type: :development
75
+ prerelease: false
76
+ version_requirements: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
67
81
  - !ruby/object:Gem::Dependency
68
82
  name: pact
69
83
  requirement: !ruby/object:Gem::Requirement
@@ -214,6 +228,8 @@ files:
214
228
  - lib/quiz_api_client.rb
215
229
  - lib/quiz_api_client/config.rb
216
230
  - lib/quiz_api_client/http_client.rb
231
+ - lib/quiz_api_client/http_request/failure.rb
232
+ - lib/quiz_api_client/http_request/metrics.rb
217
233
  - lib/quiz_api_client/json_formatter.rb
218
234
  - lib/quiz_api_client/services/base_api_service.rb
219
235
  - lib/quiz_api_client/services/interaction_types_service.rb