rails_semantic_logger 4.4.3 → 4.6.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9a4446d1749a02b6f7d9993ebbc0f373c3fc30465d3f2d11e3c464a6c05d85a6
4
- data.tar.gz: ac53f67a871e98966da541e25402c7a482c06bce99986a194b7387e581003c1a
3
+ metadata.gz: '0816ddc6820dfc94fed6b737d023c2cfdc6e6df3019d34ff1e71c40a2a6ccb2f'
4
+ data.tar.gz: b0c7f329c6e1ecf72687617155d994b6c37ef731d5166e30b76543a41e825efb
5
5
  SHA512:
6
- metadata.gz: 3bebc589086757daa96f44d2e893559a74289a42c63bd41c9edee45f2dfd9dbb2e907815107d2dff71679a064d3c38810d48acc2c3bf1725db7c4cb5e5cea45b
7
- data.tar.gz: 86005d165532656bae94e209cd8c67034440bd2a7d5a569030264d3fbb246b116dd45085edaeb8674a08732b9882752243084ccd54aa803d8e97211f89128417
6
+ metadata.gz: c42fadbc4b768c9f64f719e36cdf453bc80b88639fd8fe169704ae5b37375be8706b59d3ede6ef8a6eac090a0433be1fe514e90ea306f2f1288f026042e48b18
7
+ data.tar.gz: f16dec6c5a4336c0d0a0a2862891ec2117cbf103257a759e8611376725167476bc090c2444a7011df7b4c4e323583f2d5392dd498dea72e03f23f3555c45bde8
data/README.md CHANGED
@@ -1,13 +1,13 @@
1
1
  # Rails Semantic Logger
2
- [![Gem Version](https://img.shields.io/gem/v/rails_semantic_logger.svg)](https://rubygems.org/gems/rails_semantic_logger) [![Build Status](https://travis-ci.org/rocketjob/rails_semantic_logger.svg?branch=master)](https://travis-ci.org/rocketjob/rails_semantic_logger) [![Downloads](https://img.shields.io/gem/dt/rails_semantic_logger.svg)](https://rubygems.org/gems/rails_semantic_logger) [![License](https://img.shields.io/badge/license-Apache%202.0-brightgreen.svg)](http://opensource.org/licenses/Apache-2.0) ![](https://img.shields.io/badge/status-Production%20Ready-blue.svg) [![Gitter chat](https://img.shields.io/badge/IRC%20(gitter)-Support-brightgreen.svg)](https://gitter.im/rocketjob/support)
2
+ [![Gem Version](https://img.shields.io/gem/v/rails_semantic_logger.svg)](https://rubygems.org/gems/rails_semantic_logger) [![Build Status](https://github.com/reidmorrison/rails_semantic_logger/workflows/build/badge.svg)](https://github.com/reidmorrison/rails_semantic_logger/actions?query=workflow%3Abuild) [![Downloads](https://img.shields.io/gem/dt/rails_semantic_logger.svg)](https://rubygems.org/gems/rails_semantic_logger) [![License](https://img.shields.io/badge/license-Apache%202.0-brightgreen.svg)](http://opensource.org/licenses/Apache-2.0) ![](https://img.shields.io/badge/status-Production%20Ready-blue.svg)
3
3
 
4
- Rails Semantic Logger replaces the Rails default logger with [Semantic Logger](http://github.com/rocketjob/semantic_logger)
4
+ Rails Semantic Logger replaces the Rails default logger with [Semantic Logger](https://logger.rocketjob.io/)
5
5
 
6
- * http://github.com/rocketjob/rails_semantic_logger
6
+ * http://github.com/reidmorrison/rails_semantic_logger
7
7
 
8
8
  ## Documentation
9
9
 
10
- For complete documentation see: http://rocketjob.github.io/semantic_logger/rails
10
+ For complete documentation see: https://logger.rocketjob.io/rails
11
11
 
12
12
  ## Upgrading to Semantic Logger v4.4
13
13
 
@@ -21,13 +21,13 @@ SemanticLogger::Processor.instance.instance_variable_set(:@queue, Queue.new)
21
21
 
22
22
  ## Supports
23
23
 
24
- - Rails 3.2, 4, 5
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).
25
25
 
26
26
  ## Author
27
27
 
28
28
  [Reid Morrison](https://github.com/reidmorrison)
29
29
 
30
- [Contributors](https://github.com/rocketjob/rails_semantic_logger/graphs/contributors)
30
+ [Contributors](https://github.com/reidmorrison/rails_semantic_logger/graphs/contributors)
31
31
 
32
32
  ## Versioning
33
33
 
data/Rakefile CHANGED
@@ -1,30 +1,30 @@
1
1
  # Setup bundler to avoid having to run bundle exec all the time.
2
- require 'rubygems'
3
- require 'bundler/setup'
2
+ require "rubygems"
3
+ require "bundler/setup"
4
4
 
5
- require 'rake/testtask'
6
- require_relative 'lib/rails_semantic_logger/version'
5
+ require "rake/testtask"
6
+ require_relative "lib/rails_semantic_logger/version"
7
7
 
8
8
  task :gem do
9
- system 'gem build rails_semantic_logger.gemspec'
9
+ system "gem build rails_semantic_logger.gemspec"
10
10
  end
11
11
 
12
12
  task publish: :gem do
13
13
  system "git tag -a v#{RailsSemanticLogger::VERSION} -m 'Tagging #{RailsSemanticLogger::VERSION}'"
14
- system 'git push --tags'
14
+ system "git push --tags"
15
15
  system "gem push rails_semantic_logger-#{RailsSemanticLogger::VERSION}.gem"
16
16
  system "rm rails_semantic_logger-#{RailsSemanticLogger::VERSION}.gem"
17
17
  end
18
18
 
19
19
  Rake::TestTask.new(:test) do |t|
20
- t.pattern = 'test/**/*_test.rb'
20
+ t.pattern = "test/**/*_test.rb"
21
21
  t.verbose = true
22
22
  t.warning = false
23
23
  end
24
24
 
25
25
  # By default run tests against all appraisals
26
- if !ENV['APPRAISAL_INITIALIZED'] && !ENV['TRAVIS']
27
- require 'appraisal'
26
+ if !ENV["APPRAISAL_INITIALIZED"] && !ENV["TRAVIS"]
27
+ require "appraisal"
28
28
  task default: :appraisal
29
29
  else
30
30
  task default: :test
@@ -15,10 +15,10 @@ module RailsSemanticLogger
15
15
  # Unused, but needed for Devise 401 status code monkey patch to still work.
16
16
  ::ActionController::Base.log_process_action(payload)
17
17
 
18
- # According to PR https://github.com/rocketjob/rails_semantic_logger/pull/37/files
18
+ # According to PR https://github.com/reidmorrison/rails_semantic_logger/pull/37/files
19
19
  # payload[:params] is not always a Hash.
20
20
  payload[:params] = payload[:params].to_unsafe_h unless payload[:params].is_a?(Hash)
21
- payload[:params].except!(*INTERNAL_PARAMS)
21
+ payload[:params] = payload[:params].except(*INTERNAL_PARAMS)
22
22
  payload.delete(:params) if payload[:params].empty?
23
23
 
24
24
  format = payload[:format]
@@ -37,14 +37,21 @@ module RailsSemanticLogger
37
37
  payload[key] = payload[key].to_f.round(2) if key.to_s =~ /(.*)_runtime/
38
38
  end
39
39
 
40
+ # Rails 6+ includes allocation count
41
+ payload[:allocations] = event.allocations if event.respond_to?(:allocations)
42
+
40
43
  payload[:status_message] = ::Rack::Utils::HTTP_STATUS_CODES[payload[:status]] if payload[:status].present?
44
+
41
45
  # Causes excessive log output with Rails 5 RC1
42
46
  payload.delete(:headers)
47
+ # Causes recursion in Rails 6.1.rc1
48
+ payload.delete(:request)
49
+ payload.delete(:response)
43
50
 
44
51
  params = payload[:params]
45
52
  if params
46
53
  # When logging to JSON the entire tempfile is logged, so convert it to a string.
47
- params['file'] = params['file'].inspect if params['file']
54
+ params["file"] = params["file"].inspect if params["file"]
48
55
  end
49
56
 
50
57
  {
@@ -60,15 +67,15 @@ module RailsSemanticLogger
60
67
  end
61
68
 
62
69
  def send_file(event)
63
- controller_logger(event).info(message: 'Sent file', payload: {path: event.payload[:path]}, duration: event.duration)
70
+ controller_logger(event).info(message: "Sent file", payload: {path: event.payload[:path]}, duration: event.duration)
64
71
  end
65
72
 
66
73
  def redirect_to(event)
67
- controller_logger(event).info(message: 'Redirected to', payload: {location: event.payload[:location]})
74
+ controller_logger(event).info(message: "Redirected to", payload: {location: event.payload[:location]})
68
75
  end
69
76
 
70
77
  def send_data(event)
71
- controller_logger(event).info(message: 'Sent data', payload: {file_name: event.payload[:filename]}, duration: event.duration)
78
+ controller_logger(event).info(message: "Sent data", payload: {file_name: event.payload[:filename]}, duration: event.duration)
72
79
  end
73
80
 
74
81
  def unpermitted_parameters(event)
@@ -106,7 +113,7 @@ module RailsSemanticLogger
106
113
  end
107
114
 
108
115
  def extract_path(path)
109
- index = path.index('?')
116
+ index = path.index("?")
110
117
  index ? path[0, index] : path
111
118
  end
112
119
  end
@@ -1,10 +1,10 @@
1
- require 'active_support/log_subscriber'
1
+ require "active_support/log_subscriber"
2
2
 
3
3
  module RailsSemanticLogger
4
4
  module ActionView
5
5
  # Output Semantic logs from Action View.
6
6
  class LogSubscriber < ActiveSupport::LogSubscriber
7
- VIEWS_PATTERN = /^app\/views\//
7
+ VIEWS_PATTERN = %r{^app/views/}.freeze
8
8
 
9
9
  class << self
10
10
  attr_reader :logger
@@ -19,14 +19,15 @@ module RailsSemanticLogger
19
19
  def render_template(event)
20
20
  return unless should_log?
21
21
 
22
- payload = {
22
+ payload = {
23
23
  template: from_rails_root(event.payload[:identifier])
24
24
  }
25
25
  payload[:within] = from_rails_root(event.payload[:layout]) if event.payload[:layout]
26
+ payload[:allocations] = event.allocations if event.respond_to?(:allocations)
26
27
 
27
28
  logger.measure(
28
29
  self.class.rendered_log_level,
29
- 'Rendered',
30
+ "Rendered",
30
31
  payload: payload,
31
32
  duration: event.duration
32
33
  )
@@ -35,15 +36,16 @@ module RailsSemanticLogger
35
36
  def render_partial(event)
36
37
  return unless should_log?
37
38
 
38
- payload = {
39
+ payload = {
39
40
  partial: from_rails_root(event.payload[:identifier])
40
41
  }
41
42
  payload[:within] = from_rails_root(event.payload[:layout]) if event.payload[:layout]
42
- payload[:cache] = payload[:cache_hit] unless event.payload[:cache_hit].nil?
43
+ payload[:cache] = event.payload[:cache_hit] unless event.payload[:cache_hit].nil?
44
+ payload[:allocations] = event.allocations if event.respond_to?(:allocations)
43
45
 
44
46
  logger.measure(
45
47
  self.class.rendered_log_level,
46
- 'Rendered',
48
+ "Rendered",
47
49
  payload: payload,
48
50
  duration: event.duration
49
51
  )
@@ -52,28 +54,29 @@ module RailsSemanticLogger
52
54
  def render_collection(event)
53
55
  return unless should_log?
54
56
 
55
- identifier = event.payload[:identifier] || 'templates'
57
+ identifier = event.payload[:identifier] || "templates"
56
58
 
57
- payload = {
59
+ payload = {
58
60
  template: from_rails_root(identifier),
59
61
  count: event.payload[:count]
60
62
  }
61
- payload[:cache_hits] = payload[:cache_hits] if payload[:cache_hits]
63
+ payload[:cache_hits] = event.payload[:cache_hits] if event.payload[:cache_hits]
64
+ payload[:allocations] = event.allocations if event.respond_to?(:allocations)
62
65
 
63
66
  logger.measure(
64
67
  self.class.rendered_log_level,
65
- 'Rendered',
68
+ "Rendered",
66
69
  payload: payload,
67
70
  duration: event.duration
68
71
  )
69
72
  end
70
73
 
71
74
  def start(name, id, payload)
72
- if (name == 'render_template.action_view') && should_log?
75
+ if (name == "render_template.action_view") && should_log?
73
76
  payload = {template: from_rails_root(payload[:identifier])}
74
77
  payload[:within] = from_rails_root(payload[:layout]) if payload[:layout]
75
78
 
76
- logger.send(self.class.rendered_log_level, message: 'Rendering', payload: payload)
79
+ logger.send(self.class.rendered_log_level, message: "Rendering", payload: payload)
77
80
  end
78
81
 
79
82
  super
@@ -81,10 +84,10 @@ module RailsSemanticLogger
81
84
 
82
85
  private
83
86
 
84
- @logger = SemanticLogger['ActionView']
87
+ @logger = SemanticLogger["ActionView"]
85
88
  @rendered_log_level = :debug
86
89
 
87
- EMPTY = ''.freeze
90
+ EMPTY = "".freeze
88
91
 
89
92
  def should_log?
90
93
  logger.send("#{self.class.rendered_log_level}?")
@@ -0,0 +1,126 @@
1
+ require "active_job"
2
+
3
+ module RailsSemanticLogger
4
+ module ActiveJob
5
+ class LogSubscriber < ::ActiveSupport::LogSubscriber
6
+ def enqueue(event)
7
+ log_with_formatter event: event do |fmt|
8
+ {message: "Enqueued #{fmt.job_info}"}
9
+ end
10
+ end
11
+
12
+ def enqueue_at(event)
13
+ log_with_formatter event: event do |fmt|
14
+ {message: "Enqueued #{fmt.job_info} at #{fmt.scheduled_at}"}
15
+ end
16
+ end
17
+
18
+ def perform_start(event)
19
+ log_with_formatter event: event do |fmt|
20
+ {message: "Performing #{fmt.job_info}"}
21
+ end
22
+ end
23
+
24
+ def perform(event)
25
+ ex = event.payload[:exception_object]
26
+ if ex
27
+ log_with_formatter event: event, log_duration: true, level: :error do |fmt|
28
+ {
29
+ message: "Error performing #{fmt.job_info} in #{event.duration.round(2)}ms",
30
+ exception: ex
31
+ }
32
+ end
33
+ else
34
+ log_with_formatter event: event, log_duration: true do |fmt|
35
+ {message: "Performed #{fmt.job_info} in #{event.duration.round(2)}ms"}
36
+ end
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ class EventFormatter
43
+ def initialize(event:, log_duration: false)
44
+ @event = event
45
+ @log_duration = log_duration
46
+ end
47
+
48
+ def job_info
49
+ "#{job.class.name} (Job ID: #{job.job_id}) to #{queue_name}"
50
+ end
51
+
52
+ def payload
53
+ {}.tap do |h|
54
+ h[:event_name] = event.name
55
+ h[:adapter] = adapter_name
56
+ h[:queue] = job.queue_name
57
+ h[:job_class] = job.class.name
58
+ h[:job_id] = job.job_id
59
+ h[:provider_job_id] = job.try(:provider_job_id) # Not available in Rails 4.2
60
+ h[:duration] = event.duration.round(2) if log_duration?
61
+ h[:arguments] = formatted_args
62
+ end
63
+ end
64
+
65
+ def queue_name
66
+ adapter_name + "(#{job.queue_name})"
67
+ end
68
+
69
+ def scheduled_at
70
+ Time.at(event.payload[:job].scheduled_at).utc
71
+ end
72
+
73
+ private
74
+
75
+ attr_reader :event
76
+
77
+ def job
78
+ event.payload[:job]
79
+ end
80
+
81
+ def adapter_name
82
+ event.payload[:adapter].class.name.demodulize.remove("Adapter")
83
+ end
84
+
85
+ def formatted_args
86
+ if defined?(job.class.log_arguments?) && !job.class.log_arguments?
87
+ ""
88
+ else
89
+ JSON.pretty_generate(job.arguments.map { |arg| format(arg) })
90
+ end
91
+ end
92
+
93
+ def format(arg)
94
+ case arg
95
+ when Hash
96
+ arg.transform_values { |value| format(value) }
97
+ when Array
98
+ arg.map { |value| format(value) }
99
+ when GlobalID::Identification
100
+ begin
101
+ arg.to_global_id
102
+ rescue StandardError
103
+ arg
104
+ end
105
+ else
106
+ arg
107
+ end
108
+ end
109
+
110
+ def log_duration?
111
+ @log_duration
112
+ end
113
+ end
114
+
115
+ def log_with_formatter(level: :info, **kw_args)
116
+ fmt = EventFormatter.new(**kw_args)
117
+ msg = yield fmt
118
+ logger.public_send(level, **msg, payload: fmt.payload)
119
+ end
120
+
121
+ def logger
122
+ ::ActiveJob::Base.logger
123
+ end
124
+ end
125
+ end
126
+ end
@@ -31,6 +31,8 @@ module RailsSemanticLogger
31
31
 
32
32
  log_payload = {sql: payload[:sql]}
33
33
  log_payload[:binds] = bind_values(payload) unless (payload[:binds] || []).empty?
34
+ log_payload[:allocations] = event.allocations if event.respond_to?(:allocations)
35
+ log_payload[:cached] = event.payload[:cached]
34
36
 
35
37
  log = {
36
38
  message: name,
@@ -40,7 +42,7 @@ module RailsSemanticLogger
40
42
 
41
43
  # Log the location of the query itself.
42
44
  if logger.send(:level_index) >= SemanticLogger.backtrace_level_index
43
- log[:backtrace] = SemanticLogger::Utils.strip_backtrace
45
+ log[:backtrace] = SemanticLogger::Utils.strip_backtrace(caller)
44
46
  end
45
47
 
46
48
  logger.debug(log)
@@ -48,11 +50,11 @@ module RailsSemanticLogger
48
50
 
49
51
  private
50
52
 
51
- @logger = SemanticLogger['ActiveRecord']
53
+ @logger = SemanticLogger["ActiveRecord"]
52
54
 
53
55
  # When multiple values are received for a single bound field, it is converted into an array
54
56
  def add_bind_value(binds, key, value)
55
- key = key.downcase.to_sym
57
+ key = key.downcase.to_sym unless key.nil?
56
58
  value = (Array(binds[key]) << value) if binds.key?(key)
57
59
  binds[key] = value
58
60
  end
@@ -115,12 +117,22 @@ module RailsSemanticLogger
115
117
  binds
116
118
  end
117
119
 
120
+ def bind_values_v6_1(payload)
121
+ binds = {}
122
+ casted_params = type_casted_binds(payload[:type_casted_binds])
123
+ payload[:binds].each_with_index do |attr, i|
124
+ attr_name, value = render_bind(attr, casted_params[i])
125
+ add_bind_value(binds, attr_name, value)
126
+ end
127
+ binds
128
+ end
129
+
118
130
  def render_bind_v4_2(column, value)
119
131
  if column
120
132
  if column.binary?
121
133
  # This specifically deals with the PG adapter that casts bytea columns into a Hash.
122
134
  value = value[:value] if value.is_a?(Hash)
123
- value = value ? "<#{value.bytesize} bytes of binary data>" : '<NULL binary data>'
135
+ value = value ? "<#{value.bytesize} bytes of binary data>" : "<NULL binary data>"
124
136
  end
125
137
 
126
138
  [column.name, value]
@@ -154,6 +166,21 @@ module RailsSemanticLogger
154
166
  [attr&.name, value]
155
167
  end
156
168
 
169
+ def render_bind_v6_1(attr, value)
170
+ case attr
171
+ when ActiveModel::Attribute
172
+ if attr.type.binary? && attr.value
173
+ value = "<#{attr.value_for_database.to_s.bytesize} bytes of binary data>"
174
+ end
175
+ when Array
176
+ attr = attr.first
177
+ else
178
+ attr = nil
179
+ end
180
+
181
+ [attr&.name || :nil, value]
182
+ end
183
+
157
184
  def type_casted_binds_v5_0_3(binds, casted_binds)
158
185
  casted_binds || ::ActiveRecord::Base.connection.type_casted_binds(binds)
159
186
  end
@@ -171,6 +198,10 @@ module RailsSemanticLogger
171
198
  alias bind_values bind_values_v5_0_3
172
199
  alias render_bind render_bind_v5_0_3
173
200
  alias type_casted_binds type_casted_binds_v5_0_3
201
+ elsif Rails::VERSION::MAJOR == 6 && Rails::VERSION::MINOR > 0 # ~> 6.1.0
202
+ alias bind_values bind_values_v6_1
203
+ alias render_bind render_bind_v6_1
204
+ alias type_casted_binds type_casted_binds_v5_1_5
174
205
  elsif Rails::VERSION::MAJOR >= 5 # ~> 5.1.5 && ~> 5.0.7 && 6.x.x
175
206
  alias bind_values bind_values_v5_1_5
176
207
  alias render_bind render_bind_v5_0_3
@@ -2,7 +2,7 @@ module RailsSemanticLogger
2
2
  module DelayedJob
3
3
  class Plugin < Delayed::Plugin
4
4
  callbacks do |lifecycle|
5
- lifecycle.before(:execute) do |job, &block|
5
+ lifecycle.before(:execute) do |_job|
6
6
  ::SemanticLogger.reopen
7
7
  end
8
8
  end
@@ -1,6 +1,7 @@
1
- require 'rails'
2
- require 'action_controller/log_subscriber'
3
- require 'rails_semantic_logger/options'
1
+ require "rails"
2
+ require "action_controller/log_subscriber"
3
+ require "action_view/log_subscriber"
4
+ require "rails_semantic_logger/options"
4
5
 
5
6
  module RailsSemanticLogger
6
7
  class Engine < ::Rails::Engine
@@ -41,53 +42,54 @@ module RailsSemanticLogger
41
42
 
42
43
  # Existing loggers are ignored because servers like trinidad supply their
43
44
  # own file loggers which would result in duplicate logging to the same log file
44
- Rails.logger = config.logger = begin
45
- if config.rails_semantic_logger.add_file_appender
46
- path = config.paths['log'].first
47
- FileUtils.mkdir_p(File.dirname(path)) unless File.exist?(File.dirname(path))
48
-
49
- # Add the log file to the list of appenders
50
- # Use the colorized formatter if Rails colorized logs are enabled
51
- ap_options = config.rails_semantic_logger.ap_options
52
- formatter = config.rails_semantic_logger.format
53
- formatter = {color: {ap: ap_options}} if (formatter == :default) && (config.colorize_logging != false)
54
-
55
- # Set internal logger to log to file only, in case another appender experiences errors during writes
56
- appender = SemanticLogger::Appender::File.new(
57
- file_name: path,
58
- level: config.log_level,
59
- formatter: formatter
45
+ Rails.logger = config.logger =
46
+ begin
47
+ if config.rails_semantic_logger.add_file_appender
48
+ path = config.paths["log"].first
49
+ FileUtils.mkdir_p(File.dirname(path)) unless File.exist?(File.dirname(path))
50
+
51
+ # Add the log file to the list of appenders
52
+ # Use the colorized formatter if Rails colorized logs are enabled
53
+ ap_options = config.rails_semantic_logger.ap_options
54
+ formatter = config.rails_semantic_logger.format
55
+ formatter = {color: {ap: ap_options}} if (formatter == :default) && (config.colorize_logging != false)
56
+
57
+ # 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
+ )
63
+ appender.name = "SemanticLogger"
64
+ SemanticLogger::Processor.logger = appender
65
+
66
+ # Check for previous file or stdout loggers
67
+ SemanticLogger.appenders.each { |app| app.formatter = formatter if app.is_a?(SemanticLogger::Appender::File) }
68
+ SemanticLogger.add_appender(file_name: path, formatter: formatter, filter: config.rails_semantic_logger.filter)
69
+ end
70
+
71
+ SemanticLogger[Rails]
72
+ rescue StandardError => e
73
+ # If not able to log to file, log to standard error with warning level only
74
+ SemanticLogger.default_level = :warn
75
+
76
+ SemanticLogger::Processor.logger = SemanticLogger::Appender::File.new(io: STDERR)
77
+ SemanticLogger.add_appender(io: STDERR)
78
+
79
+ logger = SemanticLogger[Rails]
80
+ logger.warn(
81
+ "Rails Error: Unable to access log file. Please ensure that #{path} exists and is chmod 0666. " \
82
+ "The log level has been raised to WARN and the output directed to STDERR until the problem is fixed.",
83
+ e
60
84
  )
61
- appender.name = 'SemanticLogger'
62
- SemanticLogger::Processor.logger = appender
63
-
64
- # Check for previous file or stdout loggers
65
- SemanticLogger.appenders.each { |app| app.formatter = formatter if app.is_a?(SemanticLogger::Appender::File) }
66
- SemanticLogger.add_appender(file_name: path, formatter: formatter, filter: config.rails_semantic_logger.filter)
85
+ logger
67
86
  end
68
87
 
69
- SemanticLogger[Rails]
70
- rescue StandardError => exc
71
- # If not able to log to file, log to standard error with warning level only
72
- SemanticLogger.default_level = :warn
73
-
74
- SemanticLogger::Processor.logger = SemanticLogger::Appender::File.new(io: STDERR)
75
- SemanticLogger.add_appender(io: STDERR)
76
-
77
- logger = SemanticLogger[Rails]
78
- logger.warn(
79
- "Rails Error: Unable to access log file. Please ensure that #{path} exists and is chmod 0666. " \
80
- 'The log level has been raised to WARN and the output directed to STDERR until the problem is fixed.',
81
- exc
82
- )
83
- logger
84
- end
85
-
86
88
  # Replace Rails loggers
87
89
  %i[active_record action_controller action_mailer action_view].each do |name|
88
90
  ActiveSupport.on_load(name) { include SemanticLogger::Loggable }
89
91
  end
90
- ActiveSupport.on_load(:action_cable) { self.logger = SemanticLogger['ActionCable'] }
92
+ ActiveSupport.on_load(:action_cable) { self.logger = SemanticLogger["ActionCable"] }
91
93
  end
92
94
 
93
95
  # Before any initializers run, but after the gems have been loaded
@@ -100,18 +102,18 @@ module RailsSemanticLogger
100
102
  end
101
103
 
102
104
  # Replace the Mongo Loggers
103
- Mongoid.logger = SemanticLogger[Mongoid] if defined?(Mongoid)
104
- Moped.logger = SemanticLogger[Moped] if defined?(Moped)
105
- Mongo::Logger.logger = SemanticLogger[Mongo] if defined?(Mongo::Logger)
105
+ Mongoid.logger = SemanticLogger[Mongoid] if defined?(Mongoid)
106
+ Moped.logger = SemanticLogger[Moped] if defined?(Moped)
107
+ Mongo::Logger.logger = SemanticLogger[Mongo] if defined?(Mongo::Logger)
106
108
 
107
109
  # Replace the Resque Logger
108
- Resque.logger = SemanticLogger[Resque] if defined?(Resque) && Resque.respond_to?(:logger)
110
+ Resque.logger = SemanticLogger[Resque] if defined?(Resque) && Resque.respond_to?(:logger)
109
111
 
110
112
  # Replace the Sidekiq logger
111
- Sidekiq.logger = SemanticLogger[Sidekiq] if defined?(Sidekiq)
113
+ Sidekiq.logger = SemanticLogger[Sidekiq] if defined?(Sidekiq)
112
114
 
113
115
  # Replace the Sidetiq logger
114
- Sidetiq.logger = SemanticLogger[Sidetiq] if defined?(Sidetiq)
116
+ Sidetiq.logger = SemanticLogger[Sidetiq] if defined?(Sidetiq)
115
117
 
116
118
  # Replace the DelayedJob logger
117
119
  if defined?(Delayed::Worker)
@@ -125,21 +127,42 @@ module RailsSemanticLogger
125
127
 
126
128
  # After any initializers run, but after the gems have been loaded
127
129
  config.after_initialize do
130
+ config = Rails.application.config
131
+
128
132
  # Replace the Bugsnag logger
129
- Bugsnag.configure { |config| config.logger = SemanticLogger[Bugsnag] } if defined?(Bugsnag)
133
+ Bugsnag.configure { |bugsnag_config| bugsnag_config.logger = SemanticLogger[Bugsnag] } if defined?(Bugsnag)
130
134
 
131
135
  # Rails Patches
132
- require('rails_semantic_logger/extensions/action_cable/tagged_logger_proxy') if defined?(ActionCable)
133
- require('rails_semantic_logger/extensions/action_controller/live') if defined?(ActionController::Live)
134
- require('rails_semantic_logger/extensions/action_dispatch/debug_exceptions') if defined?(ActionDispatch::DebugExceptions)
135
- require('rails_semantic_logger/extensions/action_view/streaming_template_renderer') if defined?(ActionView::StreamingTemplateRenderer::Body)
136
- require('rails_semantic_logger/extensions/active_job/logging') if defined?(ActiveJob)
137
- require('rails_semantic_logger/extensions/active_model_serializers/logging') if defined?(ActiveModelSerializers)
136
+ require("rails_semantic_logger/extensions/action_cable/tagged_logger_proxy") if defined?(::ActionCable)
137
+ require("rails_semantic_logger/extensions/action_controller/live") if defined?(::ActionController::Live)
138
+ require("rails_semantic_logger/extensions/action_dispatch/debug_exceptions") if defined?(::ActionDispatch::DebugExceptions)
139
+ if defined?(::ActionView::StreamingTemplateRenderer::Body)
140
+ require("rails_semantic_logger/extensions/action_view/streaming_template_renderer")
141
+ end
142
+ require("rails_semantic_logger/extensions/active_job/logging") if defined?(::ActiveJob)
143
+ require("rails_semantic_logger/extensions/active_model_serializers/logging") if defined?(::ActiveModelSerializers)
138
144
 
139
145
  if config.rails_semantic_logger.semantic
146
+ # Active Job
147
+ if defined?(::ActiveJob) && defined?(::ActiveJob::Logging::LogSubscriber)
148
+ RailsSemanticLogger.swap_subscriber(
149
+ ::ActiveJob::Logging::LogSubscriber,
150
+ RailsSemanticLogger::ActiveJob::LogSubscriber,
151
+ :active_job
152
+ )
153
+ end
154
+
155
+ if defined?(::ActiveJob) && defined?(::ActiveJob::LogSubscriber)
156
+ RailsSemanticLogger.swap_subscriber(
157
+ ::ActiveJob::LogSubscriber,
158
+ RailsSemanticLogger::ActiveJob::LogSubscriber,
159
+ :active_job
160
+ )
161
+ end
162
+
140
163
  # Active Record
141
164
  if defined?(::ActiveRecord)
142
- require 'active_record/log_subscriber'
165
+ require "active_record/log_subscriber"
143
166
 
144
167
  RailsSemanticLogger.swap_subscriber(
145
168
  ::ActiveRecord::LogSubscriber,
@@ -153,7 +176,8 @@ module RailsSemanticLogger
153
176
 
154
177
  # Silence asset logging by applying a filter to the Rails logger itself, not any of the appenders.
155
178
  if config.rails_semantic_logger.quiet_assets && config.assets.prefix
156
- assets_regex = %r(\A/{0,2}#{config.assets.prefix})
179
+ assets_root = config.relative_url_root.to_s + config.assets.prefix
180
+ assets_regex = %r(\A/{0,2}#{assets_root})
157
181
  RailsSemanticLogger::Rack::Logger.logger.filter = ->(log) { log.payload[:path] !~ assets_regex if log.payload }
158
182
  end
159
183
 
@@ -190,6 +214,15 @@ module RailsSemanticLogger
190
214
 
191
215
  # Re-open appenders after Spring has forked a process
192
216
  Spring.after_fork { |_job| ::SemanticLogger.reopen } if defined?(Spring.after_fork)
217
+
218
+ console do |_app|
219
+ # Don't use a background thread for logging
220
+ SemanticLogger.sync!
221
+ SemanticLogger.add_appender(io: STDERR, formatter: :color)
222
+
223
+ # Include method names on log entries in the console
224
+ SemanticLogger.backtrace_level = SemanticLogger.default_level
225
+ end
193
226
  end
194
227
  end
195
228
  end
@@ -2,6 +2,7 @@
2
2
  ActionController::Live
3
3
  module ActionController
4
4
  module Live
5
+ undef_method :log_error
5
6
  def log_error(exception)
6
7
  logger.fatal(exception)
7
8
  end
@@ -4,6 +4,7 @@ module ActionDispatch
4
4
  class DebugExceptions
5
5
  private
6
6
 
7
+ undef_method :log_error
7
8
  def log_error(_request, wrapper)
8
9
  ActiveSupport::Deprecation.silence do
9
10
  ActionController::Base.logger.fatal(wrapper.exception)
@@ -6,6 +6,7 @@ module ActionView
6
6
  class Body
7
7
  private
8
8
 
9
+ undef_method :log_error
9
10
  def log_error(exception)
10
11
  ActionView::Base.logger.fatal(exception)
11
12
  end
@@ -1,5 +1,5 @@
1
1
  # Patch ActiveJob logger
2
- require 'active_job/logging'
2
+ require "active_job/logging"
3
3
 
4
4
  module ActiveJob
5
5
  module Logging
@@ -10,126 +10,5 @@ module ActiveJob
10
10
  def tag_logger(*tags, &block)
11
11
  logger.tagged(*tags, &block)
12
12
  end
13
-
14
- class LogSubscriber < ActiveSupport::LogSubscriber
15
- def enqueue(event)
16
- log_with_formatter event: event do |fmt|
17
- "Enqueued #{fmt.job_info}"
18
- end
19
- end
20
-
21
- def enqueue_at(event)
22
- log_with_formatter event: event do |fmt|
23
- "Enqueued #{fmt.job_info} at #{fmt.scheduled_at}"
24
- end
25
- end
26
-
27
- def perform_start(event)
28
- log_with_formatter event: event do |fmt|
29
- "Performing #{fmt.job_info}"
30
- end
31
- end
32
-
33
- def perform(event)
34
- ex = event.payload[:exception_object]
35
- if ex
36
- logger.error ex
37
- else
38
- log_with_formatter event: event, log_duration: true do |fmt|
39
- "Performed #{fmt.job_info} in #{event.duration.round(2)}ms"
40
- end
41
- end
42
- end
43
-
44
- private
45
-
46
- class EventFormatter
47
- def initialize(event:, log_duration: false)
48
- @event = event
49
- @log_duration = log_duration
50
- end
51
-
52
- def job_info
53
- "#{job.class.name} (Job ID: #{job.job_id}) to #{queue_name}"
54
- end
55
-
56
- def payload
57
- {}.tap do |h|
58
- h[:event_name] = event.name
59
- h[:adapter] = adapter_name
60
- h[:queue] = job.queue_name
61
- h[:job_class] = job.class.name
62
- h[:job_id] = job.job_id
63
- h[:provider_job_id] = job.try(:provider_job_id) # Not available in Rails 4.2
64
- h[:duration] = event.duration.round(2) if log_duration?
65
- h[:arguments] = formatted_args
66
- end
67
- end
68
-
69
- def queue_name
70
- adapter_name + "(#{job.queue_name})"
71
- end
72
-
73
- def scheduled_at
74
- Time.at(event.payload[:job].scheduled_at).utc
75
- end
76
-
77
- private
78
-
79
- attr_reader :event
80
-
81
- def job
82
- event.payload[:job]
83
- end
84
-
85
- def adapter_name
86
- event.payload[:adapter].class.name.demodulize.remove('Adapter')
87
- end
88
-
89
- def formatted_args
90
- JSON.pretty_generate(job.arguments.map { |arg| format(arg) })
91
- end
92
-
93
- def format(arg)
94
- case arg
95
- when Hash
96
- arg.transform_values { |value| format(value) }
97
- when Array
98
- arg.map { |value| format(value) }
99
- when GlobalID::Identification
100
- begin
101
- arg.to_global_id
102
- rescue StandardError
103
- arg
104
- end
105
- else
106
- arg
107
- end
108
- end
109
-
110
- def log_duration?
111
- @log_duration
112
- end
113
- end
114
-
115
- def log_with_formatter(**kw_args)
116
- fmt = EventFormatter.new(**kw_args)
117
- msg = yield fmt
118
- logger.info msg, fmt.payload
119
- end
120
-
121
- def logger
122
- ActiveJob::Base.logger
123
- end
124
- end
125
13
  end
126
14
  end
127
-
128
- if defined?(ActiveSupport::Notifications)
129
- ActiveSupport::Notifications.unsubscribe('perform_start.active_job')
130
- ActiveSupport::Notifications.unsubscribe('perform.active_job')
131
- ActiveSupport::Notifications.unsubscribe('enqueue_at.active_job')
132
- ActiveSupport::Notifications.unsubscribe('enqueue.active_job')
133
-
134
- ActiveJob::Logging::LogSubscriber.attach_to :active_job
135
- end
@@ -1,5 +1,5 @@
1
1
  # Patch ActiveModelSerializers logger
2
- require 'active_model_serializers/logging'
2
+ require "active_model_serializers/logging"
3
3
 
4
4
  module ActiveModelSerializers
5
5
  module Logging
@@ -0,0 +1,24 @@
1
+ require "active_support/logger"
2
+
3
+ module ActiveSupport
4
+ # More hacks to try and stop Rails from being it's own worst enemy.
5
+ class Logger
6
+ class << self
7
+ undef :logger_outputs_to?, :broadcast
8
+ end
9
+
10
+ # Prevent Console from trying to merge loggers
11
+ def self.logger_outputs_to?(*args)
12
+ true
13
+ end
14
+
15
+ # Prevent broadcasting since SemanticLogger already supports multiple loggers
16
+ def self.broadcast(logger)
17
+ Module.new
18
+ end
19
+
20
+ def self.new(*args, **kwargs)
21
+ SemanticLogger[self]
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,8 @@
1
+ module ActiveSupport
2
+ module TaggedLogging
3
+ # Semantic Logger already does tagged logging
4
+ def self.new(logger)
5
+ logger
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,11 @@
1
+ require "mongoid/config"
2
+
3
+ module Mongoid
4
+ module Config
5
+ private
6
+
7
+ # Remove log overrides
8
+ def set_log_levels
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ module RailsSemanticLogger
2
+ module Rack
3
+ module Server
4
+ def daemonize_app
5
+ super
6
+ SemanticLogger.reopen
7
+ end
8
+ end
9
+ end
10
+ end
11
+
12
+ Rack::Server.prepend(RailsSemanticLogger::Rack::Server)
@@ -5,6 +5,8 @@ module Rails
5
5
  private
6
6
 
7
7
  def log_to_stdout
8
+ wrapped_app # touch the app so the logger is set up
9
+
8
10
  SemanticLogger.add_appender(io: $stdout, formatter: :color)
9
11
  end
10
12
  end
@@ -1,8 +1,8 @@
1
- require 'active_support/core_ext/time/conversions'
2
- require 'active_support/core_ext/object/blank'
3
- require 'active_support/log_subscriber'
4
- require 'action_dispatch/http/request'
5
- require 'rack/body_proxy'
1
+ require "active_support/core_ext/time/conversions"
2
+ require "active_support/core_ext/object/blank"
3
+ require "active_support/log_subscriber"
4
+ require "action_dispatch/http/request"
5
+ require "rack/body_proxy"
6
6
 
7
7
  module RailsSemanticLogger
8
8
  module Rack
@@ -31,12 +31,12 @@ module RailsSemanticLogger
31
31
 
32
32
  private
33
33
 
34
- @logger = SemanticLogger['Rack']
34
+ @logger = SemanticLogger["Rack"]
35
35
  @started_request_log_level = :debug
36
36
 
37
37
  def call_app(request, env)
38
38
  instrumenter = ActiveSupport::Notifications.instrumenter
39
- instrumenter.start 'request.action_dispatch', request: request
39
+ instrumenter.start "request.action_dispatch", request: request
40
40
 
41
41
  logger.send(self.class.started_request_log_level) { started_request_message(request) }
42
42
 
@@ -50,11 +50,11 @@ module RailsSemanticLogger
50
50
 
51
51
  def started_request_message(request)
52
52
  {
53
- message: 'Started',
53
+ message: "Started",
54
54
  payload: {
55
55
  method: request.request_method,
56
56
  path: request.filtered_path,
57
- ip: request.ip
57
+ ip: request.remote_ip
58
58
  }
59
59
  }
60
60
  end
@@ -92,7 +92,7 @@ module RailsSemanticLogger
92
92
 
93
93
  def finish(request)
94
94
  instrumenter = ActiveSupport::Notifications.instrumenter
95
- instrumenter.finish 'request.action_dispatch', request: request
95
+ instrumenter.finish "request.action_dispatch", request: request
96
96
  end
97
97
 
98
98
  def logger
@@ -1,3 +1,3 @@
1
1
  module RailsSemanticLogger
2
- VERSION = '4.4.3'.freeze
2
+ VERSION = "4.6.1".freeze
3
3
  end
@@ -1,25 +1,28 @@
1
- require 'semantic_logger'
2
- require 'rails_semantic_logger/extensions/rails/server' if defined?(Rails::Server)
3
- require 'rails_semantic_logger/engine'
1
+ require "semantic_logger"
2
+ require "rails_semantic_logger/extensions/rails/server" if defined?(Rails::Server)
3
+ require "rails_semantic_logger/engine"
4
4
 
5
5
  module RailsSemanticLogger
6
6
  module ActionController
7
- autoload :LogSubscriber, 'rails_semantic_logger/action_controller/log_subscriber'
7
+ autoload :LogSubscriber, "rails_semantic_logger/action_controller/log_subscriber"
8
8
  end
9
9
  module ActionView
10
- autoload :LogSubscriber, 'rails_semantic_logger/action_view/log_subscriber'
10
+ autoload :LogSubscriber, "rails_semantic_logger/action_view/log_subscriber"
11
+ end
12
+ module ActiveJob
13
+ autoload :LogSubscriber, "rails_semantic_logger/active_job/log_subscriber"
11
14
  end
12
15
  module ActiveRecord
13
- autoload :LogSubscriber, 'rails_semantic_logger/active_record/log_subscriber'
16
+ autoload :LogSubscriber, "rails_semantic_logger/active_record/log_subscriber"
14
17
  end
15
18
  module Rack
16
- autoload :Logger, 'rails_semantic_logger/rack/logger'
19
+ autoload :Logger, "rails_semantic_logger/rack/logger"
17
20
  end
18
21
  module DelayedJob
19
- autoload :Plugin, 'rails_semantic_logger/delayed_job/plugin'
22
+ autoload :Plugin, "rails_semantic_logger/delayed_job/plugin"
20
23
  end
21
24
 
22
- autoload :Options, 'rails_semantic_logger/options'
25
+ autoload :Options, "rails_semantic_logger/options"
23
26
 
24
27
  # Swap an existing subscriber with a new one
25
28
  def self.swap_subscriber(old_class, new_class, notifier)
@@ -33,6 +36,7 @@ module RailsSemanticLogger
33
36
  subscriber_patterns(subscriber).each do |pattern|
34
37
  ActiveSupport::Notifications.notifier.listeners_for(pattern).each do |sub|
35
38
  next unless sub.instance_variable_get(:@delegate) == subscriber
39
+
36
40
  ActiveSupport::Notifications.unsubscribe(sub)
37
41
  end
38
42
  end
@@ -48,3 +52,7 @@ module RailsSemanticLogger
48
52
 
49
53
  private_class_method :subscriber_patterns, :unattach
50
54
  end
55
+
56
+ require("rails_semantic_logger/extensions/mongoid/config") if defined?(Mongoid)
57
+ require("rails_semantic_logger/extensions/active_support/logger") if defined?(ActiveSupport::Logger)
58
+ require("rails_semantic_logger/extensions/rack/server") if defined?(Rack::Server)
metadata CHANGED
@@ -1,60 +1,59 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_semantic_logger
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.4.3
4
+ version: 4.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Reid Morrison
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-10-10 00:00:00.000000000 Z
11
+ date: 2021-08-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: railties
14
+ name: rack
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '3.2'
19
+ version: '0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '3.2'
26
+ version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: rack
28
+ name: railties
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: '3.2'
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: '0'
40
+ version: '3.2'
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.4'
47
+ version: '4.8'
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.4'
55
- description:
54
+ version: '4.8'
55
+ description:
56
56
  email:
57
- - reidmo@gmail.com
58
57
  executables: []
59
58
  extensions: []
60
59
  extra_rdoc_files: []
@@ -65,6 +64,7 @@ files:
65
64
  - lib/rails_semantic_logger.rb
66
65
  - lib/rails_semantic_logger/action_controller/log_subscriber.rb
67
66
  - lib/rails_semantic_logger/action_view/log_subscriber.rb
67
+ - lib/rails_semantic_logger/active_job/log_subscriber.rb
68
68
  - lib/rails_semantic_logger/active_record/log_subscriber.rb
69
69
  - lib/rails_semantic_logger/delayed_job/plugin.rb
70
70
  - lib/rails_semantic_logger/engine.rb
@@ -74,15 +74,19 @@ files:
74
74
  - lib/rails_semantic_logger/extensions/action_view/streaming_template_renderer.rb
75
75
  - lib/rails_semantic_logger/extensions/active_job/logging.rb
76
76
  - lib/rails_semantic_logger/extensions/active_model_serializers/logging.rb
77
+ - lib/rails_semantic_logger/extensions/active_support/logger.rb
78
+ - lib/rails_semantic_logger/extensions/active_support/tagged_logging.rb
79
+ - lib/rails_semantic_logger/extensions/mongoid/config.rb
80
+ - lib/rails_semantic_logger/extensions/rack/server.rb
77
81
  - lib/rails_semantic_logger/extensions/rails/server.rb
78
82
  - lib/rails_semantic_logger/options.rb
79
83
  - lib/rails_semantic_logger/rack/logger.rb
80
84
  - lib/rails_semantic_logger/version.rb
81
- homepage: https://github.com/rocketjob/rails_semantic_logger
85
+ homepage: https://logger.rocketjob.io
82
86
  licenses:
83
87
  - Apache-2.0
84
88
  metadata: {}
85
- post_install_message:
89
+ post_install_message:
86
90
  rdoc_options: []
87
91
  require_paths:
88
92
  - lib
@@ -90,15 +94,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
90
94
  requirements:
91
95
  - - ">="
92
96
  - !ruby/object:Gem::Version
93
- version: '2.3'
97
+ version: '2.5'
94
98
  required_rubygems_version: !ruby/object:Gem::Requirement
95
99
  requirements:
96
100
  - - ">="
97
101
  - !ruby/object:Gem::Version
98
102
  version: '0'
99
103
  requirements: []
100
- rubygems_version: 3.0.3
101
- signing_key:
104
+ rubygems_version: 3.2.22
105
+ signing_key:
102
106
  specification_version: 4
103
107
  summary: Feature rich logging framework that replaces the Rails logger.
104
108
  test_files: []