rails_semantic_logger 4.6.1 → 4.12.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '0816ddc6820dfc94fed6b737d023c2cfdc6e6df3019d34ff1e71c40a2a6ccb2f'
4
- data.tar.gz: b0c7f329c6e1ecf72687617155d994b6c37ef731d5166e30b76543a41e825efb
3
+ metadata.gz: 73a37ac27f2cf94d083cc75aa557a778f32e2de852b3be6447b072dc1da89047
4
+ data.tar.gz: 681f2145e71def6b336792fe3d581dfd89da6fd3ca471befcbd8ffa4f11abb50
5
5
  SHA512:
6
- metadata.gz: c42fadbc4b768c9f64f719e36cdf453bc80b88639fd8fe169704ae5b37375be8706b59d3ede6ef8a6eac090a0433be1fe514e90ea306f2f1288f026042e48b18
7
- data.tar.gz: f16dec6c5a4336c0d0a0a2862891ec2117cbf103257a759e8611376725167476bc090c2444a7011df7b4c4e323583f2d5392dd498dea72e03f23f3555c45bde8
6
+ metadata.gz: 8d299a14cb4c3eaf282e4bf502d8e60c2a36095b138c17969cf0a8f79b0431a731adbe8963ae2017bf429f12b7f42fe65d5c199a2c5f88e984a71d4605766bea
7
+ data.tar.gz: d837dc46c0dcd38b19dcf2a62c926c91ef1775542d55c8919d3a76db2e62764ab8675890238da78ab19b157f3b920e9d92257d5b2e347bb66d0c5a2bde60441f
data/README.md CHANGED
@@ -21,7 +21,7 @@ SemanticLogger::Processor.instance.instance_variable_set(:@queue, Queue.new)
21
21
 
22
22
  ## Supports
23
23
 
24
- For the complete list of supported Ruby and Rails versions, see the [Testing file](https://github.com/reidmorrison/rails_semantic_logger/blob/master/.travis.yml).
24
+ For the complete list of supported Ruby and Rails versions, see the [Testing file](https://github.com/reidmorrison/rails_semantic_logger/blob/master/.github/workflows/ci.yml).
25
25
 
26
26
  ## Author
27
27
 
@@ -14,12 +14,22 @@ module RailsSemanticLogger
14
14
 
15
15
  # Unused, but needed for Devise 401 status code monkey patch to still work.
16
16
  ::ActionController::Base.log_process_action(payload)
17
+
18
+ params = payload[:params]
17
19
 
18
- # According to PR https://github.com/reidmorrison/rails_semantic_logger/pull/37/files
19
- # payload[:params] is not always a Hash.
20
- payload[:params] = payload[:params].to_unsafe_h unless payload[:params].is_a?(Hash)
21
- payload[:params] = payload[:params].except(*INTERNAL_PARAMS)
22
- payload.delete(:params) if payload[:params].empty?
20
+ if params.kind_of?(Hash) || params.kind_of?(::ActionController::Parameters)
21
+ # According to PR https://github.com/reidmorrison/rails_semantic_logger/pull/37/files
22
+ # params is not always a Hash.
23
+ payload[:params] = params.to_unsafe_h unless params.is_a?(Hash)
24
+ payload[:params] = params.except(*INTERNAL_PARAMS)
25
+
26
+ if payload[:params].empty?
27
+ payload.delete(:params)
28
+ elsif params["file"]
29
+ # When logging to JSON the entire tempfile is logged, so convert it to a string.
30
+ payload[:params]["file"] = params["file"].inspect
31
+ end
32
+ end
23
33
 
24
34
  format = payload[:format]
25
35
  payload[:format] = format.to_s.upcase if format.is_a?(Symbol)
@@ -48,12 +58,6 @@ module RailsSemanticLogger
48
58
  payload.delete(:request)
49
59
  payload.delete(:response)
50
60
 
51
- params = payload[:params]
52
- if params
53
- # When logging to JSON the entire tempfile is logged, so convert it to a string.
54
- params["file"] = params["file"].inspect if params["file"]
55
- end
56
-
57
61
  {
58
62
  message: "Completed ##{payload[:action]}",
59
63
  duration: event.duration,
@@ -0,0 +1,135 @@
1
+ require "active_support/log_subscriber"
2
+ require "action_mailer"
3
+
4
+ module RailsSemanticLogger
5
+ module ActionMailer
6
+ class LogSubscriber < ::ActiveSupport::LogSubscriber
7
+ def deliver(event)
8
+ ex = event.payload[:exception_object]
9
+ message_id = event.payload[:message_id]
10
+ duration = event.duration.round(1)
11
+ if ex
12
+ log_with_formatter event: event, log_duration: true, level: :error do |fmt|
13
+ {
14
+ message: "Error delivering mail #{message_id} (#{duration}ms)",
15
+ exception: ex
16
+ }
17
+ end
18
+ else
19
+ message = begin
20
+ if event.payload[:perform_deliveries]
21
+ "Delivered mail #{message_id} (#{duration}ms)"
22
+ else
23
+ "Skipped delivery of mail #{message_id} as `perform_deliveries` is false"
24
+ end
25
+ end
26
+ log_with_formatter event: event, log_duration: true do |fmt|
27
+ { message: message }
28
+ end
29
+ end
30
+ end
31
+
32
+ # An email was generated.
33
+ def process(event)
34
+ mailer = event.payload[:mailer]
35
+ action = event.payload[:action]
36
+ duration = event.duration.round(1)
37
+ log_with_formatter event: event do |fmt|
38
+ { message: "#{mailer}##{action}: processed outbound mail in #{duration}ms" }
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ class EventFormatter
45
+ def initialize(event:, log_duration: false)
46
+ @event = event
47
+ @log_duration = log_duration
48
+ end
49
+
50
+ def mailer
51
+ event.payload[:mailer]
52
+ end
53
+
54
+ def payload
55
+ {}.tap do |h|
56
+ h[:event_name] = event.name
57
+ h[:mailer] = mailer
58
+ h[:action] = action
59
+ h[:message_id] = event.payload[:message_id]
60
+ h[:perform_deliveries] = event.payload[:perform_deliveries]
61
+ h[:subject] = event.payload[:subject]
62
+ h[:to] = event.payload[:to]
63
+ h[:from] = event.payload[:from]
64
+ h[:bcc] = event.payload[:bcc]
65
+ h[:cc] = event.payload[:cc]
66
+ h[:date] = date
67
+ h[:duration] = event.duration.round(2) if log_duration?
68
+ h[:args] = formatted_args
69
+ end
70
+ end
71
+
72
+ def date
73
+ if event.payload[:date].respond_to?(:to_time)
74
+ event.payload[:date].to_time.utc
75
+ elsif event.payload[:date].is_a?(String)
76
+ Time.parse(date).utc
77
+ else
78
+ nil
79
+ end
80
+ end
81
+
82
+ private
83
+
84
+ attr_reader :event
85
+
86
+ def mailer
87
+ event.payload[:mailer]
88
+ end
89
+
90
+ def action
91
+ event.payload[:action]
92
+ end
93
+
94
+ def formatted_args
95
+ if defined?(mailer.contantize.log_arguments?) && !mailer.contantize.log_arguments?
96
+ ""
97
+ else
98
+ JSON.pretty_generate(event.payload[:args].map { |arg| format(arg) }) if event.payload[:args].present?
99
+ end
100
+ end
101
+
102
+ def format(arg)
103
+ case arg
104
+ when Hash
105
+ arg.transform_values { |value| format(value) }
106
+ when Array
107
+ arg.map { |value| format(value) }
108
+ when GlobalID::Identification
109
+ begin
110
+ arg.to_global_id
111
+ rescue StandardError
112
+ arg
113
+ end
114
+ else
115
+ arg
116
+ end
117
+ end
118
+
119
+ def log_duration?
120
+ @log_duration
121
+ end
122
+ end
123
+
124
+ def log_with_formatter(level: :info, **kw_args)
125
+ fmt = EventFormatter.new(**kw_args)
126
+ msg = yield fmt
127
+ logger.public_send(level, **msg, payload: fmt.payload)
128
+ end
129
+
130
+ def logger
131
+ ::ActionMailer::Base.logger
132
+ end
133
+ end
134
+ end
135
+ end
@@ -198,7 +198,8 @@ module RailsSemanticLogger
198
198
  alias bind_values bind_values_v5_0_3
199
199
  alias render_bind render_bind_v5_0_3
200
200
  alias type_casted_binds type_casted_binds_v5_0_3
201
- elsif Rails::VERSION::MAJOR == 6 && Rails::VERSION::MINOR > 0 # ~> 6.1.0
201
+ elsif (Rails::VERSION::MAJOR == 6 && Rails::VERSION::MINOR > 0) || # ~> 6.1.0
202
+ Rails::VERSION::MAJOR == 7
202
203
  alias bind_values bind_values_v6_1
203
204
  alias render_bind render_bind_v6_1
204
205
  alias type_casted_binds type_casted_binds_v5_1_5
@@ -1,6 +1,4 @@
1
1
  require "rails"
2
- require "action_controller/log_subscriber"
3
- require "action_view/log_subscriber"
4
2
  require "rails_semantic_logger/options"
5
3
 
6
4
  module RailsSemanticLogger
@@ -55,16 +53,16 @@ module RailsSemanticLogger
55
53
  formatter = {color: {ap: ap_options}} if (formatter == :default) && (config.colorize_logging != false)
56
54
 
57
55
  # Set internal logger to log to file only, in case another appender experiences errors during writes
58
- appender = SemanticLogger::Appender::File.new(
59
- file_name: path,
60
- level: config.log_level,
61
- formatter: formatter
62
- )
56
+ appender = SemanticLogger::Appender::File.new(path, formatter: formatter)
63
57
  appender.name = "SemanticLogger"
64
58
  SemanticLogger::Processor.logger = appender
65
59
 
66
60
  # Check for previous file or stdout loggers
67
- SemanticLogger.appenders.each { |app| app.formatter = formatter if app.is_a?(SemanticLogger::Appender::File) }
61
+ SemanticLogger.appenders.each do |app|
62
+ next unless app.is_a?(SemanticLogger::Appender::File) || app.is_a?(SemanticLogger::Appender::IO)
63
+
64
+ app.formatter = formatter
65
+ end
68
66
  SemanticLogger.add_appender(file_name: path, formatter: formatter, filter: config.rails_semantic_logger.filter)
69
67
  end
70
68
 
@@ -73,8 +71,8 @@ module RailsSemanticLogger
73
71
  # If not able to log to file, log to standard error with warning level only
74
72
  SemanticLogger.default_level = :warn
75
73
 
76
- SemanticLogger::Processor.logger = SemanticLogger::Appender::File.new(io: STDERR)
77
- SemanticLogger.add_appender(io: STDERR)
74
+ SemanticLogger::Processor.logger = SemanticLogger::Appender::IO.new($stderr)
75
+ SemanticLogger.add_appender(io: $stderr)
78
76
 
79
77
  logger = SemanticLogger[Rails]
80
78
  logger.warn(
@@ -107,13 +105,20 @@ module RailsSemanticLogger
107
105
  Mongo::Logger.logger = SemanticLogger[Mongo] if defined?(Mongo::Logger)
108
106
 
109
107
  # Replace the Resque Logger
110
- Resque.logger = SemanticLogger[Resque] if defined?(Resque) && Resque.respond_to?(:logger)
108
+ Resque.logger = SemanticLogger[Resque] if defined?(Resque) && Resque.respond_to?(:logger=)
111
109
 
112
110
  # Replace the Sidekiq logger
113
- Sidekiq.logger = SemanticLogger[Sidekiq] if defined?(Sidekiq)
111
+ if defined?(Sidekiq)
112
+ if Sidekiq.respond_to?(:logger=)
113
+ Sidekiq.logger = SemanticLogger[Sidekiq]
114
+ elsif Sidekiq::VERSION[0..1] == '7.'
115
+ method = Sidekiq.server? ? :configure_server : :configure_client
116
+ Sidekiq.public_send(method) { |cfg| cfg.logger = SemanticLogger[Sidekiq] }
117
+ end
118
+ end
114
119
 
115
120
  # Replace the Sidetiq logger
116
- Sidetiq.logger = SemanticLogger[Sidetiq] if defined?(Sidetiq)
121
+ Sidetiq.logger = SemanticLogger[Sidetiq] if defined?(Sidetiq) && Sidetiq.respond_to?(:logger=)
117
122
 
118
123
  # Replace the DelayedJob logger
119
124
  if defined?(Delayed::Worker)
@@ -123,6 +128,9 @@ module RailsSemanticLogger
123
128
 
124
129
  # Replace the Bugsnag logger
125
130
  Bugsnag.configure { |config| config.logger = SemanticLogger[Bugsnag] } if defined?(Bugsnag)
131
+
132
+ # Set the IOStreams PGP logger
133
+ IOStreams::Pgp.logger = SemanticLogger["IOStreams::Pgp"] if defined?(IOStreams)
126
134
  end
127
135
 
128
136
  # After any initializers run, but after the gems have been loaded
@@ -182,19 +190,38 @@ module RailsSemanticLogger
182
190
  end
183
191
 
184
192
  # Action View
185
- RailsSemanticLogger::ActionView::LogSubscriber.rendered_log_level = :info if config.rails_semantic_logger.rendered
186
- RailsSemanticLogger.swap_subscriber(
187
- ::ActionView::LogSubscriber,
188
- RailsSemanticLogger::ActionView::LogSubscriber,
189
- :action_view
190
- )
193
+ if defined?(::ActionView)
194
+ require "action_view/log_subscriber"
195
+
196
+ RailsSemanticLogger::ActionView::LogSubscriber.rendered_log_level = :info if config.rails_semantic_logger.rendered
197
+ RailsSemanticLogger.swap_subscriber(
198
+ ::ActionView::LogSubscriber,
199
+ RailsSemanticLogger::ActionView::LogSubscriber,
200
+ :action_view
201
+ )
202
+ end
191
203
 
192
204
  # Action Controller
193
- RailsSemanticLogger.swap_subscriber(
194
- ::ActionController::LogSubscriber,
195
- RailsSemanticLogger::ActionController::LogSubscriber,
196
- :action_controller
197
- )
205
+ if defined?(::ActionController)
206
+ require "action_controller/log_subscriber"
207
+
208
+ RailsSemanticLogger.swap_subscriber(
209
+ ::ActionController::LogSubscriber,
210
+ RailsSemanticLogger::ActionController::LogSubscriber,
211
+ :action_controller
212
+ )
213
+ end
214
+
215
+ # Action Mailer
216
+ if defined?(::ActionMailer)
217
+ require "action_mailer/log_subscriber"
218
+
219
+ RailsSemanticLogger.swap_subscriber(
220
+ ::ActionMailer::LogSubscriber,
221
+ RailsSemanticLogger::ActionMailer::LogSubscriber,
222
+ :action_mailer
223
+ )
224
+ end
198
225
  end
199
226
 
200
227
  #
@@ -218,7 +245,10 @@ module RailsSemanticLogger
218
245
  console do |_app|
219
246
  # Don't use a background thread for logging
220
247
  SemanticLogger.sync!
221
- SemanticLogger.add_appender(io: STDERR, formatter: :color)
248
+ # Add a stderr logger when running inside a Rails console unless one has already been added.
249
+ if config.rails_semantic_logger.console_logger && !SemanticLogger.appenders.console_output?
250
+ SemanticLogger.add_appender(io: STDERR, formatter: :color)
251
+ end
222
252
 
223
253
  # Include method names on log entries in the console
224
254
  SemanticLogger.backtrace_level = SemanticLogger.default_level
@@ -1,4 +1,4 @@
1
- ActionCable::Connection::TaggedLoggerProxy
1
+ require "action_cable/connection/tagged_logger_proxy"
2
2
 
3
3
  module ActionCable
4
4
  module Connection
@@ -1,5 +1,6 @@
1
1
  # Log actual exceptions, not a string representation
2
- ActionController::Live
2
+ require "action_controller"
3
+
3
4
  module ActionController
4
5
  module Live
5
6
  undef_method :log_error
@@ -1,5 +1,6 @@
1
1
  # Log actual exceptions, not a string representation
2
- ActionDispatch::DebugExceptions
2
+ require "action_dispatch"
3
+
3
4
  module ActionDispatch
4
5
  class DebugExceptions
5
6
  private
@@ -1,5 +1,5 @@
1
1
  # Log actual exceptions, not a string representation
2
- ActionView::StreamingTemplateRenderer
2
+ require "action_view/renderer/streaming_template_renderer"
3
3
 
4
4
  module ActionView
5
5
  class StreamingTemplateRenderer
@@ -7,6 +7,7 @@ module ActiveJob
7
7
 
8
8
  private
9
9
 
10
+ undef_method :tag_logger
10
11
  def tag_logger(*tags, &block)
11
12
  logger.tagged(*tags, &block)
12
13
  end
@@ -1,13 +1,15 @@
1
1
  # Patch the Rails::Server log_to_stdout so that it logs via SemanticLogger
2
- Rails::Server
2
+ require "rails"
3
+
3
4
  module Rails
4
5
  class Server
5
6
  private
6
-
7
+
8
+ undef_method :log_to_stdout if method_defined?(:log_to_stdout)
7
9
  def log_to_stdout
8
10
  wrapped_app # touch the app so the logger is set up
9
11
 
10
- SemanticLogger.add_appender(io: $stdout, formatter: :color)
12
+ SemanticLogger.add_appender(io: $stdout, formatter: :color) unless SemanticLogger.appenders.console_output?
11
13
  end
12
14
  end
13
15
  end
@@ -40,7 +40,7 @@ module RailsSemanticLogger
40
40
  # When Semantic Logger fails to log to an appender it logs the error to an
41
41
  # internal logger, which by default writes to STDERR.
42
42
  # Example, change the default internal logger to log to stdout:
43
- # SemanticLogger::Processor.logger = SemanticLogger::Appender::File.new(io: STDOUT, level: :warn)
43
+ # SemanticLogger::Processor.logger = SemanticLogger::Appender::IO.new($stdout, level: :warn)
44
44
  #
45
45
  # config.rails_semantic_logger.add_file_appender = true
46
46
  #
@@ -48,6 +48,10 @@ module RailsSemanticLogger
48
48
  #
49
49
  # config.rails_semantic_logger.quiet_assets = false
50
50
  #
51
+ # * Disable automatic logging to stderr when running a Rails console.
52
+ #
53
+ # config.rails_semantic_logger.console_logger = false
54
+ #
51
55
  # * Override the output format for the primary Rails log file.
52
56
  #
53
57
  # Valid options:
@@ -98,7 +102,7 @@ module RailsSemanticLogger
98
102
  # config.rails_semantic_logger.named_tags = nil
99
103
  class Options
100
104
  attr_accessor :semantic, :started, :processing, :rendered, :ap_options, :add_file_appender,
101
- :quiet_assets, :format, :named_tags, :filter
105
+ :quiet_assets, :format, :named_tags, :filter, :console_logger
102
106
 
103
107
  # Setup default values
104
108
  def initialize
@@ -112,6 +116,7 @@ module RailsSemanticLogger
112
116
  @format = :default
113
117
  @named_tags = nil
114
118
  @filter = nil
119
+ @console_logger = true
115
120
  end
116
121
  end
117
122
  end
@@ -35,16 +35,18 @@ module RailsSemanticLogger
35
35
  @started_request_log_level = :debug
36
36
 
37
37
  def call_app(request, env)
38
- instrumenter = ActiveSupport::Notifications.instrumenter
39
- instrumenter.start "request.action_dispatch", request: request
38
+ instrumenter = ActiveSupport::Notifications.instrumenter
39
+ instrumenter_state = instrumenter.start "request.action_dispatch", request: request
40
+ instrumenter_finish = -> () {
41
+ instrumenter.finish_with_state(instrumenter_state, "request.action_dispatch", request: request)
42
+ }
40
43
 
41
44
  logger.send(self.class.started_request_log_level) { started_request_message(request) }
42
-
43
45
  status, headers, body = @app.call(env)
44
- body = ::Rack::BodyProxy.new(body) { finish(request) }
46
+ body = ::Rack::BodyProxy.new(body, &instrumenter_finish)
45
47
  [status, headers, body]
46
48
  rescue Exception
47
- finish(request)
49
+ instrumenter_finish.call
48
50
  raise
49
51
  end
50
52
 
@@ -90,11 +92,6 @@ module RailsSemanticLogger
90
92
  tagged
91
93
  end
92
94
 
93
- def finish(request)
94
- instrumenter = ActiveSupport::Notifications.instrumenter
95
- instrumenter.finish "request.action_dispatch", request: request
96
- end
97
-
98
95
  def logger
99
96
  self.class.logger
100
97
  end
@@ -1,3 +1,3 @@
1
1
  module RailsSemanticLogger
2
- VERSION = "4.6.1".freeze
2
+ VERSION = "4.12.0".freeze
3
3
  end
@@ -6,6 +6,9 @@ module RailsSemanticLogger
6
6
  module ActionController
7
7
  autoload :LogSubscriber, "rails_semantic_logger/action_controller/log_subscriber"
8
8
  end
9
+ module ActionMailer
10
+ autoload :LogSubscriber, "rails_semantic_logger/action_mailer/log_subscriber"
11
+ end
9
12
  module ActionView
10
13
  autoload :LogSubscriber, "rails_semantic_logger/action_view/log_subscriber"
11
14
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_semantic_logger
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.6.1
4
+ version: 4.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Reid Morrison
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-08-15 00:00:00.000000000 Z
11
+ date: 2023-03-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -30,28 +30,28 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '3.2'
33
+ version: '5.1'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '3.2'
40
+ version: '5.1'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: semantic_logger
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '4.8'
47
+ version: '4.13'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '4.8'
54
+ version: '4.13'
55
55
  description:
56
56
  email:
57
57
  executables: []
@@ -63,6 +63,7 @@ files:
63
63
  - Rakefile
64
64
  - lib/rails_semantic_logger.rb
65
65
  - lib/rails_semantic_logger/action_controller/log_subscriber.rb
66
+ - lib/rails_semantic_logger/action_mailer/log_subscriber.rb
66
67
  - lib/rails_semantic_logger/action_view/log_subscriber.rb
67
68
  - lib/rails_semantic_logger/active_job/log_subscriber.rb
68
69
  - lib/rails_semantic_logger/active_record/log_subscriber.rb
@@ -85,7 +86,11 @@ files:
85
86
  homepage: https://logger.rocketjob.io
86
87
  licenses:
87
88
  - Apache-2.0
88
- metadata: {}
89
+ metadata:
90
+ bug_tracker_uri: https://github.com/reidmorrison/rails_semantic_logger/issues
91
+ documentation_uri: https://logger.rocketjob.io
92
+ source_code_uri: https://github.com/reidmorrison/rails_semantic_logger/tree/4.12.0
93
+ rubygems_mfa_required: 'true'
89
94
  post_install_message:
90
95
  rdoc_options: []
91
96
  require_paths:
@@ -101,7 +106,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
101
106
  - !ruby/object:Gem::Version
102
107
  version: '0'
103
108
  requirements: []
104
- rubygems_version: 3.2.22
109
+ rubygems_version: 3.4.9
105
110
  signing_key:
106
111
  specification_version: 4
107
112
  summary: Feature rich logging framework that replaces the Rails logger.