lhc 13.0.0 → 14.0.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 +4 -4
- data/.github/workflows/rubocop.yml +15 -0
- data/.github/workflows/test.yml +15 -0
- data/.rubocop.yml +344 -19
- data/.ruby-version +1 -1
- data/README.md +44 -0
- data/Rakefile +3 -3
- data/lhc.gemspec +3 -1
- data/lib/lhc.rb +59 -59
- data/lib/lhc/concerns/lhc/fix_invalid_encoding_concern.rb +1 -0
- data/lib/lhc/config.rb +3 -0
- data/lib/lhc/endpoint.rb +3 -0
- data/lib/lhc/error.rb +5 -1
- data/lib/lhc/interceptor.rb +4 -0
- data/lib/lhc/interceptors.rb +1 -0
- data/lib/lhc/interceptors/auth.rb +3 -4
- data/lib/lhc/interceptors/caching.rb +14 -3
- data/lib/lhc/interceptors/logging.rb +2 -0
- data/lib/lhc/interceptors/monitoring.rb +46 -11
- data/lib/lhc/interceptors/retry.rb +2 -0
- data/lib/lhc/interceptors/rollbar.rb +1 -0
- data/lib/lhc/interceptors/throttle.rb +7 -2
- data/lib/lhc/interceptors/zipkin.rb +2 -0
- data/lib/lhc/request.rb +13 -3
- data/lib/lhc/response.rb +1 -0
- data/lib/lhc/response/data.rb +1 -1
- data/lib/lhc/version.rb +1 -1
- data/spec/error/to_s_spec.rb +7 -2
- data/spec/formats/multipart_spec.rb +2 -2
- data/spec/formats/plain_spec.rb +1 -1
- data/spec/interceptors/after_response_spec.rb +1 -1
- data/spec/interceptors/caching/main_spec.rb +2 -2
- data/spec/interceptors/caching/multilevel_cache_spec.rb +2 -1
- data/spec/interceptors/define_spec.rb +1 -0
- data/spec/interceptors/monitoring/caching_spec.rb +66 -0
- data/spec/interceptors/response_competition_spec.rb +2 -2
- data/spec/interceptors/return_response_spec.rb +2 -2
- data/spec/response/data_spec.rb +2 -2
- data/spec/support/zipkin_mock.rb +1 -0
- metadata +27 -21
- data/.rubocop.localch.yml +0 -325
- data/cider-ci.yml +0 -5
- data/cider-ci/bin/bundle +0 -51
- data/cider-ci/bin/ruby_install +0 -8
- data/cider-ci/bin/ruby_version +0 -25
- data/cider-ci/jobs/rspec-activesupport-5.yml +0 -27
- data/cider-ci/jobs/rspec-activesupport-6.yml +0 -28
- data/cider-ci/jobs/rubocop.yml +0 -18
- data/cider-ci/task_components/bundle.yml +0 -22
- data/cider-ci/task_components/rspec.yml +0 -36
- data/cider-ci/task_components/rubocop.yml +0 -29
- data/cider-ci/task_components/ruby.yml +0 -15
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
ruby-2.
|
1
|
+
ruby-2.7.2
|
data/README.md
CHANGED
@@ -73,6 +73,10 @@ use it like:
|
|
73
73
|
* [Installation](#installation-1)
|
74
74
|
* [Environment](#environment)
|
75
75
|
* [What it tracks](#what-it-tracks)
|
76
|
+
* [Before and after request tracking](#before-and-after-request-tracking)
|
77
|
+
* [Response tracking](#response-tracking)
|
78
|
+
* [Timeout tracking](#timeout-tracking)
|
79
|
+
* [Caching tracking](#caching-tracking)
|
76
80
|
* [Configure](#configure-1)
|
77
81
|
* [Prometheus Interceptor](#prometheus-interceptor)
|
78
82
|
* [Retry Interceptor](#retry-interceptor)
|
@@ -95,6 +99,7 @@ use it like:
|
|
95
99
|
|
96
100
|
|
97
101
|
|
102
|
+
|
98
103
|
## Basic methods
|
99
104
|
|
100
105
|
Available are `get`, `post`, `put` & `delete`.
|
@@ -744,11 +749,15 @@ It tracks request attempts with `before_request` and `after_request` (counts).
|
|
744
749
|
In case your workers/processes are getting killed due limited time constraints,
|
745
750
|
you are able to detect deltas with relying on "before_request", and "after_request" counts:
|
746
751
|
|
752
|
+
###### Before and after request tracking
|
753
|
+
|
747
754
|
```ruby
|
748
755
|
"lhc.<app_name>.<env>.<host>.<http_method>.before_request", 1
|
749
756
|
"lhc.<app_name>.<env>.<host>.<http_method>.after_request", 1
|
750
757
|
```
|
751
758
|
|
759
|
+
###### Response tracking
|
760
|
+
|
752
761
|
In case of a successful response it reports the response code with a count and the response time with a gauge value.
|
753
762
|
|
754
763
|
```ruby
|
@@ -759,6 +768,17 @@ In case of a successful response it reports the response code with a count and t
|
|
759
768
|
"lhc.<app_name>.<env>.<host>.<http_method>.time", 43
|
760
769
|
```
|
761
770
|
|
771
|
+
In case of a unsuccessful response it reports the response code with a count but no time:
|
772
|
+
|
773
|
+
```ruby
|
774
|
+
LHC.get('http://local.ch')
|
775
|
+
|
776
|
+
"lhc.<app_name>.<env>.<host>.<http_method>.count", 1
|
777
|
+
"lhc.<app_name>.<env>.<host>.<http_method>.500", 1
|
778
|
+
```
|
779
|
+
|
780
|
+
###### Timeout tracking
|
781
|
+
|
762
782
|
Timeouts are also reported:
|
763
783
|
|
764
784
|
```ruby
|
@@ -767,6 +787,30 @@ Timeouts are also reported:
|
|
767
787
|
|
768
788
|
All the dots in the host are getting replaced with underscore, because dot is the default separator in graphite.
|
769
789
|
|
790
|
+
###### Caching tracking
|
791
|
+
|
792
|
+
When you want to track caching stats please make sure you have enabled the `LHC::Caching` and the `LHC::Monitoring` interceptor.
|
793
|
+
|
794
|
+
Make sure that the `LHC::Caching` is listed before `LHC::Monitoring` interceptor when configuring interceptors:
|
795
|
+
|
796
|
+
```ruby
|
797
|
+
LHC.configure do |c|
|
798
|
+
c.interceptors = [LHC::Caching, LHC::Monitoring]
|
799
|
+
end
|
800
|
+
```
|
801
|
+
|
802
|
+
If a response was served from cache it tracks:
|
803
|
+
|
804
|
+
```ruby
|
805
|
+
"lhc.<app_name>.<env>.<host>.<http_method>.cache.hit", 1
|
806
|
+
```
|
807
|
+
|
808
|
+
If a response was not served from cache it tracks:
|
809
|
+
|
810
|
+
```ruby
|
811
|
+
"lhc.<app_name>.<env>.<host>.<http_method>.cache.miss", 1
|
812
|
+
```
|
813
|
+
|
770
814
|
##### Configure
|
771
815
|
|
772
816
|
It is possible to set the key for Monitoring Interceptor on per request basis:
|
data/Rakefile
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
begin
|
2
4
|
require 'bundler/setup'
|
3
5
|
rescue LoadError
|
@@ -17,9 +19,7 @@ end
|
|
17
19
|
begin
|
18
20
|
require 'rspec/core/rake_task'
|
19
21
|
RSpec::Core::RakeTask.new(:spec)
|
20
|
-
task :
|
21
|
-
rescue LoadError
|
22
|
-
# no rspec available
|
22
|
+
task default: :spec
|
23
23
|
end
|
24
24
|
|
25
25
|
Bundler::GemHelper.install_tasks
|
data/lhc.gemspec
CHANGED
@@ -20,6 +20,7 @@ Gem::Specification.new do |s|
|
|
20
20
|
s.require_paths = ['lib']
|
21
21
|
|
22
22
|
s.requirements << 'Ruby >= 2.0.0'
|
23
|
+
s.required_ruby_version = '>= 2.7' # Needed for rubocop
|
23
24
|
|
24
25
|
s.add_dependency 'activesupport', '>= 5.2'
|
25
26
|
s.add_dependency 'addressable'
|
@@ -31,7 +32,8 @@ Gem::Specification.new do |s|
|
|
31
32
|
s.add_development_dependency 'rails', '>= 5.2'
|
32
33
|
s.add_development_dependency 'redis'
|
33
34
|
s.add_development_dependency 'rspec-rails', '>= 3.0.0'
|
34
|
-
s.add_development_dependency 'rubocop', '~> 0
|
35
|
+
s.add_development_dependency 'rubocop', '~> 1.0'
|
36
|
+
s.add_development_dependency 'rubocop-performance', '~> 1.0'
|
35
37
|
s.add_development_dependency 'rubocop-rspec', '~> 1.26.0'
|
36
38
|
s.add_development_dependency 'timecop'
|
37
39
|
s.add_development_dependency 'webmock'
|
data/lib/lhc.rb
CHANGED
@@ -6,131 +6,131 @@ require 'active_support/core_ext/hash/keys'
|
|
6
6
|
|
7
7
|
module LHC
|
8
8
|
autoload :BasicMethodsConcern,
|
9
|
-
|
9
|
+
'lhc/concerns/lhc/basic_methods_concern'
|
10
10
|
autoload :ConfigurationConcern,
|
11
|
-
|
11
|
+
'lhc/concerns/lhc/configuration_concern'
|
12
12
|
autoload :FixInvalidEncodingConcern,
|
13
|
-
|
13
|
+
'lhc/concerns/lhc/fix_invalid_encoding_concern'
|
14
14
|
autoload :FormatsConcern,
|
15
|
-
|
15
|
+
'lhc/concerns/lhc/formats_concern'
|
16
16
|
|
17
17
|
include BasicMethodsConcern
|
18
18
|
include ConfigurationConcern
|
19
19
|
include FormatsConcern
|
20
20
|
|
21
21
|
autoload :Auth,
|
22
|
-
|
22
|
+
'lhc/interceptors/auth'
|
23
23
|
autoload :Caching,
|
24
|
-
|
24
|
+
'lhc/interceptors/caching'
|
25
25
|
autoload :DefaultTimeout,
|
26
|
-
|
26
|
+
'lhc/interceptors/default_timeout'
|
27
27
|
autoload :Logging,
|
28
|
-
|
28
|
+
'lhc/interceptors/logging'
|
29
29
|
autoload :Prometheus,
|
30
|
-
|
30
|
+
'lhc/interceptors/prometheus'
|
31
31
|
autoload :Retry,
|
32
|
-
|
32
|
+
'lhc/interceptors/retry'
|
33
33
|
autoload :Throttle,
|
34
|
-
|
34
|
+
'lhc/interceptors/throttle'
|
35
35
|
|
36
36
|
autoload :Config,
|
37
|
-
|
37
|
+
'lhc/config'
|
38
38
|
autoload :Endpoint,
|
39
|
-
|
39
|
+
'lhc/endpoint'
|
40
40
|
|
41
41
|
autoload :Error,
|
42
|
-
|
42
|
+
'lhc/error'
|
43
43
|
autoload :ClientError,
|
44
|
-
|
44
|
+
'lhc/errors/client_error'
|
45
45
|
autoload :BadRequest,
|
46
|
-
|
46
|
+
'lhc/errors/client_error'
|
47
47
|
autoload :Unauthorized,
|
48
|
-
|
48
|
+
'lhc/errors/client_error'
|
49
49
|
autoload :PaymentRequired,
|
50
|
-
|
50
|
+
'lhc/errors/client_error'
|
51
51
|
autoload :Forbidden,
|
52
|
-
|
52
|
+
'lhc/errors/client_error'
|
53
53
|
autoload :Forbidden,
|
54
|
-
|
54
|
+
'lhc/errors/client_error'
|
55
55
|
autoload :NotFound,
|
56
|
-
|
56
|
+
'lhc/errors/client_error'
|
57
57
|
autoload :MethodNotAllowed,
|
58
|
-
|
58
|
+
'lhc/errors/client_error'
|
59
59
|
autoload :NotAcceptable,
|
60
|
-
|
60
|
+
'lhc/errors/client_error'
|
61
61
|
autoload :ProxyAuthenticationRequired,
|
62
|
-
|
62
|
+
'lhc/errors/client_error'
|
63
63
|
autoload :RequestTimeout,
|
64
|
-
|
64
|
+
'lhc/errors/client_error'
|
65
65
|
autoload :Conflict,
|
66
|
-
|
66
|
+
'lhc/errors/client_error'
|
67
67
|
autoload :Gone,
|
68
|
-
|
68
|
+
'lhc/errors/client_error'
|
69
69
|
autoload :LengthRequired,
|
70
|
-
|
70
|
+
'lhc/errors/client_error'
|
71
71
|
autoload :PreconditionFailed,
|
72
|
-
|
72
|
+
'lhc/errors/client_error'
|
73
73
|
autoload :RequestEntityTooLarge,
|
74
|
-
|
74
|
+
'lhc/errors/client_error'
|
75
75
|
autoload :RequestUriToLong,
|
76
|
-
|
76
|
+
'lhc/errors/client_error'
|
77
77
|
autoload :UnsupportedMediaType,
|
78
|
-
|
78
|
+
'lhc/errors/client_error'
|
79
79
|
autoload :RequestedRangeNotSatisfiable,
|
80
|
-
|
80
|
+
'lhc/errors/client_error'
|
81
81
|
autoload :ExpectationFailed,
|
82
|
-
|
82
|
+
'lhc/errors/client_error'
|
83
83
|
autoload :UnprocessableEntity,
|
84
|
-
|
84
|
+
'lhc/errors/client_error'
|
85
85
|
autoload :Locked,
|
86
|
-
|
86
|
+
'lhc/errors/client_error'
|
87
87
|
autoload :FailedDependency,
|
88
|
-
|
88
|
+
'lhc/errors/client_error'
|
89
89
|
autoload :UpgradeRequired,
|
90
|
-
|
90
|
+
'lhc/errors/client_error'
|
91
91
|
autoload :ParserError,
|
92
|
-
|
92
|
+
'lhc/errors/parser_error'
|
93
93
|
autoload :ServerError,
|
94
|
-
|
94
|
+
'lhc/errors/server_error'
|
95
95
|
autoload :InternalServerError,
|
96
|
-
|
96
|
+
'lhc/errors/server_error'
|
97
97
|
autoload :NotImplemented,
|
98
|
-
|
98
|
+
'lhc/errors/server_error'
|
99
99
|
autoload :BadGateway,
|
100
|
-
|
100
|
+
'lhc/errors/server_error'
|
101
101
|
autoload :ServiceUnavailable,
|
102
|
-
|
102
|
+
'lhc/errors/server_error'
|
103
103
|
autoload :GatewayTimeout,
|
104
|
-
|
104
|
+
'lhc/errors/server_error'
|
105
105
|
autoload :HttpVersionNotSupported,
|
106
|
-
|
106
|
+
'lhc/errors/server_error'
|
107
107
|
autoload :InsufficientStorage,
|
108
|
-
|
108
|
+
'lhc/errors/server_error'
|
109
109
|
autoload :NotExtended,
|
110
|
-
|
110
|
+
'lhc/errors/server_error'
|
111
111
|
autoload :Timeout,
|
112
|
-
|
112
|
+
'lhc/errors/timeout'
|
113
113
|
autoload :UnknownError,
|
114
|
-
|
114
|
+
'lhc/errors/unknown_error'
|
115
115
|
|
116
116
|
autoload :Interceptor,
|
117
|
-
|
117
|
+
'lhc/interceptor'
|
118
118
|
autoload :Interceptors,
|
119
|
-
|
119
|
+
'lhc/interceptors'
|
120
120
|
autoload :Formats,
|
121
|
-
|
121
|
+
'lhc/formats'
|
122
122
|
autoload :Format,
|
123
|
-
|
123
|
+
'lhc/format'
|
124
124
|
autoload :Monitoring,
|
125
|
-
|
125
|
+
'lhc/interceptors/monitoring'
|
126
126
|
autoload :Request,
|
127
|
-
|
127
|
+
'lhc/request'
|
128
128
|
autoload :Response,
|
129
|
-
|
129
|
+
'lhc/response'
|
130
130
|
autoload :Rollbar,
|
131
|
-
|
131
|
+
'lhc/interceptors/rollbar'
|
132
132
|
autoload :Zipkin,
|
133
|
-
|
133
|
+
'lhc/interceptors/zipkin'
|
134
134
|
|
135
135
|
require 'lhc/railtie' if defined?(Rails)
|
136
136
|
end
|
data/lib/lhc/config.rb
CHANGED
@@ -13,6 +13,7 @@ class LHC::Config
|
|
13
13
|
def endpoint(name, url, options = {})
|
14
14
|
name = name.to_sym
|
15
15
|
raise 'Endpoint already exists for that name' if @endpoints[name]
|
16
|
+
|
16
17
|
@endpoints[name] = LHC::Endpoint.new(url, options)
|
17
18
|
end
|
18
19
|
|
@@ -23,6 +24,7 @@ class LHC::Config
|
|
23
24
|
def placeholder(name, value)
|
24
25
|
name = name.to_sym
|
25
26
|
raise 'Placeholder already exists for that name' if @placeholders[name]
|
27
|
+
|
26
28
|
@placeholders[name] = value
|
27
29
|
end
|
28
30
|
|
@@ -36,6 +38,7 @@ class LHC::Config
|
|
36
38
|
|
37
39
|
def interceptors=(interceptors)
|
38
40
|
raise 'Default interceptors already set and can only be set once' if @interceptors
|
41
|
+
|
39
42
|
@interceptors = interceptors
|
40
43
|
end
|
41
44
|
|
data/lib/lhc/endpoint.rb
CHANGED
@@ -55,6 +55,7 @@ class LHC::Endpoint
|
|
55
55
|
# Example: {+datastore}/contracts/{id} == http://local.ch/contracts/1
|
56
56
|
def match?(url)
|
57
57
|
return true if url == uri.pattern
|
58
|
+
|
58
59
|
match_data = match_data(url)
|
59
60
|
return false if match_data.nil?
|
60
61
|
|
@@ -75,6 +76,7 @@ class LHC::Endpoint
|
|
75
76
|
def values_as_params(url)
|
76
77
|
match_data = match_data(url)
|
77
78
|
return if match_data.nil?
|
79
|
+
|
78
80
|
Hash[match_data.variables.map(&:to_sym).zip(match_data.values)]
|
79
81
|
end
|
80
82
|
|
@@ -103,6 +105,7 @@ class LHC::Endpoint
|
|
103
105
|
# creates params according to template
|
104
106
|
def self.values_as_params(template, url)
|
105
107
|
raise("#{url} does not match the template: #{template}") if !match?(url, template)
|
108
|
+
|
106
109
|
new(template).values_as_params(url)
|
107
110
|
end
|
108
111
|
|
data/lib/lhc/error.rb
CHANGED
@@ -43,6 +43,7 @@ class LHC::Error < StandardError
|
|
43
43
|
|
44
44
|
def self.find(response)
|
45
45
|
return LHC::Timeout if response.timeout?
|
46
|
+
|
46
47
|
status_code = response.code.to_s[0..2].to_i
|
47
48
|
error = map[status_code]
|
48
49
|
error ||= LHC::UnknownError
|
@@ -64,8 +65,11 @@ class LHC::Error < StandardError
|
|
64
65
|
end
|
65
66
|
|
66
67
|
def to_s
|
67
|
-
return response
|
68
|
+
return response.to_s unless response.is_a?(LHC::Response)
|
69
|
+
|
68
70
|
request = response.request
|
71
|
+
return unless request.is_a?(LHC::Request)
|
72
|
+
|
69
73
|
debug = []
|
70
74
|
debug << [request.method, request.url].map { |str| self.class.fix_invalid_encoding(str) }.join(' ')
|
71
75
|
debug << "Options: #{request.options}"
|
data/lib/lhc/interceptor.rb
CHANGED
data/lib/lhc/interceptors.rb
CHANGED
@@ -16,6 +16,7 @@ class LHC::Auth < LHC::Interceptor
|
|
16
16
|
def after_response
|
17
17
|
return unless configuration_correct?
|
18
18
|
return unless reauthenticate?
|
19
|
+
|
19
20
|
reauthenticate!
|
20
21
|
end
|
21
22
|
|
@@ -75,10 +76,6 @@ class LHC::Auth < LHC::Interceptor
|
|
75
76
|
@refresh_client_token_option ||= auth_options[:refresh_client_token] || refresh_client_token
|
76
77
|
end
|
77
78
|
|
78
|
-
def all_interceptor_classes
|
79
|
-
@all_interceptors ||= LHC::Interceptors.new(request).all.map(&:class)
|
80
|
-
end
|
81
|
-
|
82
79
|
def auth_options
|
83
80
|
request.options[:auth] || {}
|
84
81
|
end
|
@@ -90,11 +87,13 @@ class LHC::Auth < LHC::Interceptor
|
|
90
87
|
|
91
88
|
def refresh_client_token?
|
92
89
|
return true if refresh_client_token_option.is_a?(Proc)
|
90
|
+
|
93
91
|
warn("[WARNING] The given refresh_client_token must be a Proc for reauthentication.")
|
94
92
|
end
|
95
93
|
|
96
94
|
def retry_interceptor?
|
97
95
|
return true if all_interceptor_classes.include?(LHC::Retry) && all_interceptor_classes.index(LHC::Retry) > all_interceptor_classes.index(self.class)
|
96
|
+
|
98
97
|
warn("[WARNING] Your interceptors must include LHC::Retry after LHC::Auth.")
|
99
98
|
end
|
100
99
|
end
|
@@ -41,15 +41,16 @@ class LHC::Caching < LHC::Interceptor
|
|
41
41
|
|
42
42
|
def before_request
|
43
43
|
return unless cache?(request)
|
44
|
-
|
45
|
-
|
46
|
-
return unless response_data
|
44
|
+
return if response_data.blank?
|
45
|
+
|
47
46
|
from_cache(request, response_data)
|
48
47
|
end
|
49
48
|
|
50
49
|
def after_response
|
51
50
|
return unless response.success?
|
52
51
|
return unless cache?(request)
|
52
|
+
return if response_data.present?
|
53
|
+
|
53
54
|
multilevel_cache.write(
|
54
55
|
key(request, options[:key]),
|
55
56
|
to_cache(response),
|
@@ -59,6 +60,14 @@ class LHC::Caching < LHC::Interceptor
|
|
59
60
|
|
60
61
|
private
|
61
62
|
|
63
|
+
# from cache
|
64
|
+
def response_data
|
65
|
+
# stop calling multi-level cache if it already returned nil for this interceptor instance
|
66
|
+
return @response_data if defined? @response_data
|
67
|
+
|
68
|
+
@response_data ||= multilevel_cache.fetch(key(request, options[:key]))
|
69
|
+
end
|
70
|
+
|
62
71
|
# performs read/write (fetch/write) on all configured cache levels (e.g. local & central)
|
63
72
|
def multilevel_cache
|
64
73
|
MultilevelCache.new(
|
@@ -75,6 +84,7 @@ class LHC::Caching < LHC::Interceptor
|
|
75
84
|
|
76
85
|
def central_cache
|
77
86
|
return nil if central.blank? || (central[:read].blank? && central[:write].blank?)
|
87
|
+
|
78
88
|
{}.tap do |options|
|
79
89
|
options[:read] = ActiveSupport::Cache::RedisCacheStore.new(url: central[:read]) if central[:read].present?
|
80
90
|
options[:write] = ActiveSupport::Cache::RedisCacheStore.new(url: central[:write]) if central[:write].present?
|
@@ -86,6 +96,7 @@ class LHC::Caching < LHC::Interceptor
|
|
86
96
|
# return false if this interceptor cannot work
|
87
97
|
def cache?(request)
|
88
98
|
return false unless request.options[:cache]
|
99
|
+
|
89
100
|
(local_cache || central_cache) &&
|
90
101
|
cached_method?(request.method, options[:methods])
|
91
102
|
end
|