pricehubble 0.1.0 → 0.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: 3a6dec9a50e1bc53530adc56e69bccf3c0309b0c38b8819be5862ac01b78aa24
4
- data.tar.gz: edb1ce1a5667290d8d8481edfeb41c39cffc09d35efea6a7e6f1d81f38f00095
3
+ metadata.gz: 708dc6002a8c92bc8cdcebbfd1d580c72d199644f343a650d19d9229dd90e86c
4
+ data.tar.gz: 59ea57131a818d6fa7af30743963c9e991b167a9e0d364bae6727dc86d91cd72
5
5
  SHA512:
6
- metadata.gz: 4c02c6a1153849bbad1f2ba7f171a5b526be7fb6d42001f7419099901df2bf80abb61943948e3a2322e92ab202ef96122533f2c4887fd1c385db6fd3c4c897a9
7
- data.tar.gz: ee651835c4f91e894a9967d5477cb44a9efb13dc64dbb3cde557b6315c71b8837806f6a9c3c2356e772c3a4b5e202870a8d7f7e399ea972cc336da1647e91386
6
+ metadata.gz: b416c6035d36d6266ab6968bd445feb5f964d1af09d9feff852cd998f34d5054ae33962e878fc6d1128ef6e19557154da22372a157f3e492a6bb37b936717dbe
7
+ data.tar.gz: 3511f1a0bdad3da7ce4f58214e59cc34b159b8012441df368193bff5b162ff6d799a49c5a0fbd6abd65c09f875c2ea1e7000d9c1a67c85a4fd034f5e3d28dfe0
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ### 0.2.0
2
+
3
+ * Added a configuration for request logging which is enabled by default now
4
+ * Implemented a generic instrumentation facility
5
+ * Improved the instrumentation and request logging facility (logs are colored
6
+ now to make local development easier and error handling was added to be more
7
+ robust on response issues)
8
+
1
9
  ### 0.1.0
2
10
 
3
11
  * Implemented a transparent authentication handling
data/README.md CHANGED
@@ -65,8 +65,11 @@ PriceHubble.configure do |conf|
65
65
  # endpoint we know about)
66
66
  conf.base_url = 'https://api.pricehubble.com'
67
67
 
68
- # Writes to stdout by default
68
+ # Writes to stdout by default, or use the Rails logger if present
69
69
  conf.logger = Logger.new(IO::NULL)
70
+
71
+ # Enable request logging or not
72
+ conf.request_logging = true
70
73
  end
71
74
  ```
72
75
 
data/lib/pricehubble.rb CHANGED
@@ -25,6 +25,7 @@ module PriceHubble
25
25
  autoload :ConfigurationHandling, 'pricehubble/configuration_handling'
26
26
  autoload :Client, 'pricehubble/client'
27
27
  autoload :Identity, 'pricehubble/identity'
28
+ autoload :Instrumentation, 'pricehubble/instrumentation'
28
29
 
29
30
  # Entities
30
31
  autoload :BaseEntity, 'pricehubble/entity/base_entity'
@@ -46,6 +47,11 @@ module PriceHubble
46
47
  autoload :Bangers, 'pricehubble/utils/bangers'
47
48
  end
48
49
 
50
+ # Instrumentation
51
+ module Instrumentation
52
+ autoload :LogSubscriber, 'pricehubble/instrumentation/log_subscriber'
53
+ end
54
+
49
55
  # Dedicated application HTTP (low level) client
50
56
  module Client
51
57
  # All our utilities used for the low level client
@@ -100,4 +106,5 @@ module PriceHubble
100
106
  include PriceHubble::ConfigurationHandling
101
107
  include PriceHubble::Client
102
108
  include PriceHubble::Identity
109
+ include PriceHubble::Instrumentation
103
110
  end
@@ -22,5 +22,8 @@ module PriceHubble
22
22
 
23
23
  Logger.new($stdout)
24
24
  end
25
+
26
+ # Enable request logging or not
27
+ config_accessor(:request_logging) { true }
25
28
  end
26
29
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PriceHubble
4
+ # Some instrumentation and logging facility helpers.
5
+ module Instrumentation
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ # Add the log subscriber to the faraday namespace
10
+ PriceHubble::Instrumentation::LogSubscriber.attach_to :faraday
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PriceHubble
4
+ module Instrumentation
5
+ # Produce logs for requests.
6
+ class LogSubscriber < ActiveSupport::LogSubscriber
7
+ # Return the PriceHubble SDK configured logger when logging is enabled.
8
+ # Otherwise +nil+ is returned and the subscriber is never started.
9
+ #
10
+ # @return [Logger, nil] the logger to use
11
+ def logger
12
+ return unless PriceHubble.configuration.request_logging
13
+
14
+ PriceHubble.configuration.logger
15
+ end
16
+
17
+ # Log request statistics and debugging details.
18
+ #
19
+ # @param event [ActiveSupport::Notifications::Event] the subscribed event
20
+ def request(event)
21
+ log_action_summary(event)
22
+ log_request_details(event)
23
+ log_response_details(event)
24
+ end
25
+
26
+ private
27
+
28
+ # Print some top-level request/action details.
29
+ #
30
+ # @param event [ActiveSupport::Notifications::Event] the subscribed event
31
+ def log_action_summary(event)
32
+ env = event.payload
33
+ info do
34
+ "[#{req_id(env)}] #{req_origin(env)} -> #{res_result(env)} " \
35
+ "(#{event.duration.round(1)}ms)"
36
+ end
37
+ end
38
+
39
+ # Print details about the request.
40
+ #
41
+ # @param event [ActiveSupport::Notifications::Event] the subscribed event
42
+ def log_request_details(event)
43
+ env = event.payload
44
+ debug do
45
+ "[#{req_id(env)}] #{req_dest(env)} > " \
46
+ "#{env.request_headers.sort.to_h.to_json}"
47
+ end
48
+ end
49
+
50
+ # When no response is available (due to timeout, DNS resolve issues, etc)
51
+ # we just can log an error without details. Otherwise print details about
52
+ # the response.
53
+ #
54
+ # @param event [ActiveSupport::Notifications::Event] the subscribed event
55
+ def log_response_details(event)
56
+ env = event.payload
57
+
58
+ if env.response.nil?
59
+ return error do
60
+ "[#{req_id(env)}] #{req_dest(env)} < #{res_result(env)}"
61
+ end
62
+ end
63
+
64
+ debug do
65
+ "[#{req_id(env)}] #{req_dest(env)} < " \
66
+ "#{env.response_headers.sort.to_h.to_json}"
67
+ end
68
+ end
69
+
70
+ # Format the request identifier.
71
+ #
72
+ # @param env [Faraday::Env] the request/response environment
73
+ # @return [String] the request identifier
74
+ def req_id(env)
75
+ env.request.context[:request_id].to_s
76
+ end
77
+
78
+ # Format the request/action origin.
79
+ #
80
+ # @param env [Faraday::Env] the request/response environment
81
+ # @return [String] the request identifier
82
+ def req_origin(env)
83
+ req = env.request.context
84
+ action = req[:action]
85
+ action = color(action, color_method(action), true)
86
+ client = req[:client].to_s.gsub('PriceHubble::Client', 'PriceHubble')
87
+ "#{client.underscore}##{action}"
88
+ end
89
+
90
+ # Format the request destination.
91
+ #
92
+ # @param env [Faraday::Env] the request/response environment
93
+ # @return [String] the request identifier
94
+ def req_dest(env)
95
+ method = env[:method].to_s.upcase
96
+ method = color(method, color_method(method), true)
97
+ url = env[:url].to_s.gsub(/access_token=[^&]+/,
98
+ 'access_token=[FILTERED]')
99
+ "#{method} #{url}"
100
+ end
101
+
102
+ # Format the request result.
103
+ #
104
+ # @param env [Faraday::Env] the request/response environment
105
+ # @return [String] the request identifier
106
+ def res_result(env)
107
+ return color('no response', RED, true).to_s if env.response.nil?
108
+
109
+ status = env[:status]
110
+ color("#{status}/#{env[:reason_phrase]}", color_status(status), true)
111
+ end
112
+
113
+ # Decide which color to use for the given HTTP status code.
114
+ #
115
+ # @param status [Integer] the HTTP status code
116
+ # @return [String] the ANSI color code
117
+ def color_status(status)
118
+ case status
119
+ when 0..199 then MAGENTA
120
+ when 200..299 then GREEN
121
+ when 300..399 then YELLOW
122
+ when 400..599 then RED
123
+ else WHITE
124
+ end
125
+ end
126
+
127
+ # Decide which color to use for the given HTTP/client method.
128
+ #
129
+ # @param method [String] the method to inspect
130
+ # @return [String] the ANSI color code
131
+ def color_method(method)
132
+ case method
133
+ when /delete/i then RED
134
+ when /get|search|reload|find/i then BLUE
135
+ when /post|create/i then GREEN
136
+ when /put|patch|update/i then YELLOW
137
+ when /login|logout|download|query/i then CYAN
138
+ else MAGENTA
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
@@ -2,5 +2,5 @@
2
2
 
3
3
  module PriceHubble
4
4
  # The version of the +price-hubble+ gem
5
- VERSION = '0.1.0'
5
+ VERSION = '0.2.0'
6
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pricehubble
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hermann Mayer
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-10-21 00:00:00.000000000 Z
11
+ date: 2019-10-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -402,6 +402,8 @@ files:
402
402
  - lib/pricehubble/errors.rb
403
403
  - lib/pricehubble/faraday.rb
404
404
  - lib/pricehubble/identity.rb
405
+ - lib/pricehubble/instrumentation.rb
406
+ - lib/pricehubble/instrumentation/log_subscriber.rb
405
407
  - lib/pricehubble/railtie.rb
406
408
  - lib/pricehubble/utils/bangers.rb
407
409
  - lib/pricehubble/utils/decision.rb