skylight 5.1.0.beta → 5.1.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +390 -371
  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/lib/skylight.rb +20 -30
  8. data/lib/skylight/api.rb +22 -18
  9. data/lib/skylight/cli.rb +47 -46
  10. data/lib/skylight/cli/doctor.rb +50 -50
  11. data/lib/skylight/cli/helpers.rb +19 -19
  12. data/lib/skylight/cli/merger.rb +141 -139
  13. data/lib/skylight/config.rb +265 -302
  14. data/lib/skylight/deprecation.rb +4 -4
  15. data/lib/skylight/errors.rb +3 -4
  16. data/lib/skylight/extensions.rb +17 -29
  17. data/lib/skylight/extensions/source_location.rb +128 -128
  18. data/lib/skylight/formatters/http.rb +1 -3
  19. data/lib/skylight/gc.rb +30 -40
  20. data/lib/skylight/helpers.rb +43 -41
  21. data/lib/skylight/instrumenter.rb +25 -18
  22. data/lib/skylight/middleware.rb +31 -35
  23. data/lib/skylight/native.rb +8 -10
  24. data/lib/skylight/native_ext_fetcher.rb +10 -12
  25. data/lib/skylight/normalizers.rb +43 -39
  26. data/lib/skylight/normalizers/action_controller/process_action.rb +24 -25
  27. data/lib/skylight/normalizers/action_controller/send_file.rb +7 -6
  28. data/lib/skylight/normalizers/action_dispatch/route_set.rb +7 -7
  29. data/lib/skylight/normalizers/active_job/perform.rb +48 -44
  30. data/lib/skylight/normalizers/active_model_serializers/render.rb +7 -3
  31. data/lib/skylight/normalizers/active_storage.rb +11 -13
  32. data/lib/skylight/normalizers/active_support/cache.rb +1 -12
  33. data/lib/skylight/normalizers/coach/handler_finish.rb +1 -3
  34. data/lib/skylight/normalizers/default.rb +1 -9
  35. data/lib/skylight/normalizers/faraday/request.rb +1 -3
  36. data/lib/skylight/normalizers/grape/endpoint.rb +13 -19
  37. data/lib/skylight/normalizers/grape/endpoint_run.rb +16 -18
  38. data/lib/skylight/normalizers/grape/endpoint_run_filters.rb +1 -3
  39. data/lib/skylight/normalizers/graphql/base.rb +23 -28
  40. data/lib/skylight/normalizers/render.rb +19 -21
  41. data/lib/skylight/normalizers/shrine.rb +15 -17
  42. data/lib/skylight/normalizers/sql.rb +4 -4
  43. data/lib/skylight/probes.rb +38 -46
  44. data/lib/skylight/probes/action_controller.rb +32 -28
  45. data/lib/skylight/probes/action_dispatch/request_id.rb +9 -5
  46. data/lib/skylight/probes/action_dispatch/routing/route_set.rb +7 -5
  47. data/lib/skylight/probes/action_view.rb +9 -10
  48. data/lib/skylight/probes/active_job_enqueue.rb +3 -9
  49. data/lib/skylight/probes/active_model_serializers.rb +8 -8
  50. data/lib/skylight/probes/delayed_job.rb +37 -42
  51. data/lib/skylight/probes/elasticsearch.rb +3 -5
  52. data/lib/skylight/probes/excon.rb +1 -1
  53. data/lib/skylight/probes/excon/middleware.rb +22 -23
  54. data/lib/skylight/probes/graphql.rb +2 -7
  55. data/lib/skylight/probes/middleware.rb +14 -5
  56. data/lib/skylight/probes/mongo.rb +83 -91
  57. data/lib/skylight/probes/net_http.rb +1 -1
  58. data/lib/skylight/probes/redis.rb +5 -17
  59. data/lib/skylight/probes/sequel.rb +7 -11
  60. data/lib/skylight/probes/sinatra.rb +8 -5
  61. data/lib/skylight/probes/tilt.rb +2 -4
  62. data/lib/skylight/railtie.rb +121 -135
  63. data/lib/skylight/sidekiq.rb +4 -5
  64. data/lib/skylight/subscriber.rb +31 -33
  65. data/lib/skylight/test.rb +89 -84
  66. data/lib/skylight/trace.rb +121 -115
  67. data/lib/skylight/user_config.rb +14 -17
  68. data/lib/skylight/util/clock.rb +1 -0
  69. data/lib/skylight/util/component.rb +18 -21
  70. data/lib/skylight/util/deploy.rb +11 -13
  71. data/lib/skylight/util/http.rb +104 -105
  72. data/lib/skylight/util/logging.rb +4 -6
  73. data/lib/skylight/util/lru_cache.rb +2 -6
  74. data/lib/skylight/util/platform.rb +2 -6
  75. data/lib/skylight/util/ssl.rb +1 -3
  76. data/lib/skylight/version.rb +1 -1
  77. data/lib/skylight/vm/gc.rb +1 -9
  78. metadata +4 -4
@@ -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`