julewire-rails 1.0.0 → 1.1.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 (33) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -0
  3. data/docs/capture-and-filtering.md +4 -3
  4. data/docs/configuration.md +3 -2
  5. data/julewire-rails.gemspec +3 -3
  6. data/lib/julewire/rails/configuration.rb +4 -4
  7. data/lib/julewire/rails/context_body_proxy.rb +8 -3
  8. data/lib/julewire/rails/debug_exception_log_silencer.rb +9 -18
  9. data/lib/julewire/rails/doctor_app.rb +21 -21
  10. data/lib/julewire/rails/lifecycle_hooks.rb +0 -11
  11. data/lib/julewire/rails/log_subscriber_silencer.rb +4 -17
  12. data/lib/julewire/rails/logger.rb +29 -24
  13. data/lib/julewire/rails/logger_outputs.rb +0 -3
  14. data/lib/julewire/rails/output_requirement.rb +2 -2
  15. data/lib/julewire/rails/parameter_filter_plan.rb +13 -37
  16. data/lib/julewire/rails/parameter_filter_processor.rb +13 -45
  17. data/lib/julewire/rails/parameter_filters.rb +21 -0
  18. data/lib/julewire/rails/railtie.rb +42 -28
  19. data/lib/julewire/rails/request_attributes.rb +37 -16
  20. data/lib/julewire/rails/request_completion.rb +21 -20
  21. data/lib/julewire/rails/request_context.rb +29 -7
  22. data/lib/julewire/rails/request_error_ownership.rb +11 -19
  23. data/lib/julewire/rails/request_fields.rb +2 -2
  24. data/lib/julewire/rails/request_lifecycle.rb +7 -13
  25. data/lib/julewire/rails/request_middleware.rb +14 -13
  26. data/lib/julewire/rails/request_summary_timeout_scheduler.rb +0 -9
  27. data/lib/julewire/rails/structured_event_record.rb +11 -39
  28. data/lib/julewire/rails/subscribers/controller_response.rb +9 -14
  29. data/lib/julewire/rails/subscribers/error.rb +11 -15
  30. data/lib/julewire/rails/subscribers/event.rb +6 -8
  31. data/lib/julewire/rails/subscribers/rendered_exception.rb +12 -16
  32. data/lib/julewire/rails/version.rb +1 -1
  33. metadata +9 -8
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/parameter_filter"
4
+ require "julewire/rails/parameter_filters"
4
5
 
5
6
  module Julewire
6
7
  module Rails
@@ -8,70 +9,47 @@ module Julewire
8
9
  EMPTY_CONTAINER_MARKER = Core.sentinel(:empty_container)
9
10
  private_constant :EMPTY_CONTAINER_MARKER
10
11
 
11
- def initialize(filters = rails_filter_parameters)
12
+ def initialize(filters = ParameterFilters.configured)
12
13
  @filter = build_filter(filters)
13
14
  # Rails exposes filter_param for scalar fields; use it to avoid whole-record
14
- # copies when the filter list has no Proc semantics to preserve. Regex-only
15
- # filters fall back to whole-record filtering unless they can scalarize a
16
- # required record container.
17
- @filter_param_fast_path = filter_param_safe?(filters) && @filter.respond_to?(:filter_param)
15
+ # copies when the filter list has no Proc semantics to preserve.
16
+ @filter_param_fast_path = filter_param_safe?(filters)
18
17
  @field_plan = ParameterFilterPlan.build(filters) if @filter_param_fast_path
19
18
  end
20
19
 
21
20
  def call(draft)
22
21
  validate_draft!(draft)
23
- return if @filter.nil?
24
-
25
22
  @filter_param_fast_path ? filter_draft_fields!(draft) : filter_whole_record!(draft)
23
+ draft
26
24
  end
27
25
 
28
26
  private
29
27
 
30
28
  def validate_draft!(draft)
31
- return draft if draft.is_a?(Julewire::RecordDraft)
29
+ return if draft.instance_of?(RecordDraft)
32
30
 
33
31
  raise TypeError, "expected Julewire::RecordDraft"
34
32
  end
35
33
 
36
34
  def build_filter(filters)
37
- return filters if filters.respond_to?(:filter) && !filters.is_a?(Array)
38
-
39
- filters = Array(filters)
40
- return if filters.empty?
41
-
42
- ::ActiveSupport::ParameterFilter.new(::ActiveSupport::ParameterFilter.precompile_filters(filters))
35
+ ParameterFilters.build(filters)
43
36
  end
44
37
 
45
38
  def filter_param_safe?(filters)
46
39
  return false if filters.respond_to?(:filter) && !filters.is_a?(Array)
47
40
 
48
41
  filters = Array(filters)
49
- return false if filters.any?(Proc)
50
-
51
- filters.none?(Regexp) || filters.any? { regexp_matches_record_container?(it) }
52
- end
53
-
54
- def regexp_matches_record_container?(filter)
55
- filter.is_a?(Regexp) && Core::Processing::RecordFieldTransform.container_keys.any? { filter.match?(it.name) }
42
+ filters.none?(Proc)
56
43
  end
57
44
 
58
45
  def filter_draft_fields!(draft)
59
- each_filter_field_key(draft) do |key|
60
- next unless draft.key?(key)
61
-
62
- value = draft[key]
46
+ draft.each_key do |key|
47
+ value = draft.fetch(key)
63
48
  next if skip_empty_container?(key, value)
64
49
 
65
50
  filtered = filter_record_param(key, value)
66
- draft.transform_field!(key) { filtered } unless filtered.equal?(value)
51
+ draft.transform_field!(key) { filtered }
67
52
  end
68
- draft
69
- end
70
-
71
- def each_filter_field_key(draft, &)
72
- return @field_plan.filtered_field_keys.each(&) if @field_plan&.filtered_field_keys
73
-
74
- draft.each_key(&)
75
53
  end
76
54
 
77
55
  def filter_whole_record!(draft)
@@ -79,12 +57,10 @@ module Julewire
79
57
  end
80
58
 
81
59
  def filter_record_param(key, value)
82
- if @field_plan&.direct_container_filter? && record_container_key?(key) && value.is_a?(Hash)
83
- return @field_plan.filter_value(value)
84
- end
60
+ return @field_plan.filter_value(value) if @field_plan && record_container_key?(key)
85
61
 
86
62
  filtered = @filter.filter_param(key, value)
87
- return filtered unless record_container_key?(key) && !filtered.is_a?(Hash)
63
+ return filtered unless record_container_key?(key) && !filtered.instance_of?(Hash)
88
64
  return value unless value.is_a?(Hash)
89
65
 
90
66
  @filter.filter(value)
@@ -104,14 +80,6 @@ module Julewire
104
80
  def record_container_key?(key)
105
81
  Core::Processing::RecordFieldTransform.container_key?(key)
106
82
  end
107
-
108
- def rails_filter_parameters
109
- app = ::Rails.application if defined?(::Rails) && ::Rails.respond_to?(:application)
110
- config = app.config if app.respond_to?(:config)
111
- config.filter_parameters if config.respond_to?(:filter_parameters)
112
- rescue StandardError
113
- []
114
- end
115
83
  end
116
84
  end
117
85
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Julewire
4
+ module Rails
5
+ module ParameterFilters
6
+ class << self
7
+ def configured
8
+ Array(::Rails.application.config.filter_parameters)
9
+ rescue StandardError
10
+ []
11
+ end
12
+
13
+ def build(filters)
14
+ return filters if filters.respond_to?(:filter) && !filters.is_a?(Array)
15
+
16
+ ActiveSupport::ParameterFilter.new(Array(filters))
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -9,41 +9,53 @@ module Julewire
9
9
  config.julewire_rails = Configuration.new
10
10
 
11
11
  initializer "julewire_rails.logger", before: :initialize_logger do |app|
12
- settings = app.config.julewire_rails
13
- settings.validate!
14
- next unless settings.logger?
15
-
16
- logger = Logger.new(name: settings.logger_name, source: settings.source)
17
- logger.level = ::Logger::Severity.const_get(app.config.log_level.to_s.upcase)
18
- logger.formatter = app.config.log_formatter if app.config.respond_to?(:log_formatter)
19
- app.config.logger = ::ActiveSupport::TaggedLogging.new(logger)
20
- LoggerOutputs.install!
12
+ Railtie.initialize_logger!(app)
21
13
  end
22
14
 
23
15
  initializer "julewire_rails.request_middleware", before: :build_middleware_stack do |app|
24
- settings = app.config.julewire_rails
25
- settings.validate!
26
- next unless settings.request_middleware?
27
-
28
- self.class.install_request_middleware(app, settings, app.config.log_tags)
16
+ Railtie.initialize_request_middleware!(app)
29
17
  end
30
18
 
31
19
  initializer "julewire_rails.exception_logging", before: :build_middleware_stack do |app|
32
- settings = app.config.julewire_rails
33
- settings.validate!
34
- self.class.configure_exception_logging(app, settings)
20
+ Railtie.initialize_exception_logging!(app)
35
21
  end
36
22
 
37
23
  config.after_initialize do |app|
38
- settings = app.config.julewire_rails
39
- settings.validate!
40
- OutputRequirement.check!(settings)
41
- LifecycleHooks.install!(settings)
42
- Railtie.install_subscribers(settings)
43
- DebugExceptionLogSilencer.install!(settings)
24
+ Railtie.finish_initialization!(app)
44
25
  end
45
26
 
46
27
  class << self
28
+ def initialize_logger!(app)
29
+ settings = validated_settings(app)
30
+ return unless settings.logger?
31
+
32
+ logger = Logger.new(name: settings.logger_name, source: settings.source)
33
+ logger.level = app.config.log_level
34
+ logger.formatter = app.config.log_formatter
35
+ app.config.logger = ::ActiveSupport::TaggedLogging.new(logger)
36
+ LoggerOutputs.install!
37
+ end
38
+
39
+ def initialize_request_middleware!(app)
40
+ settings = validated_settings(app)
41
+ return unless settings.request_middleware?
42
+
43
+ install_request_middleware(app, settings, app.config.log_tags)
44
+ end
45
+
46
+ def initialize_exception_logging!(app)
47
+ settings = validated_settings(app)
48
+ configure_exception_logging(app, settings)
49
+ end
50
+
51
+ def finish_initialization!(app)
52
+ settings = validated_settings(app)
53
+ OutputRequirement.check!(settings)
54
+ LifecycleHooks.install!(settings)
55
+ install_subscribers(settings)
56
+ DebugExceptionLogSilencer.install!(settings)
57
+ end
58
+
47
59
  def install_subscribers(settings)
48
60
  Subscribers::ControllerResponse.install!(settings)
49
61
  settings.error_reports? ? Subscribers::Error.install!(settings) : Subscribers::Error.reset!
@@ -70,13 +82,15 @@ module Julewire
70
82
  end
71
83
 
72
84
  def log_rescued_responses_value(settings)
73
- if settings.log_rescued_responses == :auto
74
- return false if settings.logger? && settings.request_summary?
85
+ return settings.log_rescued_responses unless settings.log_rescued_responses == :auto
75
86
 
76
- return
77
- end
87
+ false if settings.logger? && settings.request_summary?
88
+ end
89
+
90
+ private
78
91
 
79
- settings.log_rescued_responses
92
+ def validated_settings(app)
93
+ app.config.julewire_rails.tap(&:validate!)
80
94
  end
81
95
  end
82
96
  end
@@ -9,7 +9,7 @@ module Julewire
9
9
  values = Core::Integration::Values::Shape
10
10
  {}.tap do |fields|
11
11
  values.append_field(fields, :request_id, request.id)
12
- values.append_field(fields, :http_method, request.method)
12
+ values.append_field(fields, :http_method, request.request_method)
13
13
  values.append_field(fields, :path, request.path)
14
14
  values.append_field(fields, :remote_ip, request.remote_ip)
15
15
  end
@@ -26,16 +26,8 @@ module Julewire
26
26
  }
27
27
  end
28
28
 
29
- def rendered_error_summary(request, rendered_error, status:)
30
- error_summary(
31
- request,
32
- rendered_error.fetch(:error),
33
- status: status,
34
- wrapper: nil
35
- ).tap do |fields|
36
- fields[:attributes][:rails][:rescue_response] = rendered_error[:rescue_response]
37
- fields[:attributes][:rails][:rescue_template] = rendered_error[:rescue_template]
38
- end
29
+ def rendered_error_details(rendered_error)
30
+ apply_rendered_error_metadata(error_details(rendered_error.fetch(:error), wrapper: nil), rendered_error)
39
31
  end
40
32
 
41
33
  def error_summary(request, error, status:, wrapper:)
@@ -45,10 +37,23 @@ module Julewire
45
37
  }
46
38
  end
47
39
 
40
+ def error_details(error, wrapper:)
41
+ {
42
+ attributes: { rails: rails_exception_attributes(error, wrapper: wrapper) },
43
+ neutral: {}
44
+ }
45
+ end
46
+
48
47
  def request_id(request)
49
48
  request_fields(request).id
50
49
  end
51
50
 
51
+ # Rack headers and parsed bodies are user input. Normalize them before
52
+ # passing adapter-owned records to the core integration boundary.
53
+ def normalize_user_fields(fields)
54
+ Core::Fields::FieldSet.deep_symbolize_keys(fields)
55
+ end
56
+
52
57
  private
53
58
 
54
59
  def request_neutral_attributes(request)
@@ -58,7 +63,7 @@ module Julewire
58
63
  values.append_field(
59
64
  fields,
60
65
  Core::Fields::AttributeKeys::HTTP_REQUEST_METHOD,
61
- request.method
66
+ request.request_method
62
67
  )
63
68
  values.append_field(fields, Core::Fields::AttributeKeys::URL_FULL, request.filtered_url)
64
69
  values.append_field(fields, Core::Fields::AttributeKeys::URL_PATH, request.path)
@@ -82,20 +87,36 @@ module Julewire
82
87
  def rails_error_attributes(request, error, status:, wrapper:)
83
88
  rails_request_attributes(request).tap do |rails|
84
89
  values = Core::Integration::Values::Shape
85
- values.append_field(rails, :error_class, error.class.name)
86
90
  values.append_field(rails, :status, status)
87
- values.append_field(rails, :rescue_response, rescue_response?(wrapper))
88
- values.append_field(rails, :rescue_template, rescue_template(wrapper))
91
+ rails_exception_attributes(error, wrapper: wrapper).each do |key, value|
92
+ values.append_field(rails, key, value)
93
+ end
89
94
  end
90
95
  end
91
96
 
97
+ def rails_exception_attributes(error, wrapper:)
98
+ values = Core::Integration::Values::Shape
99
+ {}.tap do |fields|
100
+ values.append_field(fields, :error_class, error.class.name)
101
+ values.append_field(fields, :rescue_response, rescue_response?(wrapper))
102
+ values.append_field(fields, :rescue_template, rescue_template(wrapper))
103
+ end
104
+ end
105
+
106
+ def apply_rendered_error_metadata(fields, rendered_error)
107
+ rails = fields.fetch(:attributes).fetch(:rails)
108
+ rails[:rescue_response] = rendered_error[:rescue_response]
109
+ rails[:rescue_template] = rendered_error[:rescue_template]
110
+ fields
111
+ end
112
+
92
113
  def rails_request_attributes(request)
93
114
  request = request_fields(request)
94
115
  values = Core::Integration::Values::Shape
95
116
  {}.tap do |fields|
96
117
  values.append_field(fields, :filtered_url, request.filtered_url)
97
118
  values.append_field(fields, :filtered_path, request.filtered_path)
98
- values.append_field(fields, :request_method, request.method)
119
+ values.append_field(fields, :request_method, request.request_method)
99
120
  values.append_field(fields, :path, request.path)
100
121
  values.append_field(fields, :user_agent, request.user_agent)
101
122
  end
@@ -1,19 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "concurrent/atomic/atomic_boolean"
4
+
3
5
  module Julewire
4
6
  module Rails
5
7
  class RequestCompletion
6
8
  class << self
7
9
  def finish_instrumentation(instrumenter_handle)
8
- instrumenter_handle&.finish
10
+ instrumenter_handle.finish
9
11
  rescue StandardError
10
12
  nil
11
13
  ensure
12
- begin
13
- ::ActiveSupport::LogSubscriber.flush_all!
14
- rescue StandardError
15
- nil
16
- end
14
+ flush_log_subscribers
15
+ end
16
+
17
+ private
18
+
19
+ def flush_log_subscribers
20
+ ::ActiveSupport::LogSubscriber.flush_all!
21
+ rescue StandardError
22
+ nil
17
23
  end
18
24
  end
19
25
 
@@ -50,21 +56,17 @@ module Julewire
50
56
  response_finished = @env["rack.response_finished"]
51
57
  return unless response_finished.respond_to?(:<<)
52
58
 
53
- response_finished << proc do |_rack_env, _status, _headers, error|
59
+ response_finished << lambda do |_rack_env, _status, _headers, error|
54
60
  finish_once.call(error)
55
61
  end
56
62
  end
57
63
 
58
64
  def completion_callback
59
- mutex = Mutex.new
60
- finished = false
65
+ finished = Concurrent::AtomicBoolean.new
61
66
  lambda do |error|
62
- mutex.synchronize do
63
- return if finished
67
+ return unless finished.make_true
64
68
 
65
- finished = true
66
- end
67
- yield if block_given?
69
+ yield
68
70
  @execution_handle.with_context { finish_completion(error) }
69
71
  end
70
72
  end
@@ -90,12 +92,12 @@ module Julewire
90
92
  end
91
93
 
92
94
  def completion_timeout_context
93
- return {} unless @configuration.request_context?
95
+ return unless @configuration.request_context?
94
96
 
95
97
  {
96
98
  request_id: request_id,
97
99
  path: @request.path
98
- }.compact
100
+ }
99
101
  end
100
102
 
101
103
  def emit_completion_timeout_warning(timeout, context)
@@ -103,17 +105,16 @@ module Julewire
103
105
  event: "request.completion_timeout",
104
106
  logger: @configuration.logger_name,
105
107
  source: @configuration.source,
106
- attributes: { rails: { completion_timeout_ms: (timeout * 1000).round } }
108
+ attributes: { rails: { completion_timeout_ms: (timeout * 1000).round } },
109
+ context: context
107
110
  }
108
- record[:context] = context unless context.empty?
109
111
  Julewire.warn(record)
110
112
  rescue StandardError
111
113
  nil
112
114
  end
113
115
 
114
116
  def request_id
115
- value = @request.request_id if @request.respond_to?(:request_id)
116
- value || @request.get_header("action_dispatch.request_id") || @request.get_header("HTTP_X_REQUEST_ID")
117
+ RequestAttributes.request_id(@request)
117
118
  end
118
119
  end
119
120
  end
@@ -3,7 +3,12 @@
3
3
  module Julewire
4
4
  module Rails
5
5
  class RequestContext
6
- def initialize(configuration:, request:, active_support_context: Core::UNSET, event_reporter: Core::UNSET)
6
+ def initialize(
7
+ configuration:,
8
+ request:,
9
+ active_support_context: Julewire::Core::UNSET,
10
+ event_reporter: Julewire::Core::UNSET
11
+ )
7
12
  @configuration = configuration
8
13
  @request = request
9
14
  @active_support_context = default_provider(active_support_context) { ::ActiveSupport::ExecutionContext }
@@ -23,14 +28,14 @@ module Julewire
23
28
  private
24
29
 
25
30
  def default_provider(value)
26
- value.equal?(Core::UNSET) ? yield : value
31
+ value.equal?(Julewire::Core::UNSET) ? yield : value
27
32
  end
28
33
 
29
34
  def with_request_context(&)
30
35
  return yield unless @configuration.request_context?
31
36
 
32
37
  fields = RequestAttributes.context_fields(@request)
33
- Core::Integration::Facade.with_context(fields) do
38
+ Julewire::Core::Integration::Facade.with_context(fields) do
34
39
  with_active_support_execution_context(fields) do
35
40
  with_rails_event_context(fields, &)
36
41
  end
@@ -41,10 +46,14 @@ module Julewire
41
46
  return yield unless @configuration.carry_request_headers
42
47
  raise ArgumentError, "carry_request_headers must be an explicit header list" if all_carry_headers?
43
48
 
44
- headers = Julewire::Rack::Capture::Headers.request(@request, selector: @configuration.carry_request_headers)
49
+ headers = Julewire::Rack::Capture::Headers.request(
50
+ @request,
51
+ selector: @configuration.carry_request_headers
52
+ )
45
53
  return yield if headers.empty?
46
54
 
47
- Core::Integration::Facade.with_carry(http: { request_headers: headers }, &)
55
+ headers = RequestAttributes.normalize_user_fields(headers)
56
+ Julewire::Core::Integration::Facade.with_carry(http: { request_headers: headers }, &)
48
57
  end
49
58
 
50
59
  def all_carry_headers?
@@ -67,7 +76,7 @@ module Julewire
67
76
  @event_reporter.set_context(fields)
68
77
  context_set = true
69
78
  rescue StandardError
70
- return yield
79
+ nil
71
80
  end
72
81
  yield
73
82
  ensure
@@ -81,8 +90,21 @@ module Julewire
81
90
  end
82
91
 
83
92
  def restore_rails_event_context(previous)
93
+ return unless clear_rails_event_context
94
+ return if previous.nil? || previous.empty?
95
+
96
+ apply_rails_event_context(previous)
97
+ end
98
+
99
+ def clear_rails_event_context
84
100
  @event_reporter.clear_context
85
- @event_reporter.set_context(previous) unless previous.nil? || previous.empty?
101
+ true
102
+ rescue StandardError
103
+ false
104
+ end
105
+
106
+ def apply_rails_event_context(previous)
107
+ @event_reporter.set_context(previous)
86
108
  rescue StandardError
87
109
  nil
88
110
  end
@@ -11,25 +11,19 @@ module Julewire
11
11
  class << self
12
12
  def clear
13
13
  ::ActiveSupport::IsolatedExecutionState.delete(KEY)
14
- rescue StandardError
15
- nil
16
14
  end
17
15
 
18
16
  def mark(error)
19
- return unless error
20
-
21
- errors = error_map
22
- each_exception(error) { errors[it] = true }
23
- rescue StandardError
24
- nil
17
+ each_exception(error) { error_map[it] = true }
25
18
  end
26
19
 
27
20
  def consume?(error)
28
21
  errors = current_error_map
29
22
  return false unless errors
30
23
 
31
- each_exception(error).any? { errors.delete(it) }
32
- rescue StandardError
24
+ each_exception(error) do |exception|
25
+ return true if errors.delete(exception)
26
+ end
33
27
  false
34
28
  end
35
29
 
@@ -40,22 +34,20 @@ module Julewire
40
34
  end
41
35
 
42
36
  def set_error_map
43
- ObjectSpace::WeakKeyMap.new.tap { ::ActiveSupport::IsolatedExecutionState[KEY] = it }
37
+ ObjectSpace::WeakMap.new.tap { ::ActiveSupport::IsolatedExecutionState[KEY] = it }
44
38
  end
45
39
 
46
40
  def current_error_map
47
41
  ::ActiveSupport::IsolatedExecutionState[KEY]
48
42
  end
49
43
 
50
- def each_exception(error)
51
- return enum_for(:each_exception, error) unless block_given?
44
+ def each_exception(error, seen = {}.compare_by_identity, &)
45
+ return unless error
46
+ return if seen.key?(error)
52
47
 
53
- seen = {}.compare_by_identity
54
- while error && !seen.key?(error)
55
- yield error
56
- seen[error] = true
57
- error = error.cause
58
- end
48
+ seen[error] = nil
49
+ yield error
50
+ each_exception(error.cause, seen, &)
59
51
  end
60
52
  end
61
53
  end
@@ -16,7 +16,7 @@ module Julewire
16
16
  nil
17
17
  end
18
18
 
19
- def method
19
+ def request_method
20
20
  @request.request_method
21
21
  end
22
22
 
@@ -40,7 +40,7 @@ module Julewire
40
40
 
41
41
  def remote_ip
42
42
  env = @request.env if @request.respond_to?(:env)
43
- return env[REMOTE_IP_ENV_KEY] if env&.key?(REMOTE_IP_ENV_KEY)
43
+ return env.fetch(REMOTE_IP_ENV_KEY) if env&.key?(REMOTE_IP_ENV_KEY)
44
44
 
45
45
  value = @request.remote_ip
46
46
  env[REMOTE_IP_ENV_KEY] = value if env
@@ -3,23 +3,16 @@
3
3
  module Julewire
4
4
  module Rails
5
5
  class RequestLifecycle
6
- attr_reader :execution_handle
7
-
8
6
  def initialize(configuration:, env:, request:, taggers:)
9
7
  @configuration = configuration
10
8
  @env = env
11
9
  @request = request
12
10
  @taggers = taggers
13
- @completion_attached = false
14
- @execution_handle = nil
15
- @instrumenter_handle = nil
16
- @tag_count = 0
17
11
  end
18
12
 
19
13
  def start
20
14
  @tag_count = push_tags
21
15
  @instrumenter_handle = start_request_instrumentation
22
- self
23
16
  end
24
17
 
25
18
  def start_execution!(neutral:)
@@ -60,7 +53,7 @@ module Julewire
60
53
  private
61
54
 
62
55
  def push_tags
63
- return 0 unless ::Rails.logger.respond_to?(:push_tags)
56
+ return unless ::Rails.logger.respond_to?(:push_tags)
64
57
 
65
58
  ::Rails.logger.push_tags(*compute_tags).size
66
59
  end
@@ -88,12 +81,13 @@ module Julewire
88
81
  end
89
82
 
90
83
  def finish_request_thread_logging
91
- return unless @tag_count.to_i.positive? && ::Rails.logger.respond_to?(:pop_tags)
84
+ return unless @tag_count&.positive?
92
85
 
93
- ::Rails.logger.pop_tags(@tag_count)
94
- @tag_count = 0
95
- rescue StandardError
96
- nil
86
+ begin
87
+ ::Rails.logger.pop_tags(@tag_count)
88
+ rescue StandardError
89
+ nil
90
+ end
97
91
  end
98
92
 
99
93
  def finish_unattached_request