lhc 13.0.0 → 15.0.0

Sign up to get free protection for your applications and to get access to all the features.
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