skylight 5.0.1 → 5.1.1

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 (79) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +395 -364
  3. data/CLA.md +1 -1
  4. data/LICENSE.md +7 -17
  5. data/README.md +1 -1
  6. data/ext/extconf.rb +42 -54
  7. data/ext/libskylight.yml +9 -6
  8. data/lib/skylight.rb +20 -30
  9. data/lib/skylight/api.rb +22 -18
  10. data/lib/skylight/cli.rb +47 -46
  11. data/lib/skylight/cli/doctor.rb +50 -50
  12. data/lib/skylight/cli/helpers.rb +19 -19
  13. data/lib/skylight/cli/merger.rb +141 -139
  14. data/lib/skylight/config.rb +265 -300
  15. data/lib/skylight/deprecation.rb +4 -4
  16. data/lib/skylight/errors.rb +3 -4
  17. data/lib/skylight/extensions.rb +17 -29
  18. data/lib/skylight/extensions/source_location.rb +128 -128
  19. data/lib/skylight/formatters/http.rb +1 -3
  20. data/lib/skylight/gc.rb +30 -40
  21. data/lib/skylight/helpers.rb +43 -41
  22. data/lib/skylight/instrumenter.rb +25 -18
  23. data/lib/skylight/middleware.rb +31 -35
  24. data/lib/skylight/native.rb +8 -10
  25. data/lib/skylight/native_ext_fetcher.rb +10 -12
  26. data/lib/skylight/normalizers.rb +43 -39
  27. data/lib/skylight/normalizers/action_controller/process_action.rb +24 -25
  28. data/lib/skylight/normalizers/action_controller/send_file.rb +7 -6
  29. data/lib/skylight/normalizers/action_dispatch/route_set.rb +7 -7
  30. data/lib/skylight/normalizers/active_job/perform.rb +48 -44
  31. data/lib/skylight/normalizers/active_model_serializers/render.rb +7 -3
  32. data/lib/skylight/normalizers/active_storage.rb +11 -13
  33. data/lib/skylight/normalizers/active_support/cache.rb +1 -12
  34. data/lib/skylight/normalizers/coach/handler_finish.rb +1 -3
  35. data/lib/skylight/normalizers/default.rb +1 -9
  36. data/lib/skylight/normalizers/faraday/request.rb +1 -3
  37. data/lib/skylight/normalizers/grape/endpoint.rb +13 -19
  38. data/lib/skylight/normalizers/grape/endpoint_run.rb +16 -18
  39. data/lib/skylight/normalizers/grape/endpoint_run_filters.rb +1 -3
  40. data/lib/skylight/normalizers/graphql/base.rb +23 -28
  41. data/lib/skylight/normalizers/render.rb +19 -21
  42. data/lib/skylight/normalizers/shrine.rb +15 -17
  43. data/lib/skylight/normalizers/sql.rb +4 -4
  44. data/lib/skylight/probes.rb +38 -46
  45. data/lib/skylight/probes/action_controller.rb +32 -28
  46. data/lib/skylight/probes/action_dispatch/request_id.rb +9 -5
  47. data/lib/skylight/probes/action_dispatch/routing/route_set.rb +7 -5
  48. data/lib/skylight/probes/action_view.rb +9 -10
  49. data/lib/skylight/probes/active_job_enqueue.rb +3 -9
  50. data/lib/skylight/probes/active_model_serializers.rb +8 -8
  51. data/lib/skylight/probes/delayed_job.rb +37 -42
  52. data/lib/skylight/probes/elasticsearch.rb +3 -5
  53. data/lib/skylight/probes/excon.rb +1 -1
  54. data/lib/skylight/probes/excon/middleware.rb +22 -23
  55. data/lib/skylight/probes/graphql.rb +2 -7
  56. data/lib/skylight/probes/middleware.rb +14 -5
  57. data/lib/skylight/probes/mongo.rb +83 -91
  58. data/lib/skylight/probes/net_http.rb +1 -1
  59. data/lib/skylight/probes/redis.rb +5 -17
  60. data/lib/skylight/probes/sequel.rb +7 -11
  61. data/lib/skylight/probes/sinatra.rb +8 -5
  62. data/lib/skylight/probes/tilt.rb +2 -4
  63. data/lib/skylight/railtie.rb +121 -135
  64. data/lib/skylight/sidekiq.rb +4 -5
  65. data/lib/skylight/subscriber.rb +31 -33
  66. data/lib/skylight/test.rb +89 -84
  67. data/lib/skylight/trace.rb +121 -115
  68. data/lib/skylight/user_config.rb +14 -17
  69. data/lib/skylight/util/clock.rb +1 -0
  70. data/lib/skylight/util/component.rb +18 -21
  71. data/lib/skylight/util/deploy.rb +11 -13
  72. data/lib/skylight/util/http.rb +104 -105
  73. data/lib/skylight/util/logging.rb +4 -6
  74. data/lib/skylight/util/lru_cache.rb +2 -6
  75. data/lib/skylight/util/platform.rb +2 -6
  76. data/lib/skylight/util/ssl.rb +1 -25
  77. data/lib/skylight/version.rb +1 -1
  78. data/lib/skylight/vm/gc.rb +1 -9
  79. metadata +6 -6
@@ -11,9 +11,7 @@ module Skylight
11
11
  # @param [String] query Request query string
12
12
  # @return [Hash] a hash containing `:category`, `:title`, and `:annotations`
13
13
  def self.build_opts(method, _scheme, host, _port, _path, _query)
14
- { category: "api.http.#{method.downcase}",
15
- title: "#{method.upcase} #{host}",
16
- internal: true }
14
+ { category: "api.http.#{method.downcase}", title: "#{method.upcase} #{host}", internal: true }
17
15
  end
18
16
  end
19
17
  end
data/lib/skylight/gc.rb CHANGED
@@ -3,10 +3,10 @@ require "skylight/util/logging"
3
3
  module Skylight
4
4
  # @api private
5
5
  class GC
6
- METHODS = %i[enable total_time].freeze
7
- TH_KEY = :SK_GC_CURR_WINDOW
6
+ METHODS = %i[enable total_time].freeze
7
+ TH_KEY = :SK_GC_CURR_WINDOW
8
8
  MAX_COUNT = 1000
9
- MAX_TIME = 30_000_000
9
+ MAX_TIME = 30_000_000
10
10
 
11
11
  include Util::Logging
12
12
 
@@ -14,9 +14,9 @@ module Skylight
14
14
 
15
15
  def initialize(config, profiler)
16
16
  @listeners = []
17
- @config = config
18
- @lock = Mutex.new
19
- @time = 0
17
+ @config = config
18
+ @lock = Mutex.new
19
+ @time = 0
20
20
 
21
21
  if METHODS.all? { |m| profiler.respond_to?(m) }
22
22
  @profiler = profiler
@@ -46,9 +46,7 @@ module Skylight
46
46
  # Cleanup any listeners that might have leaked
47
47
  @listeners.shift until @listeners[0].time < MAX_TIME
48
48
 
49
- if @listeners.length > MAX_COUNT
50
- @listeners.shift
51
- end
49
+ @listeners.shift if @listeners.length > MAX_COUNT
52
50
  end
53
51
 
54
52
  win
@@ -58,52 +56,44 @@ module Skylight
58
56
  end
59
57
 
60
58
  def release(win)
61
- @lock.synchronize do
62
- @listeners.delete(win)
63
- end
59
+ @lock.synchronize { @listeners.delete(win) }
64
60
  end
65
61
 
66
62
  def update
67
- @lock.synchronize do
68
- __update
69
- end
63
+ @lock.synchronize { __update }
70
64
 
71
65
  nil
72
66
  end
73
67
 
74
68
  private
75
69
 
76
- def __update
77
- time = @profiler.total_time
78
- diff = time - @time
79
- @time = time
70
+ def __update
71
+ time = @profiler.total_time
72
+ diff = time - @time
73
+ @time = time
80
74
 
81
- if diff > 0
82
- @listeners.each do |l|
83
- l.add(diff)
84
- end
85
- end
86
- end
75
+ @listeners.each { |l| l.add(diff) } if diff > 0
76
+ end
87
77
 
88
- class Window
89
- attr_reader :time
78
+ class Window
79
+ attr_reader :time
90
80
 
91
- def initialize(global)
92
- @global = global
93
- @time = 0
94
- end
81
+ def initialize(global)
82
+ @global = global
83
+ @time = 0
84
+ end
95
85
 
96
- def update
97
- @global&.update
98
- end
86
+ def update
87
+ @global&.update
88
+ end
99
89
 
100
- def add(time)
101
- @time += time
102
- end
90
+ def add(time)
91
+ @time += time
92
+ end
103
93
 
104
- def release
105
- @global&.release(self)
106
- end
94
+ def release
95
+ @global&.release(self)
107
96
  end
97
+ end
108
98
  end
109
99
  end
@@ -130,47 +130,47 @@ module Skylight
130
130
 
131
131
  private
132
132
 
133
- HAS_ARGUMENT_FORWARDING = Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.7.0")
133
+ HAS_ARGUMENT_FORWARDING = Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.7.0")
134
134
 
135
- def __sk_instrument_method_on(klass, name, title, **opts)
136
- category = (opts[:category] || "app.method").to_s
137
- title = (opts[:title] || title).to_s
138
- desc = opts[:description].to_s if opts[:description]
135
+ def __sk_instrument_method_on(klass, name, title, **opts)
136
+ category = (opts[:category] || "app.method").to_s
137
+ title = (opts[:title] || title).to_s
138
+ desc = opts[:description].to_s if opts[:description]
139
139
 
140
- # NOTE: The source location logic happens before we have have a config so we can'
141
- # check if source locations are enabled. However, it only happens once so the potential impact
142
- # should be minimal. This would more appropriately belong to Extensions::SourceLocation,
143
- # but as that is a runtime concern, and this happens at compile time, there isn't currently
144
- # a clean way to turn this on and off. The absence of the extension will cause the
145
- # source_file and source_line to be removed from the trace span before it is submitted.
146
- source_file, source_line = klass.instance_method(name).source_location
140
+ # NOTE: The source location logic happens before we have have a config so we can'
141
+ # check if source locations are enabled. However, it only happens once so the potential impact
142
+ # should be minimal. This would more appropriately belong to Extensions::SourceLocation,
143
+ # but as that is a runtime concern, and this happens at compile time, there isn't currently
144
+ # a clean way to turn this on and off. The absence of the extension will cause the
145
+ # source_file and source_line to be removed from the trace span before it is submitted.
146
+ source_file, source_line = klass.instance_method(name).source_location
147
147
 
148
- # We should strongly prefer using the new argument-forwarding syntax (...) where available.
149
- # In Ruby 2.7, the following are known to be syntax errors:
150
- #
151
- # - mixing positional arguments with argument forwarding (e.g., send(:method_name, ...))
152
- # - calling a setter method with multiple arguments, unless dispatched via send or public_send.
153
- #
154
- # So it is possible, though not recommended, to define setter methods that take multiple arguments,
155
- # keywords, and/or blocks. Unfortunately, this means that for setters, we still need to explicitly
156
- # forward the different argument types.
157
- is_setter_method = name.to_s.end_with?("=")
148
+ # We should strongly prefer using the new argument-forwarding syntax (...) where available.
149
+ # In Ruby 2.7, the following are known to be syntax errors:
150
+ #
151
+ # - mixing positional arguments with argument forwarding (e.g., send(:method_name, ...))
152
+ # - calling a setter method with multiple arguments, unless dispatched via send or public_send.
153
+ #
154
+ # So it is possible, though not recommended, to define setter methods that take multiple arguments,
155
+ # keywords, and/or blocks. Unfortunately, this means that for setters, we still need to explicitly
156
+ # forward the different argument types.
157
+ is_setter_method = name.to_s.end_with?("=")
158
158
 
159
- arg_string =
160
- if HAS_ARGUMENT_FORWARDING
161
- is_setter_method ? "*args, **kwargs, &blk" : "..."
162
- else
163
- "*args, &blk"
164
- end
159
+ arg_string =
160
+ if HAS_ARGUMENT_FORWARDING
161
+ is_setter_method ? "*args, **kwargs, &blk" : "..."
162
+ else
163
+ "*args, &blk"
164
+ end
165
165
 
166
- original_method_dispatch =
167
- if is_setter_method
168
- "self.send(:before_instrument_#{name}, #{arg_string})"
169
- else
170
- "before_instrument_#{name}(#{arg_string})"
171
- end
166
+ original_method_dispatch =
167
+ if is_setter_method
168
+ "self.send(:before_instrument_#{name}, #{arg_string})"
169
+ else
170
+ "before_instrument_#{name}(#{arg_string})"
171
+ end
172
172
 
173
- klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
173
+ klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
174
174
  alias_method :"before_instrument_#{name}", :"#{name}" # alias_method :"before_instrument_process", :"process"
175
175
  def #{name}(#{arg_string}) # def process(*args, **kwargs, &blk)
176
176
  span = Skylight.instrument( # span = Skylight.instrument(
@@ -198,15 +198,17 @@ module Skylight
198
198
  private :"#{name}" # private :"process"
199
199
  end # end
200
200
  RUBY
201
- end
201
+ end
202
202
 
203
- if respond_to?(:singleton_class)
204
- alias __sk_singleton_class singleton_class
205
- else
206
- def __sk_singleton_class
207
- class << self; self; end
203
+ if respond_to?(:singleton_class)
204
+ alias __sk_singleton_class singleton_class
205
+ else
206
+ def __sk_singleton_class
207
+ class << self
208
+ self
208
209
  end
209
210
  end
211
+ end
210
212
  end
211
213
 
212
214
  # @api private
@@ -99,16 +99,14 @@ module Skylight
99
99
  end
100
100
 
101
101
  def current_trace=(trace)
102
- t { "setting current_trace=#{trace ? trace.uuid : 'nil'}; thread=#{Thread.current.object_id}" }
102
+ t { "setting current_trace=#{trace ? trace.uuid : "nil"}; thread=#{Thread.current.object_id}" }
103
103
  @trace_info.current = trace
104
104
  end
105
105
 
106
106
  def validate_installation
107
107
  # Warn if there was an error installing Skylight.
108
108
 
109
- if defined?(Skylight.check_install_errors)
110
- Skylight.check_install_errors(config)
111
- end
109
+ Skylight.check_install_errors(config) if defined?(Skylight.check_install_errors)
112
110
 
113
111
  if !Skylight.native? && defined?(Skylight.warn_skylight_native_missing)
114
112
  Skylight.warn_skylight_native_missing(config)
@@ -143,9 +141,7 @@ module Skylight
143
141
  end
144
142
 
145
143
  def silence_warnings(context)
146
- @warnings_silenced || @mutex.synchronize do
147
- @warnings_silenced ||= {}
148
- end
144
+ @warnings_silenced || @mutex.synchronize { @warnings_silenced ||= {} }
149
145
 
150
146
  @warnings_silenced[context] = true
151
147
  end
@@ -203,8 +199,18 @@ module Skylight
203
199
  begin
204
200
  meta ||= {}
205
201
  extensions.process_trace_meta(meta)
206
- trace = Trace.new(self, endpoint, Skylight::Util::Clock.nanos, cat, title, desc,
207
- meta: meta, segment: segment, component: component)
202
+ trace =
203
+ Trace.new(
204
+ self,
205
+ endpoint,
206
+ Skylight::Util::Clock.nanos,
207
+ cat,
208
+ title,
209
+ desc,
210
+ meta: meta,
211
+ segment: segment,
212
+ component: component
213
+ )
208
214
  rescue Exception => e
209
215
  log_error e.message
210
216
  t { e.backtrace.join("\n") }
@@ -301,7 +307,7 @@ module Skylight
301
307
  finalize_endpoint_segment(trace)
302
308
  native_submit_trace(trace)
303
309
  true
304
- rescue => e
310
+ rescue StandardError => e
305
311
  handle_instrumenter_error(trace, e)
306
312
  end
307
313
  end
@@ -332,14 +338,15 @@ module Skylight
332
338
  def finalize_endpoint_segment(trace)
333
339
  return unless (segment = trace.segment)
334
340
 
335
- segment = case trace.compound_response_error_status
336
- when :all
337
- "error"
338
- when :partial
339
- "#{segment}+error"
340
- else
341
- segment
342
- end
341
+ segment =
342
+ case trace.compound_response_error_status
343
+ when :all
344
+ "error"
345
+ when :partial
346
+ "#{segment}+error"
347
+ else
348
+ segment
349
+ end
343
350
 
344
351
  trace.endpoint += "<sk-segment>#{segment}</sk-segment>"
345
352
  end
@@ -49,12 +49,16 @@ module Skylight
49
49
  def self.with_after_close(resp, debug_identifier: "unknown", &block)
50
50
  unless resp.respond_to?(:to_ary)
51
51
  if resp.respond_to?(:to_a)
52
- Skylight.warn("Rack response from \"#{debug_identifier}\" cannot be implicitly converted to an array. " \
53
- "This is in violation of the Rack SPEC and will raise an error in future versions.")
52
+ Skylight.warn(
53
+ "Rack response from \"#{debug_identifier}\" cannot be implicitly converted to an array. " \
54
+ "This is in violation of the Rack SPEC and will raise an error in future versions."
55
+ )
54
56
  resp = resp.to_a
55
57
  else
56
- Skylight.error("Rack response from \"#{debug_identifier}\" cannot be converted to an array. This is in " \
57
- "violation of the Rack SPEC and may cause problems with Skylight operation.")
58
+ Skylight.error(
59
+ "Rack response from \"#{debug_identifier}\" cannot be converted to an array. This is in " \
60
+ "violation of the Rack SPEC and may cause problems with Skylight operation."
61
+ )
58
62
  return resp
59
63
  end
60
64
  end
@@ -91,11 +95,7 @@ module Skylight
91
95
 
92
96
  resp = @app.call(env)
93
97
 
94
- if trace
95
- Middleware.with_after_close(resp, debug_identifier: "Rack App: #{@app.class}") { trace.submit }
96
- else
97
- resp
98
- end
98
+ trace ? Middleware.with_after_close(resp, debug_identifier: "Rack App: #{@app.class}") { trace.submit } : resp
99
99
  rescue Exception => e
100
100
  t { "middleware exception: #{e}\n#{e.backtrace.join("\n")}" }
101
101
  trace&.submit
@@ -106,36 +106,32 @@ module Skylight
106
106
 
107
107
  private
108
108
 
109
- def log_context
110
- # Don't cache this, it will change
111
- { request_id: @current_request_id, inst: Skylight.instrumenter&.uuid }
112
- end
109
+ def log_context
110
+ # Don't cache this, it will change
111
+ { request_id: @current_request_id, inst: Skylight.instrumenter&.uuid }
112
+ end
113
113
 
114
- # Allow for overwriting
115
- def endpoint_name(_env)
116
- "Rack"
117
- end
114
+ # Allow for overwriting
115
+ def endpoint_name(_env)
116
+ "Rack"
117
+ end
118
118
 
119
- def endpoint_meta(_env)
120
- { source_location: Trace::SYNTHETIC }
121
- end
119
+ def endpoint_meta(_env)
120
+ { source_location: Trace::SYNTHETIC }
121
+ end
122
122
 
123
- # Request ID code based on ActionDispatch::RequestId
124
- def set_request_id(env)
125
- existing_request_id = env["action_dispatch.request_id"] || env["HTTP_X_REQUEST_ID"]
126
- @current_request_id = env["skylight.request_id"] = make_request_id(existing_request_id)
127
- end
123
+ # Request ID code based on ActionDispatch::RequestId
124
+ def set_request_id(env)
125
+ existing_request_id = env["action_dispatch.request_id"] || env["HTTP_X_REQUEST_ID"]
126
+ @current_request_id = env["skylight.request_id"] = make_request_id(existing_request_id)
127
+ end
128
128
 
129
- def make_request_id(request_id)
130
- if request_id && !request_id.empty?
131
- request_id.gsub(/[^\w\-]/, "".freeze)[0...255]
132
- else
133
- internal_request_id
134
- end
135
- end
129
+ def make_request_id(request_id)
130
+ request_id && !request_id.empty? ? request_id.gsub(/[^\w\-]/, "".freeze)[0...255] : internal_request_id
131
+ end
136
132
 
137
- def internal_request_id
138
- SecureRandom.uuid
139
- end
133
+ def internal_request_id
134
+ SecureRandom.uuid
135
+ end
140
136
  end
141
137
  end
@@ -105,20 +105,18 @@ module Skylight
105
105
  install_log = File.expand_path("../../ext/install.log", __dir__)
106
106
 
107
107
  if File.exist?(install_log) && File.read(install_log) =~ /ERROR/
108
- config.alert_logger.error \
109
- "[SKYLIGHT] [#{Skylight::VERSION}] The Skylight native extension failed to install. " \
110
- "Please check #{install_log} and notify support@skylight.io. " \
111
- "The missing extension will not affect the functioning of your application."
108
+ config.alert_logger.error "[SKYLIGHT] [#{Skylight::VERSION}] The Skylight native extension failed to install. " \
109
+ "Please check #{install_log} and notify support@skylight.io. " \
110
+ "The missing extension will not affect the functioning of your application."
112
111
  end
113
112
  end
114
113
 
115
114
  # @api private
116
115
  def self.warn_skylight_native_missing(config)
117
- config.alert_logger.error \
118
- "[SKYLIGHT] [#{Skylight::VERSION}] The Skylight native extension for " \
119
- "your platform wasn't found. Supported operating systems are " \
120
- "Linux 2.6.18+ and Mac OS X 10.8+. The missing extension will not " \
121
- "affect the functioning of your application. If you are on a " \
122
- "supported platform, please contact support at support@skylight.io."
116
+ config.alert_logger.error "[SKYLIGHT] [#{Skylight::VERSION}] The Skylight native extension for " \
117
+ "your platform wasn't found. Supported operating systems are " \
118
+ "Linux 2.6.18+ and Mac OS X 10.8+. The missing extension will not " \
119
+ "affect the functioning of your application. If you are on a " \
120
+ "supported platform, please contact support at support@skylight.io."
123
121
  end
124
122
  end
@@ -17,7 +17,8 @@ module Skylight
17
17
 
18
18
  include FileUtils
19
19
 
20
- class FetchError < StandardError; end
20
+ class FetchError < StandardError
21
+ end
21
22
 
22
23
  # Creates a new fetcher and fetches
23
24
  # @param opts [Hash]
@@ -56,7 +57,7 @@ module Skylight
56
57
  # @return [String] the inflated archive
57
58
  def fetch
58
59
  log "fetching native ext; curr-platform=#{@platform}; " \
59
- "requested-arch=#{@arch}; version=#{@version}"
60
+ "requested-arch=#{@arch}; version=#{@version}"
60
61
 
61
62
  tar_gz = "#{@target}/#{basename}"
62
63
 
@@ -109,11 +110,12 @@ module Skylight
109
110
  next
110
111
  end
111
112
  end
112
- rescue => e
113
+ rescue StandardError => e
113
114
  remaining_attempts -= 1
114
115
 
115
116
  error "failed to fetch native extension; uri=#{uri}; msg=#{e.message}; " \
116
- "remaining-attempts=#{remaining_attempts}", e
117
+ "remaining-attempts=#{remaining_attempts}",
118
+ e
117
119
 
118
120
  if remaining_attempts > 0
119
121
  sleep 2
@@ -149,9 +151,7 @@ module Skylight
149
151
  opts = {}
150
152
  opts[:use_ssl] = use_ssl
151
153
 
152
- if use_ssl
153
- opts[:ca_file] = Util::SSL.ca_cert_file_or_default
154
- end
154
+ opts[:ca_file] = Util::SSL.ca_cert_file_or_default if use_ssl
155
155
 
156
156
  Net::HTTP.start(host, port, p_host, p_port, p_user, p_pass, use_ssl: use_ssl) do |http|
157
157
  http.request_get path do |resp|
@@ -164,13 +164,13 @@ module Skylight
164
164
  out.write chunk
165
165
  end
166
166
 
167
- return [:success, digest.hexdigest]
167
+ return :success, digest.hexdigest
168
168
  when Net::HTTPRedirection
169
169
  unless (location = resp["location"])
170
170
  raise "received redirect but no location"
171
171
  end
172
172
 
173
- return [:redirect, location]
173
+ return :redirect, location
174
174
  else
175
175
  raise "received HTTP status code #{resp.code}"
176
176
  end
@@ -221,9 +221,7 @@ module Skylight
221
221
  def maybe_raise(err)
222
222
  error err
223
223
 
224
- if @required
225
- raise err
226
- end
224
+ raise err if @required
227
225
  end
228
226
 
229
227
  # Log an `info` to the `logger`