lhc 12.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 (195) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +37 -0
  3. data/.rubocop.localch.yml +325 -0
  4. data/.rubocop.yml +61 -0
  5. data/.ruby-version +1 -0
  6. data/Gemfile +13 -0
  7. data/Gemfile.activesupport4 +4 -0
  8. data/Gemfile.activesupport5 +4 -0
  9. data/Gemfile.activesupport6 +4 -0
  10. data/LICENSE +674 -0
  11. data/README.md +984 -0
  12. data/Rakefile +25 -0
  13. data/cider-ci.yml +6 -0
  14. data/cider-ci/bin/bundle +51 -0
  15. data/cider-ci/bin/ruby_install +8 -0
  16. data/cider-ci/bin/ruby_version +25 -0
  17. data/cider-ci/jobs/rspec-activesupport-4.yml +28 -0
  18. data/cider-ci/jobs/rspec-activesupport-5.yml +27 -0
  19. data/cider-ci/jobs/rspec-activesupport-6.yml +28 -0
  20. data/cider-ci/jobs/rubocop.yml +18 -0
  21. data/cider-ci/task_components/bundle.yml +22 -0
  22. data/cider-ci/task_components/rspec.yml +36 -0
  23. data/cider-ci/task_components/rubocop.yml +29 -0
  24. data/cider-ci/task_components/ruby.yml +15 -0
  25. data/friday.yml +3 -0
  26. data/lhc.gemspec +39 -0
  27. data/lib/core_ext/hash/deep_transform_values.rb +48 -0
  28. data/lib/lhc.rb +136 -0
  29. data/lib/lhc/concerns/lhc/basic_methods_concern.rb +42 -0
  30. data/lib/lhc/concerns/lhc/configuration_concern.rb +20 -0
  31. data/lib/lhc/concerns/lhc/fix_invalid_encoding_concern.rb +42 -0
  32. data/lib/lhc/concerns/lhc/formats_concern.rb +25 -0
  33. data/lib/lhc/concerns/lhc/request/user_agent_concern.rb +25 -0
  34. data/lib/lhc/config.rb +47 -0
  35. data/lib/lhc/endpoint.rb +119 -0
  36. data/lib/lhc/error.rb +80 -0
  37. data/lib/lhc/errors/client_error.rb +73 -0
  38. data/lib/lhc/errors/parser_error.rb +4 -0
  39. data/lib/lhc/errors/server_error.rb +28 -0
  40. data/lib/lhc/errors/timeout.rb +4 -0
  41. data/lib/lhc/errors/unknown_error.rb +4 -0
  42. data/lib/lhc/format.rb +18 -0
  43. data/lib/lhc/formats.rb +8 -0
  44. data/lib/lhc/formats/form.rb +45 -0
  45. data/lib/lhc/formats/json.rb +55 -0
  46. data/lib/lhc/formats/multipart.rb +45 -0
  47. data/lib/lhc/formats/plain.rb +42 -0
  48. data/lib/lhc/interceptor.rb +32 -0
  49. data/lib/lhc/interceptors.rb +26 -0
  50. data/lib/lhc/interceptors/auth.rb +98 -0
  51. data/lib/lhc/interceptors/caching.rb +127 -0
  52. data/lib/lhc/interceptors/default_timeout.rb +16 -0
  53. data/lib/lhc/interceptors/logging.rb +37 -0
  54. data/lib/lhc/interceptors/monitoring.rb +63 -0
  55. data/lib/lhc/interceptors/prometheus.rb +51 -0
  56. data/lib/lhc/interceptors/retry.rb +41 -0
  57. data/lib/lhc/interceptors/rollbar.rb +36 -0
  58. data/lib/lhc/interceptors/throttle.rb +81 -0
  59. data/lib/lhc/interceptors/zipkin.rb +110 -0
  60. data/lib/lhc/railtie.rb +10 -0
  61. data/lib/lhc/request.rb +157 -0
  62. data/lib/lhc/response.rb +60 -0
  63. data/lib/lhc/response/data.rb +28 -0
  64. data/lib/lhc/response/data/base.rb +22 -0
  65. data/lib/lhc/response/data/collection.rb +16 -0
  66. data/lib/lhc/response/data/item.rb +29 -0
  67. data/lib/lhc/rspec.rb +12 -0
  68. data/lib/lhc/test/cache_helper.rb +3 -0
  69. data/lib/lhc/version.rb +5 -0
  70. data/script/ci/build.sh +19 -0
  71. data/spec/basic_methods/delete_spec.rb +34 -0
  72. data/spec/basic_methods/get_spec.rb +49 -0
  73. data/spec/basic_methods/post_spec.rb +42 -0
  74. data/spec/basic_methods/put_spec.rb +48 -0
  75. data/spec/basic_methods/request_spec.rb +19 -0
  76. data/spec/basic_methods/request_without_rails_spec.rb +29 -0
  77. data/spec/config/endpoints_spec.rb +63 -0
  78. data/spec/config/placeholders_spec.rb +32 -0
  79. data/spec/core_ext/hash/deep_transform_values_spec.rb +24 -0
  80. data/spec/dummy/README.rdoc +28 -0
  81. data/spec/dummy/Rakefile +8 -0
  82. data/spec/dummy/app/assets/config/manifest.js +3 -0
  83. data/spec/dummy/app/assets/images/.keep +0 -0
  84. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  85. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  86. data/spec/dummy/app/controllers/application_controller.rb +7 -0
  87. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  88. data/spec/dummy/app/helpers/application_helper.rb +4 -0
  89. data/spec/dummy/app/mailers/.keep +0 -0
  90. data/spec/dummy/app/models/.keep +0 -0
  91. data/spec/dummy/app/models/concerns/.keep +0 -0
  92. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  93. data/spec/dummy/bin/bundle +5 -0
  94. data/spec/dummy/bin/rails +6 -0
  95. data/spec/dummy/bin/rake +6 -0
  96. data/spec/dummy/config.ru +6 -0
  97. data/spec/dummy/config/application.rb +16 -0
  98. data/spec/dummy/config/boot.rb +7 -0
  99. data/spec/dummy/config/environment.rb +7 -0
  100. data/spec/dummy/config/environments/development.rb +36 -0
  101. data/spec/dummy/config/environments/production.rb +77 -0
  102. data/spec/dummy/config/environments/test.rb +41 -0
  103. data/spec/dummy/config/initializers/assets.rb +10 -0
  104. data/spec/dummy/config/initializers/backtrace_silencers.rb +9 -0
  105. data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
  106. data/spec/dummy/config/initializers/filter_parameter_logging.rb +6 -0
  107. data/spec/dummy/config/initializers/inflections.rb +18 -0
  108. data/spec/dummy/config/initializers/mime_types.rb +6 -0
  109. data/spec/dummy/config/initializers/session_store.rb +5 -0
  110. data/spec/dummy/config/initializers/wrap_parameters.rb +11 -0
  111. data/spec/dummy/config/locales/en.yml +23 -0
  112. data/spec/dummy/config/routes.rb +58 -0
  113. data/spec/dummy/config/secrets.yml +22 -0
  114. data/spec/dummy/lib/assets/.keep +0 -0
  115. data/spec/dummy/log/.keep +0 -0
  116. data/spec/dummy/public/404.html +67 -0
  117. data/spec/dummy/public/422.html +67 -0
  118. data/spec/dummy/public/500.html +66 -0
  119. data/spec/dummy/public/favicon.ico +0 -0
  120. data/spec/endpoint/compile_spec.rb +35 -0
  121. data/spec/endpoint/match_spec.rb +41 -0
  122. data/spec/endpoint/placeholders_spec.rb +30 -0
  123. data/spec/endpoint/remove_interpolated_params_spec.rb +17 -0
  124. data/spec/endpoint/values_as_params_spec.rb +31 -0
  125. data/spec/error/dup_spec.rb +12 -0
  126. data/spec/error/find_spec.rb +57 -0
  127. data/spec/error/response_spec.rb +17 -0
  128. data/spec/error/timeout_spec.rb +14 -0
  129. data/spec/error/to_s_spec.rb +80 -0
  130. data/spec/formats/form_spec.rb +27 -0
  131. data/spec/formats/json_spec.rb +66 -0
  132. data/spec/formats/multipart_spec.rb +26 -0
  133. data/spec/formats/plain_spec.rb +29 -0
  134. data/spec/interceptors/after_request_spec.rb +20 -0
  135. data/spec/interceptors/after_response_spec.rb +39 -0
  136. data/spec/interceptors/auth/basic_auth_spec.rb +17 -0
  137. data/spec/interceptors/auth/bearer_spec.rb +19 -0
  138. data/spec/interceptors/auth/reauthentication_configuration_spec.rb +61 -0
  139. data/spec/interceptors/auth/reauthentication_spec.rb +44 -0
  140. data/spec/interceptors/before_request_spec.rb +21 -0
  141. data/spec/interceptors/before_response_spec.rb +20 -0
  142. data/spec/interceptors/caching/hydra_spec.rb +26 -0
  143. data/spec/interceptors/caching/main_spec.rb +73 -0
  144. data/spec/interceptors/caching/methods_spec.rb +42 -0
  145. data/spec/interceptors/caching/options_spec.rb +89 -0
  146. data/spec/interceptors/caching/parameters_spec.rb +24 -0
  147. data/spec/interceptors/caching/response_status_spec.rb +29 -0
  148. data/spec/interceptors/caching/to_cache_spec.rb +16 -0
  149. data/spec/interceptors/default_interceptors_spec.rb +15 -0
  150. data/spec/interceptors/default_timeout/main_spec.rb +34 -0
  151. data/spec/interceptors/define_spec.rb +29 -0
  152. data/spec/interceptors/dup_spec.rb +19 -0
  153. data/spec/interceptors/logging/main_spec.rb +37 -0
  154. data/spec/interceptors/monitoring/main_spec.rb +97 -0
  155. data/spec/interceptors/prometheus_spec.rb +54 -0
  156. data/spec/interceptors/response_competition_spec.rb +41 -0
  157. data/spec/interceptors/retry/main_spec.rb +73 -0
  158. data/spec/interceptors/return_response_spec.rb +38 -0
  159. data/spec/interceptors/rollbar/invalid_encoding_spec.rb +43 -0
  160. data/spec/interceptors/rollbar/main_spec.rb +57 -0
  161. data/spec/interceptors/throttle/main_spec.rb +106 -0
  162. data/spec/interceptors/throttle/reset_track_spec.rb +53 -0
  163. data/spec/interceptors/zipkin/distributed_tracing_spec.rb +135 -0
  164. data/spec/rails_helper.rb +6 -0
  165. data/spec/request/body_spec.rb +39 -0
  166. data/spec/request/encoding_spec.rb +37 -0
  167. data/spec/request/error_handling_spec.rb +88 -0
  168. data/spec/request/headers_spec.rb +12 -0
  169. data/spec/request/ignore_errors_spec.rb +73 -0
  170. data/spec/request/option_dup_spec.rb +13 -0
  171. data/spec/request/parallel_requests_spec.rb +59 -0
  172. data/spec/request/params_encoding_spec.rb +26 -0
  173. data/spec/request/request_without_rails_spec.rb +15 -0
  174. data/spec/request/url_patterns_spec.rb +54 -0
  175. data/spec/request/user_agent_spec.rb +26 -0
  176. data/spec/request/user_agent_without_rails_spec.rb +27 -0
  177. data/spec/response/body_spec.rb +16 -0
  178. data/spec/response/code_spec.rb +16 -0
  179. data/spec/response/data_accessor_spec.rb +29 -0
  180. data/spec/response/data_spec.rb +61 -0
  181. data/spec/response/effective_url_spec.rb +16 -0
  182. data/spec/response/headers_spec.rb +18 -0
  183. data/spec/response/options_spec.rb +18 -0
  184. data/spec/response/success_spec.rb +13 -0
  185. data/spec/response/time_spec.rb +21 -0
  186. data/spec/spec_helper.rb +8 -0
  187. data/spec/support/fixtures/json/feedback.json +11 -0
  188. data/spec/support/fixtures/json/feedbacks.json +164 -0
  189. data/spec/support/fixtures/json/localina_content_ad.json +23 -0
  190. data/spec/support/load_json.rb +5 -0
  191. data/spec/support/reset_config.rb +7 -0
  192. data/spec/support/zipkin_mock.rb +113 -0
  193. data/spec/timeouts/no_signal_spec.rb +13 -0
  194. data/spec/timeouts/timings_spec.rb +55 -0
  195. metadata +534 -0
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ class LHC::DefaultTimeout < LHC::Interceptor
4
+ include ActiveSupport::Configurable
5
+
6
+ config_accessor :timeout, :connecttimeout
7
+
8
+ CONNECTTIMEOUT = 2 # seconds
9
+ TIMEOUT = 15 # seconds
10
+
11
+ def before_raw_request
12
+ request_options = (request.options || {})
13
+ request_options[:timeout] ||= timeout || TIMEOUT
14
+ request_options[:connecttimeout] ||= connecttimeout || CONNECTTIMEOUT
15
+ end
16
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ class LHC::Logging < LHC::Interceptor
4
+
5
+ include ActiveSupport::Configurable
6
+ config_accessor :logger
7
+
8
+ def before_request
9
+ return unless logger
10
+ logger.info(
11
+ [
12
+ 'Before LHC request',
13
+ "<#{request.object_id}>",
14
+ request.method.upcase,
15
+ "#{request.url} at #{Time.now.iso8601}",
16
+ "Params=#{request.params}",
17
+ "Headers=#{request.headers}",
18
+ request.source ? "\nCalled from #{request.source}" : nil
19
+ ].compact.join(' ')
20
+ )
21
+ end
22
+
23
+ def after_response
24
+ return unless logger
25
+ logger.info(
26
+ [
27
+ 'After LHC response for request',
28
+ "<#{request.object_id}>",
29
+ request.method.upcase,
30
+ "#{request.url} at #{Time.now.iso8601}",
31
+ "Time=#{response.time_ms}ms",
32
+ "URL=#{response.effective_url}",
33
+ request.source ? "\nCalled from #{request.source}" : nil
34
+ ].compact.join(' ')
35
+ )
36
+ end
37
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ class LHC::Monitoring < LHC::Interceptor
4
+
5
+ # Options forwarded to the monitoring
6
+ FORWARDED_OPTIONS = {
7
+ monitoring_key: :key
8
+ }
9
+
10
+ include ActiveSupport::Configurable
11
+
12
+ config_accessor :statsd, :env
13
+
14
+ def before_request
15
+ return unless statsd
16
+ LHC::Monitoring.statsd.count("#{key(request)}.before_request", 1)
17
+ end
18
+
19
+ def after_request
20
+ return unless statsd
21
+ LHC::Monitoring.statsd.count("#{key(request)}.count", 1)
22
+ LHC::Monitoring.statsd.count("#{key(request)}.after_request", 1)
23
+ end
24
+
25
+ def after_response
26
+ return unless statsd
27
+ key = key(response)
28
+ LHC::Monitoring.statsd.timing("#{key}.time", response.time) if response.success?
29
+ key += response.timeout? ? '.timeout' : ".#{response.code}"
30
+ LHC::Monitoring.statsd.count(key, 1)
31
+ end
32
+
33
+ private
34
+
35
+ def key(target)
36
+ request = target.is_a?(LHC::Request) ? target : target.request
37
+ key = options(request.options)[:key]
38
+ return key if key.present?
39
+
40
+ url = sanitize_url(request.url)
41
+ key = [
42
+ 'lhc',
43
+ Rails.application.class.parent_name.underscore,
44
+ LHC::Monitoring.env || Rails.env,
45
+ URI.parse(url).host.gsub(/\./, '_'),
46
+ request.method
47
+ ]
48
+ key.join('.')
49
+ end
50
+
51
+ def sanitize_url(url)
52
+ return url if url.match(%r{https?://})
53
+ "http://#{url}"
54
+ end
55
+
56
+ def options(input = {})
57
+ options = {}
58
+ FORWARDED_OPTIONS.each do |k, v|
59
+ options[v] = input[k] if input.key?(k)
60
+ end
61
+ options
62
+ end
63
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ class LHC::Prometheus < LHC::Interceptor
4
+ include ActiveSupport::Configurable
5
+
6
+ config_accessor :client, :namespace
7
+
8
+ REQUEST_COUNTER_KEY = :lhc_requests
9
+ REQUEST_HISTOGRAM_KEY = :lhc_request_seconds
10
+
11
+ class << self
12
+ attr_accessor :registered
13
+ end
14
+
15
+ def initialize(request)
16
+ super(request)
17
+ return if LHC::Prometheus.registered || LHC::Prometheus.client.blank?
18
+
19
+ begin
20
+ LHC::Prometheus.client.registry.counter(LHC::Prometheus::REQUEST_COUNTER_KEY, 'Counter of all LHC requests.')
21
+ LHC::Prometheus.client.registry.histogram(LHC::Prometheus::REQUEST_HISTOGRAM_KEY, 'Request timings for all LHC requests in seconds.')
22
+ rescue Prometheus::Client::Registry::AlreadyRegisteredError => e
23
+ Rails.logger.error(e) if defined?(Rails)
24
+ ensure
25
+ LHC::Prometheus.registered = true
26
+ end
27
+ end
28
+
29
+ def after_response
30
+ return if !LHC::Prometheus.registered || LHC::Prometheus.client.blank?
31
+
32
+ host = URI.parse(request.url).host
33
+
34
+ LHC::Prometheus.client.registry
35
+ .get(LHC::Prometheus::REQUEST_COUNTER_KEY)
36
+ .increment(
37
+ code: response.code,
38
+ success: response.success?,
39
+ timeout: response.timeout?,
40
+ host: host,
41
+ app: LHC::Prometheus.namespace
42
+ )
43
+
44
+ LHC::Prometheus.client.registry
45
+ .get(LHC::Prometheus::REQUEST_HISTOGRAM_KEY)
46
+ .observe({
47
+ host: host,
48
+ app: LHC::Prometheus.namespace
49
+ }, response.time)
50
+ end
51
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ class LHC::Retry < LHC::Interceptor
4
+ attr_accessor :retries, :current_retry
5
+
6
+ class << self
7
+ attr_accessor :max, :all
8
+ end
9
+
10
+ def after_response
11
+ response.request.options[:retries] ||= 0
12
+ return unless retry?(response.request)
13
+ response.request.options[:retries] += 1
14
+ current_retry = response.request.options[:retries]
15
+ begin
16
+ response.request.run!
17
+ rescue LHC::Error
18
+ return
19
+ end
20
+ response.request.response if current_retry == response.request.options[:retries]
21
+ end
22
+
23
+ private
24
+
25
+ def retry?(request)
26
+ return false if request.response.success?
27
+ return false if request.error_ignored?
28
+ return false if !request.options.dig(:retry) && !LHC::Retry.all
29
+ request.options[:retries] < max(request)
30
+ end
31
+
32
+ def max(request)
33
+ options(request).is_a?(Hash) ? options(request).fetch(:max, LHC::Retry.max) : LHC::Retry.max
34
+ end
35
+
36
+ def options(request)
37
+ @options ||= request.options.dig(:retry)
38
+ end
39
+ end
40
+
41
+ LHC::Retry.max = 3
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'core_ext/hash/deep_transform_values'
4
+
5
+ class LHC::Rollbar < LHC::Interceptor
6
+ include ActiveSupport::Configurable
7
+ include LHC::FixInvalidEncodingConcern
8
+
9
+ def after_response
10
+ return unless Object.const_defined?('Rollbar')
11
+ return if response.success?
12
+ request = response.request
13
+ additional_params = request.options.fetch(:rollbar, {})
14
+ data = {
15
+ response: {
16
+ body: response.body,
17
+ code: response.code,
18
+ headers: response.headers,
19
+ time: response.time,
20
+ timeout?: response.timeout?
21
+ },
22
+ request: {
23
+ url: request.url,
24
+ method: request.method,
25
+ headers: request.headers,
26
+ params: request.params
27
+ }
28
+ }.merge additional_params
29
+ begin
30
+ Rollbar.warning("Status: #{response.code} URL: #{request.url}", data)
31
+ rescue Encoding::UndefinedConversionError
32
+ sanitized_data = data.deep_transform_values { |value| self.class.fix_invalid_encoding(value) }
33
+ Rollbar.warning("Status: #{response.code} URL: #{request.url}", sanitized_data)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/duration'
4
+
5
+ class LHC::Throttle < LHC::Interceptor
6
+
7
+ class OutOfQuota < StandardError
8
+ end
9
+
10
+ class << self
11
+ attr_accessor :track
12
+ end
13
+
14
+ def before_request
15
+ options = request.options.dig(:throttle)
16
+ return unless options
17
+ break_options = options.dig(:break)
18
+ return unless break_options
19
+ break_when_quota_reached! if break_options.match('%')
20
+ end
21
+
22
+ def after_response
23
+ options = response.request.options.dig(:throttle)
24
+ return unless options
25
+ return unless options.dig(:track)
26
+ self.class.track ||= {}
27
+ self.class.track[options.dig(:provider)] = {
28
+ limit: limit(options: options[:limit], response: response),
29
+ remaining: remaining(options: options[:remaining], response: response),
30
+ expires: expires(options: options[:expires], response: response)
31
+ }
32
+ end
33
+
34
+ private
35
+
36
+ def break_when_quota_reached!
37
+ options = request.options.dig(:throttle)
38
+ track = (self.class.track || {}).dig(options[:provider])
39
+ return if track.blank? || track[:remaining].blank? || track[:limit].blank? || track[:expires].blank?
40
+ return if Time.zone.now > track[:expires]
41
+ # avoid floats by multiplying with 100
42
+ remaining = track[:remaining] * 100
43
+ limit = track[:limit]
44
+ quota = 100 - options[:break].to_i
45
+ raise(OutOfQuota, "Reached predefined quota for #{options[:provider]}") if remaining < quota * limit
46
+ end
47
+
48
+ def limit(options:, response:)
49
+ @limit ||= begin
50
+ if options.is_a?(Integer)
51
+ options
52
+ elsif options.is_a?(Hash) && options[:header] && response.headers.present?
53
+ response.headers[options[:header]]&.to_i
54
+ end
55
+ end
56
+ end
57
+
58
+ def remaining(options:, response:)
59
+ @remaining ||= begin
60
+ if options.is_a?(Hash) && options[:header] && response.headers.present?
61
+ response.headers[options[:header]]&.to_i
62
+ end
63
+ end
64
+ end
65
+
66
+ def expires(options:, response:)
67
+ @expires ||= begin
68
+ if options.is_a?(Hash) && options[:header] && response.headers.present?
69
+ convert_expires(response.headers[options[:header]]&.to_i)
70
+ else
71
+ convert_expires(options)
72
+ end
73
+ end
74
+ end
75
+
76
+ def convert_expires(value)
77
+ if value.is_a?(Integer)
78
+ Time.zone.at(value).to_datetime
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ class LHC::Zipkin < LHC::Interceptor
4
+ B3_HEADERS = {
5
+ trace_id: 'X-B3-TraceId',
6
+ parent_id: 'X-B3-ParentSpanId',
7
+ span_id: 'X-B3-SpanId',
8
+ sampled: 'X-B3-Sampled',
9
+ flags: 'X-B3-Flags'
10
+ }.freeze
11
+ TRUE = '1' # true in binary annotation
12
+
13
+ def before_request
14
+ return if !dependencies? || !tracing?
15
+ ZipkinTracer::TraceContainer.with_trace_id(trace_id) do
16
+ # add headers even if the current trace_id should not be sampled
17
+ B3_HEADERS.each { |method, header| request.headers[header] = trace_id.send(method).to_s }
18
+ # only sample the current call if we're instructed to do so
19
+ start_trace! if ::Trace.tracer && trace_id.sampled?
20
+ end
21
+ end
22
+
23
+ def after_response
24
+ # only sample the current call if we're instructed to do so
25
+ return unless dependencies? && trace_id.sampled?
26
+ end_trace!
27
+ end
28
+
29
+ private
30
+
31
+ def tracing?
32
+ ZipkinTracer::TraceContainer.current
33
+ end
34
+
35
+ def start_trace!
36
+ record_path
37
+ record_remote_endpoint
38
+ record_local_endpoint
39
+ end
40
+
41
+ def end_trace!
42
+ record_status
43
+ record_error if !response.success?
44
+ record_end
45
+ end
46
+
47
+ def trace_id
48
+ @trace_id ||= ZipkinTracer::TraceGenerator.new.next_trace_id
49
+ end
50
+
51
+ # register a new span with zipkin tracer
52
+ def span
53
+ @span ||= ::Trace.tracer.start_span(trace_id, url.path)
54
+ end
55
+
56
+ def url
57
+ @url ||= URI(request.raw.url)
58
+ end
59
+
60
+ def status
61
+ @status ||= response.code.to_s
62
+ end
63
+
64
+ def service_name
65
+ @service_name ||= url.host
66
+ end
67
+
68
+ def record_local_endpoint
69
+ span.record(::Trace::Annotation::CLIENT_SEND, local_endpoint)
70
+ end
71
+
72
+ def record_remote_endpoint
73
+ span.record_tag(::Trace::BinaryAnnotation::SERVER_ADDRESS, TRUE, ::Trace::BinaryAnnotation::Type::BOOL, remote_endpoint)
74
+ end
75
+
76
+ def record_path
77
+ span.record_tag(::Trace::BinaryAnnotation::PATH, url.path, ::Trace::BinaryAnnotation::Type::STRING, local_endpoint)
78
+ end
79
+
80
+ def record_end
81
+ span.record(::Trace::Annotation::CLIENT_RECV, local_endpoint)
82
+ ::Trace.tracer.end_span(span)
83
+ end
84
+
85
+ def record_error
86
+ span.record_tag(::Trace::BinaryAnnotation::ERROR, status, ::Trace::BinaryAnnotation::Type::STRING, local_endpoint)
87
+ end
88
+
89
+ def record_status
90
+ span.record_tag(::Trace::BinaryAnnotation::STATUS, status, ::Trace::BinaryAnnotation::Type::STRING, local_endpoint)
91
+ end
92
+
93
+ def local_endpoint
94
+ @local_endpoint ||= ::Trace.default_endpoint
95
+ end
96
+
97
+ def remote_endpoint
98
+ @remote_endpoint ||= ::Trace::Endpoint.remote_endpoint(url, service_name, local_endpoint.ip_format)
99
+ end
100
+
101
+ def dependencies?
102
+ (
103
+ defined?(ZipkinTracer::TraceContainer) &&
104
+ defined?(::Trace) &&
105
+ defined?(::Trace::Annotation) &&
106
+ defined?(::Trace::BinaryAnnotation) &&
107
+ defined?(::Trace::Endpoint)
108
+ ) || warn('[WARNING] Zipkin interceptor is enabled but dependencies are not found. See: https://github.com/local-ch/lhc#zipkin')
109
+ end
110
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LHC
4
+ class Railtie < Rails::Railtie
5
+ initializer "lhc.configure_rails_initialization" do
6
+ LHC::Caching.cache ||= Rails.cache
7
+ LHC::Caching.logger ||= Rails.logger
8
+ end
9
+ end
10
+ end