lhc 13.0.0 → 15.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.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rubocop.yml +15 -0
  3. data/.github/workflows/test.yml +15 -0
  4. data/.rubocop.yml +344 -19
  5. data/.ruby-version +1 -1
  6. data/README.md +89 -0
  7. data/Rakefile +3 -3
  8. data/lhc.gemspec +3 -1
  9. data/lib/lhc.rb +70 -59
  10. data/lib/lhc/concerns/lhc/fix_invalid_encoding_concern.rb +1 -0
  11. data/lib/lhc/config.rb +16 -0
  12. data/lib/lhc/endpoint.rb +3 -0
  13. data/lib/lhc/error.rb +7 -4
  14. data/lib/lhc/interceptor.rb +4 -0
  15. data/lib/lhc/interceptors.rb +1 -0
  16. data/lib/lhc/interceptors/auth.rb +10 -5
  17. data/lib/lhc/interceptors/caching.rb +14 -3
  18. data/lib/lhc/interceptors/logging.rb +4 -2
  19. data/lib/lhc/interceptors/monitoring.rb +46 -11
  20. data/lib/lhc/interceptors/retry.rb +2 -0
  21. data/lib/lhc/interceptors/rollbar.rb +3 -2
  22. data/lib/lhc/interceptors/throttle.rb +7 -2
  23. data/lib/lhc/interceptors/zipkin.rb +2 -0
  24. data/lib/lhc/request.rb +37 -4
  25. data/lib/lhc/response.rb +1 -0
  26. data/lib/lhc/response/data.rb +1 -1
  27. data/lib/lhc/scrubber.rb +45 -0
  28. data/lib/lhc/scrubbers/auth_scrubber.rb +33 -0
  29. data/lib/lhc/scrubbers/body_scrubber.rb +28 -0
  30. data/lib/lhc/scrubbers/headers_scrubber.rb +38 -0
  31. data/lib/lhc/scrubbers/params_scrubber.rb +14 -0
  32. data/lib/lhc/version.rb +1 -1
  33. data/spec/config/scrubs_spec.rb +108 -0
  34. data/spec/error/to_s_spec.rb +13 -8
  35. data/spec/formats/multipart_spec.rb +2 -2
  36. data/spec/formats/plain_spec.rb +1 -1
  37. data/spec/interceptors/after_response_spec.rb +1 -1
  38. data/spec/interceptors/caching/main_spec.rb +2 -2
  39. data/spec/interceptors/caching/multilevel_cache_spec.rb +2 -1
  40. data/spec/interceptors/define_spec.rb +1 -0
  41. data/spec/interceptors/logging/main_spec.rb +21 -1
  42. data/spec/interceptors/monitoring/caching_spec.rb +66 -0
  43. data/spec/interceptors/response_competition_spec.rb +2 -2
  44. data/spec/interceptors/return_response_spec.rb +2 -2
  45. data/spec/interceptors/rollbar/main_spec.rb +27 -15
  46. data/spec/request/scrubbed_headers_spec.rb +101 -0
  47. data/spec/request/scrubbed_options_spec.rb +194 -0
  48. data/spec/request/scrubbed_params_spec.rb +35 -0
  49. data/spec/response/data_spec.rb +2 -2
  50. data/spec/support/zipkin_mock.rb +1 -0
  51. metadata +40 -21
  52. data/.rubocop.localch.yml +0 -325
  53. data/cider-ci.yml +0 -5
  54. data/cider-ci/bin/bundle +0 -51
  55. data/cider-ci/bin/ruby_install +0 -8
  56. data/cider-ci/bin/ruby_version +0 -25
  57. data/cider-ci/jobs/rspec-activesupport-5.yml +0 -27
  58. data/cider-ci/jobs/rspec-activesupport-6.yml +0 -28
  59. data/cider-ci/jobs/rubocop.yml +0 -18
  60. data/cider-ci/task_components/bundle.yml +0 -22
  61. data/cider-ci/task_components/rspec.yml +0 -36
  62. data/cider-ci/task_components/rubocop.yml +0 -29
  63. data/cider-ci/task_components/ruby.yml +0 -15
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- ruby-2.6.5
1
+ ruby-2.7.2
data/README.md CHANGED
@@ -51,6 +51,7 @@ use it like:
51
51
  * [Configuration](#configuration)
52
52
  * [Configuring endpoints](#configuring-endpoints)
53
53
  * [Configuring placeholders](#configuring-placeholders)
54
+ * [Configuring scrubs](#configuring-scrubs)
54
55
  * [Interceptors](#interceptors)
55
56
  * [Quick start: Configure/Enable Interceptors](#quick-start-configureenable-interceptors)
56
57
  * [Interceptors on local request level](#interceptors-on-local-request-level)
@@ -73,6 +74,10 @@ use it like:
73
74
  * [Installation](#installation-1)
74
75
  * [Environment](#environment)
75
76
  * [What it tracks](#what-it-tracks)
77
+ * [Before and after request tracking](#before-and-after-request-tracking)
78
+ * [Response tracking](#response-tracking)
79
+ * [Timeout tracking](#timeout-tracking)
80
+ * [Caching tracking](#caching-tracking)
76
81
  * [Configure](#configure-1)
77
82
  * [Prometheus Interceptor](#prometheus-interceptor)
78
83
  * [Retry Interceptor](#retry-interceptor)
@@ -95,6 +100,7 @@ use it like:
95
100
 
96
101
 
97
102
 
103
+
98
104
  ## Basic methods
99
105
 
100
106
  Available are `get`, `post`, `put` & `delete`.
@@ -486,6 +492,50 @@ You can configure global placeholders, that are used when generating urls from u
486
492
  LHC.get(:feedbacks) # http://datastore/v2/feedbacks
487
493
  ```
488
494
 
495
+ ### Configuring scrubs
496
+
497
+ You can filter out sensitive request data from your log files and rollbar by appending them to `LHS.config.scrubs`. These values will be marked `[FILTERED]` in the log and on rollbar. Also nested parameters are being filtered.
498
+ The scrubbing configuration affects all request done by LHC independent of the endpoint. You can scrub any attribute within `:params`, `:headers` or `:body`. For `:auth` you either can choose `:bearer` or `:basic` (default is both).
499
+
500
+ LHS scrubs per default:
501
+ - Bearer Token within the Request Header
502
+ - Basic Auth `username` and `password` within the Request Header
503
+ - `password` and `password_confirmation` within the Request Body
504
+
505
+ Enhance the default scrubbing by pushing the name of the parameter, which should be scrubbed, as string to the existing configuration.
506
+ You can also add multiple parameters at once by pushing multiple strings.
507
+
508
+ Example:
509
+ ```ruby
510
+ LHC.configure do |c|
511
+ c.scrubs[:params] << 'api_key'
512
+ c.scrubs[:body].push('user_token', 'secret_key')
513
+ end
514
+ ```
515
+
516
+ For disabling scrubbing, add following configuration:
517
+ ```ruby
518
+ LHC.configure do |c|
519
+ c.scrubs = {}
520
+ end
521
+ ```
522
+
523
+ If you want to turn off `:bearer` or `:basic` scrubbing, then just overwrite the `:auth` configuration.
524
+
525
+ Example:
526
+ ```ruby
527
+ LHC.configure do |c|
528
+ c.scrubs[:auth] = [:bearer]
529
+ end
530
+ ```
531
+
532
+ If your app has a different authentication strategy than Bearer Authentication or Basic Authentication then you can filter the data by scrubbing the whole header:
533
+ ```ruby
534
+ LHC.configure do |c|
535
+ c.scrubs[:headers] << 'Authorization'
536
+ end
537
+ ```
538
+
489
539
  ## Interceptors
490
540
 
491
541
  To monitor and manipulate the HTTP communication done with LHC, you can define interceptors that follow the (Inteceptor Pattern)[https://en.wikipedia.org/wiki/Interceptor_pattern].
@@ -744,11 +794,15 @@ It tracks request attempts with `before_request` and `after_request` (counts).
744
794
  In case your workers/processes are getting killed due limited time constraints,
745
795
  you are able to detect deltas with relying on "before_request", and "after_request" counts:
746
796
 
797
+ ###### Before and after request tracking
798
+
747
799
  ```ruby
748
800
  "lhc.<app_name>.<env>.<host>.<http_method>.before_request", 1
749
801
  "lhc.<app_name>.<env>.<host>.<http_method>.after_request", 1
750
802
  ```
751
803
 
804
+ ###### Response tracking
805
+
752
806
  In case of a successful response it reports the response code with a count and the response time with a gauge value.
753
807
 
754
808
  ```ruby
@@ -759,6 +813,17 @@ In case of a successful response it reports the response code with a count and t
759
813
  "lhc.<app_name>.<env>.<host>.<http_method>.time", 43
760
814
  ```
761
815
 
816
+ In case of a unsuccessful response it reports the response code with a count but no time:
817
+
818
+ ```ruby
819
+ LHC.get('http://local.ch')
820
+
821
+ "lhc.<app_name>.<env>.<host>.<http_method>.count", 1
822
+ "lhc.<app_name>.<env>.<host>.<http_method>.500", 1
823
+ ```
824
+
825
+ ###### Timeout tracking
826
+
762
827
  Timeouts are also reported:
763
828
 
764
829
  ```ruby
@@ -767,6 +832,30 @@ Timeouts are also reported:
767
832
 
768
833
  All the dots in the host are getting replaced with underscore, because dot is the default separator in graphite.
769
834
 
835
+ ###### Caching tracking
836
+
837
+ When you want to track caching stats please make sure you have enabled the `LHC::Caching` and the `LHC::Monitoring` interceptor.
838
+
839
+ Make sure that the `LHC::Caching` is listed before `LHC::Monitoring` interceptor when configuring interceptors:
840
+
841
+ ```ruby
842
+ LHC.configure do |c|
843
+ c.interceptors = [LHC::Caching, LHC::Monitoring]
844
+ end
845
+ ```
846
+
847
+ If a response was served from cache it tracks:
848
+
849
+ ```ruby
850
+ "lhc.<app_name>.<env>.<host>.<http_method>.cache.hit", 1
851
+ ```
852
+
853
+ If a response was not served from cache it tracks:
854
+
855
+ ```ruby
856
+ "lhc.<app_name>.<env>.<host>.<http_method>.cache.miss", 1
857
+ ```
858
+
770
859
  ##### Configure
771
860
 
772
861
  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 :default => :spec
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.57.1'
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,142 @@ require 'active_support/core_ext/hash/keys'
6
6
 
7
7
  module LHC
8
8
  autoload :BasicMethodsConcern,
9
- 'lhc/concerns/lhc/basic_methods_concern'
9
+ 'lhc/concerns/lhc/basic_methods_concern'
10
10
  autoload :ConfigurationConcern,
11
- 'lhc/concerns/lhc/configuration_concern'
11
+ 'lhc/concerns/lhc/configuration_concern'
12
12
  autoload :FixInvalidEncodingConcern,
13
- 'lhc/concerns/lhc/fix_invalid_encoding_concern'
13
+ 'lhc/concerns/lhc/fix_invalid_encoding_concern'
14
14
  autoload :FormatsConcern,
15
- 'lhc/concerns/lhc/formats_concern'
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
- 'lhc/interceptors/auth'
22
+ 'lhc/interceptors/auth'
23
23
  autoload :Caching,
24
- 'lhc/interceptors/caching'
24
+ 'lhc/interceptors/caching'
25
25
  autoload :DefaultTimeout,
26
- 'lhc/interceptors/default_timeout'
26
+ 'lhc/interceptors/default_timeout'
27
27
  autoload :Logging,
28
- 'lhc/interceptors/logging'
28
+ 'lhc/interceptors/logging'
29
29
  autoload :Prometheus,
30
- 'lhc/interceptors/prometheus'
30
+ 'lhc/interceptors/prometheus'
31
31
  autoload :Retry,
32
- 'lhc/interceptors/retry'
32
+ 'lhc/interceptors/retry'
33
33
  autoload :Throttle,
34
- 'lhc/interceptors/throttle'
34
+ 'lhc/interceptors/throttle'
35
35
 
36
36
  autoload :Config,
37
- 'lhc/config'
37
+ 'lhc/config'
38
38
  autoload :Endpoint,
39
- 'lhc/endpoint'
39
+ 'lhc/endpoint'
40
40
 
41
41
  autoload :Error,
42
- 'lhc/error'
42
+ 'lhc/error'
43
43
  autoload :ClientError,
44
- 'lhc/errors/client_error'
44
+ 'lhc/errors/client_error'
45
45
  autoload :BadRequest,
46
- 'lhc/errors/client_error'
46
+ 'lhc/errors/client_error'
47
47
  autoload :Unauthorized,
48
- 'lhc/errors/client_error'
48
+ 'lhc/errors/client_error'
49
49
  autoload :PaymentRequired,
50
- 'lhc/errors/client_error'
50
+ 'lhc/errors/client_error'
51
51
  autoload :Forbidden,
52
- 'lhc/errors/client_error'
52
+ 'lhc/errors/client_error'
53
53
  autoload :Forbidden,
54
- 'lhc/errors/client_error'
54
+ 'lhc/errors/client_error'
55
55
  autoload :NotFound,
56
- 'lhc/errors/client_error'
56
+ 'lhc/errors/client_error'
57
57
  autoload :MethodNotAllowed,
58
- 'lhc/errors/client_error'
58
+ 'lhc/errors/client_error'
59
59
  autoload :NotAcceptable,
60
- 'lhc/errors/client_error'
60
+ 'lhc/errors/client_error'
61
61
  autoload :ProxyAuthenticationRequired,
62
- 'lhc/errors/client_error'
62
+ 'lhc/errors/client_error'
63
63
  autoload :RequestTimeout,
64
- 'lhc/errors/client_error'
64
+ 'lhc/errors/client_error'
65
65
  autoload :Conflict,
66
- 'lhc/errors/client_error'
66
+ 'lhc/errors/client_error'
67
67
  autoload :Gone,
68
- 'lhc/errors/client_error'
68
+ 'lhc/errors/client_error'
69
69
  autoload :LengthRequired,
70
- 'lhc/errors/client_error'
70
+ 'lhc/errors/client_error'
71
71
  autoload :PreconditionFailed,
72
- 'lhc/errors/client_error'
72
+ 'lhc/errors/client_error'
73
73
  autoload :RequestEntityTooLarge,
74
- 'lhc/errors/client_error'
74
+ 'lhc/errors/client_error'
75
75
  autoload :RequestUriToLong,
76
- 'lhc/errors/client_error'
76
+ 'lhc/errors/client_error'
77
77
  autoload :UnsupportedMediaType,
78
- 'lhc/errors/client_error'
78
+ 'lhc/errors/client_error'
79
79
  autoload :RequestedRangeNotSatisfiable,
80
- 'lhc/errors/client_error'
80
+ 'lhc/errors/client_error'
81
81
  autoload :ExpectationFailed,
82
- 'lhc/errors/client_error'
82
+ 'lhc/errors/client_error'
83
83
  autoload :UnprocessableEntity,
84
- 'lhc/errors/client_error'
84
+ 'lhc/errors/client_error'
85
85
  autoload :Locked,
86
- 'lhc/errors/client_error'
86
+ 'lhc/errors/client_error'
87
87
  autoload :FailedDependency,
88
- 'lhc/errors/client_error'
88
+ 'lhc/errors/client_error'
89
89
  autoload :UpgradeRequired,
90
- 'lhc/errors/client_error'
90
+ 'lhc/errors/client_error'
91
91
  autoload :ParserError,
92
- 'lhc/errors/parser_error'
92
+ 'lhc/errors/parser_error'
93
93
  autoload :ServerError,
94
- 'lhc/errors/server_error'
94
+ 'lhc/errors/server_error'
95
95
  autoload :InternalServerError,
96
- 'lhc/errors/server_error'
96
+ 'lhc/errors/server_error'
97
97
  autoload :NotImplemented,
98
- 'lhc/errors/server_error'
98
+ 'lhc/errors/server_error'
99
99
  autoload :BadGateway,
100
- 'lhc/errors/server_error'
100
+ 'lhc/errors/server_error'
101
101
  autoload :ServiceUnavailable,
102
- 'lhc/errors/server_error'
102
+ 'lhc/errors/server_error'
103
103
  autoload :GatewayTimeout,
104
- 'lhc/errors/server_error'
104
+ 'lhc/errors/server_error'
105
105
  autoload :HttpVersionNotSupported,
106
- 'lhc/errors/server_error'
106
+ 'lhc/errors/server_error'
107
107
  autoload :InsufficientStorage,
108
- 'lhc/errors/server_error'
108
+ 'lhc/errors/server_error'
109
109
  autoload :NotExtended,
110
- 'lhc/errors/server_error'
110
+ 'lhc/errors/server_error'
111
111
  autoload :Timeout,
112
- 'lhc/errors/timeout'
112
+ 'lhc/errors/timeout'
113
113
  autoload :UnknownError,
114
- 'lhc/errors/unknown_error'
114
+ 'lhc/errors/unknown_error'
115
+
116
+ autoload :Scrubber,
117
+ 'lhc/scrubber'
118
+ autoload :AuthScrubber,
119
+ 'lhc/scrubbers/auth_scrubber'
120
+ autoload :BodyScrubber,
121
+ 'lhc/scrubbers/body_scrubber'
122
+ autoload :HeadersScrubber,
123
+ 'lhc/scrubbers/headers_scrubber'
124
+ autoload :ParamsScrubber,
125
+ 'lhc/scrubbers/params_scrubber'
115
126
 
116
127
  autoload :Interceptor,
117
- 'lhc/interceptor'
128
+ 'lhc/interceptor'
118
129
  autoload :Interceptors,
119
- 'lhc/interceptors'
130
+ 'lhc/interceptors'
120
131
  autoload :Formats,
121
- 'lhc/formats'
132
+ 'lhc/formats'
122
133
  autoload :Format,
123
- 'lhc/format'
134
+ 'lhc/format'
124
135
  autoload :Monitoring,
125
- 'lhc/interceptors/monitoring'
136
+ 'lhc/interceptors/monitoring'
126
137
  autoload :Request,
127
- 'lhc/request'
138
+ 'lhc/request'
128
139
  autoload :Response,
129
- 'lhc/response'
140
+ 'lhc/response'
130
141
  autoload :Rollbar,
131
- 'lhc/interceptors/rollbar'
142
+ 'lhc/interceptors/rollbar'
132
143
  autoload :Zipkin,
133
- 'lhc/interceptors/zipkin'
144
+ 'lhc/interceptors/zipkin'
134
145
 
135
146
  require 'lhc/railtie' if defined?(Rails)
136
147
  end
@@ -12,6 +12,7 @@ module LHC
12
12
  # an empty string is returned instead
13
13
  def fix_invalid_encoding(string)
14
14
  return string unless string.is_a?(String)
15
+
15
16
  result = string.dup
16
17
 
17
18
  # we assume it's ISO-8859-1 first
data/lib/lhc/config.rb CHANGED
@@ -5,14 +5,18 @@ require 'singleton'
5
5
  class LHC::Config
6
6
  include Singleton
7
7
 
8
+ attr_accessor :scrubs
9
+
8
10
  def initialize
9
11
  @endpoints = {}
10
12
  @placeholders = {}
13
+ @scrubs = default_scrubs
11
14
  end
12
15
 
13
16
  def endpoint(name, url, options = {})
14
17
  name = name.to_sym
15
18
  raise 'Endpoint already exists for that name' if @endpoints[name]
19
+
16
20
  @endpoints[name] = LHC::Endpoint.new(url, options)
17
21
  end
18
22
 
@@ -23,6 +27,7 @@ class LHC::Config
23
27
  def placeholder(name, value)
24
28
  name = name.to_sym
25
29
  raise 'Placeholder already exists for that name' if @placeholders[name]
30
+
26
31
  @placeholders[name] = value
27
32
  end
28
33
 
@@ -36,12 +41,23 @@ class LHC::Config
36
41
 
37
42
  def interceptors=(interceptors)
38
43
  raise 'Default interceptors already set and can only be set once' if @interceptors
44
+
39
45
  @interceptors = interceptors
40
46
  end
41
47
 
48
+ def default_scrubs
49
+ {
50
+ auth: [:bearer, :basic],
51
+ params: [],
52
+ headers: [],
53
+ body: ['password', 'password_confirmation']
54
+ }
55
+ end
56
+
42
57
  def reset
43
58
  @endpoints = {}
44
59
  @placeholders = {}
45
60
  @interceptors = nil
61
+ @scrubs = default_scrubs
46
62
  end
47
63
  end
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