quiz_api_client 4.1.0 → 4.2.0

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 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