rails_semantic_logger 4.2.1 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -6
  3. data/Rakefile +2 -2
  4. data/lib/rails_semantic_logger.rb +35 -0
  5. data/lib/rails_semantic_logger/action_controller/log_subscriber.rb +108 -0
  6. data/lib/rails_semantic_logger/action_view/log_subscriber.rb +108 -0
  7. data/lib/rails_semantic_logger/active_record/log_subscriber.rb +186 -0
  8. data/lib/rails_semantic_logger/delayed_job/plugin.rb +11 -0
  9. data/lib/rails_semantic_logger/engine.rb +80 -70
  10. data/lib/rails_semantic_logger/extensions/action_controller/live.rb +5 -3
  11. data/lib/rails_semantic_logger/extensions/action_dispatch/debug_exceptions.rb +8 -6
  12. data/lib/rails_semantic_logger/extensions/action_view/streaming_template_renderer.rb +8 -5
  13. data/lib/rails_semantic_logger/extensions/active_job/logging.rb +8 -5
  14. data/lib/rails_semantic_logger/extensions/active_model_serializers/logging.rb +11 -8
  15. data/lib/rails_semantic_logger/extensions/rails/server.rb +2 -2
  16. data/lib/rails_semantic_logger/rack/logger.rb +103 -0
  17. data/lib/rails_semantic_logger/version.rb +2 -2
  18. metadata +13 -14
  19. data/lib/rails_semantic_logger/extensions/action_controller/log_subscriber.rb +0 -111
  20. data/lib/rails_semantic_logger/extensions/action_controller/log_subscriber_processing.rb +0 -28
  21. data/lib/rails_semantic_logger/extensions/action_view/log_subscriber.rb +0 -12
  22. data/lib/rails_semantic_logger/extensions/active_record/log_subscriber.rb +0 -102
  23. data/lib/rails_semantic_logger/extensions/rails/rack/logger.rb +0 -63
  24. data/lib/rails_semantic_logger/extensions/rails/rack/logger_info_as_debug.rb +0 -30
@@ -0,0 +1,11 @@
1
+ module RailsSemanticLogger
2
+ module DelayedJob
3
+ class Plugin < Delayed::Plugin
4
+ callbacks do |lifecycle|
5
+ lifecycle.before(:execute) do |job, &block|
6
+ ::SemanticLogger.reopen
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -1,3 +1,6 @@
1
+ require 'active_record/log_subscriber'
2
+ require 'action_controller/log_subscriber'
3
+
1
4
  module RailsSemanticLogger
2
5
  class Engine < ::Rails::Engine
3
6
  # Make the SemanticLogger config available in the Rails application config
@@ -16,22 +19,22 @@ module RailsSemanticLogger
16
19
  # end
17
20
  config.semantic_logger = ::SemanticLogger
18
21
 
19
- config.rails_semantic_logger = ActiveSupport::OrderedOptions.new
22
+ config.rails_semantic_logger = ActiveSupport::OrderedOptions.new
20
23
 
21
24
  # Convert Action Controller and Active Record text messages to semantic data
22
25
  # Rails -- Started -- { :ip => "127.0.0.1", :method => "GET", :path => "/dashboards/inquiry_recent_activity" }
23
26
  # UserController -- Completed #index -- { :action => "index", :db_runtime => 54.64, :format => "HTML", :method => "GET", :mongo_runtime => 0.0, :path => "/users", :status => 200, :status_message => "OK", :view_runtime => 709.88 }
24
- config.rails_semantic_logger.semantic = true
27
+ config.rails_semantic_logger.semantic = true
25
28
 
26
29
  # Change Rack started message to debug so that it does not appear in production
27
- config.rails_semantic_logger.started = false
30
+ config.rails_semantic_logger.started = false
28
31
 
29
32
  # Change Processing message to debug so that it does not appear in production
30
- config.rails_semantic_logger.processing = false
33
+ config.rails_semantic_logger.processing = false
31
34
 
32
35
  # Change Action View render log messages to debug so that they do not appear in production
33
36
  # ActionView::Base -- Rendered data/search/_user.html.haml (46.7ms)
34
- config.rails_semantic_logger.rendered = false
37
+ config.rails_semantic_logger.rendered = false
35
38
 
36
39
  # Override the Awesome Print options for logging Hash data as text:
37
40
  #
@@ -41,7 +44,7 @@ module RailsSemanticLogger
41
44
  #
42
45
  # Note: The option :multiline is set to false if not supplied.
43
46
  # Note: Has no effect if Awesome Print is not installed.
44
- config.rails_semantic_logger.ap_options = {multiline: false}
47
+ config.rails_semantic_logger.ap_options = {multiline: false}
45
48
 
46
49
  # Whether to automatically add an environment specific log file appender.
47
50
  # For Example: 'log/development.log'
@@ -54,7 +57,7 @@ module RailsSemanticLogger
54
57
  config.rails_semantic_logger.add_file_appender = true
55
58
 
56
59
  # Silence asset logging
57
- config.rails_semantic_logger.quiet_assets = false
60
+ config.rails_semantic_logger.quiet_assets = false
58
61
 
59
62
  # Override the output format for the primary Rails log file.
60
63
  #
@@ -90,18 +93,18 @@ module RailsSemanticLogger
90
93
  #
91
94
  # # In application.rb:
92
95
  # config.rails_semantic_logger.format = MyFormatter.new
93
- config.rails_semantic_logger.format = :default
96
+ config.rails_semantic_logger.format = :default
94
97
 
95
98
  # DEPRECATED
96
99
  # Instead, supply a Hash to config.log_tags
97
- config.rails_semantic_logger.named_tags = nil
100
+ config.rails_semantic_logger.named_tags = nil
98
101
 
99
102
  # Add a filter to the file logger [Regexp|Proc]
100
103
  # RegExp: Only include log messages where the class name matches the supplied
101
104
  # regular expression. All other messages will be ignored.
102
105
  # Proc: Only include log messages where the supplied Proc returns true.
103
106
  # The Proc must return true or false.
104
- config.rails_semantic_logger.filter = nil
107
+ config.rails_semantic_logger.filter = nil
105
108
 
106
109
  # Initialize SemanticLogger. In a Rails environment it will automatically
107
110
  # insert itself above the configured rails logger to add support for its
@@ -111,14 +114,18 @@ module RailsSemanticLogger
111
114
  Rails::Application::Bootstrap.initializers.delete_if { |i| i.name == :initialize_logger }
112
115
 
113
116
  initializer :initialize_logger, group: :all do
114
- config = Rails.application.config
117
+ config = Rails.application.config
115
118
 
116
119
  # Set the default log level based on the Rails config
117
120
  SemanticLogger.default_level = config.log_level
118
121
 
122
+ if defined?(Rails::Rack::Logger) && config.rails_semantic_logger.semantic
123
+ config.middleware.swap(Rails::Rack::Logger, RailsSemanticLogger::Rack::Logger, config.log_tags)
124
+ end
125
+
119
126
  # Existing loggers are ignored because servers like trinidad supply their
120
127
  # own file loggers which would result in duplicate logging to the same log file
121
- Rails.logger = config.logger = begin
128
+ Rails.logger = config.logger = begin
122
129
  if config.rails_semantic_logger.add_file_appender
123
130
  path = config.paths['log'].first
124
131
  FileUtils.mkdir_p(File.dirname(path)) unless File.exist?(File.dirname(path))
@@ -130,16 +137,16 @@ module RailsSemanticLogger
130
137
  formatter = {color: {ap: ap_options}} if (formatter == :default) && (config.colorize_logging != false)
131
138
 
132
139
  # Set internal logger to log to file only, in case another appender experiences errors during writes
133
- appender = SemanticLogger::Appender::File.new(file_name: path, level: config.log_level, formatter: formatter)
140
+ appender = SemanticLogger::Appender::File.new(
141
+ file_name: path,
142
+ level: config.log_level,
143
+ formatter: formatter
144
+ )
134
145
  appender.name = 'SemanticLogger'
135
146
  SemanticLogger::Processor.logger = appender
136
147
 
137
148
  # Check for previous file or stdout loggers
138
- if SemanticLogger::VERSION.to_f >= 4.2
139
- SemanticLogger.appenders.each { |appender| appender.formatter = formatter if appender.is_a?(SemanticLogger::Appender::File) }
140
- elsif config.colorize_logging == false
141
- SemanticLogger.appenders.each { |appender| appender.formatter = SemanticLogger::Formatters::Default.new if appender.is_a?(SemanticLogger::Appender::File) }
142
- end
149
+ SemanticLogger.appenders.each { |app| app.formatter = formatter if app.is_a?(SemanticLogger::Appender::File) }
143
150
  SemanticLogger.add_appender(file_name: path, formatter: formatter, filter: config.rails_semantic_logger.filter)
144
151
  end
145
152
 
@@ -153,54 +160,29 @@ module RailsSemanticLogger
153
160
 
154
161
  logger = SemanticLogger[Rails]
155
162
  logger.warn(
156
- "Rails Error: Unable to access log file. Please ensure that #{path} exists and is chmod 0666. " +
157
- "The log level has been raised to WARN and the output directed to STDERR until the problem is fixed.",
163
+ "Rails Error: Unable to access log file. Please ensure that #{path} exists and is chmod 0666. " \
164
+ 'The log level has been raised to WARN and the output directed to STDERR until the problem is fixed.',
158
165
  exc
159
166
  )
160
167
  logger
161
168
  end
162
169
 
163
170
  # Replace Rails loggers
164
- [:active_record, :action_controller, :action_mailer, :action_view].each do |name|
171
+ %i[active_record action_controller action_mailer action_view].each do |name|
165
172
  ActiveSupport.on_load(name) { include SemanticLogger::Loggable }
166
173
  end
167
174
  ActiveSupport.on_load(:action_cable) { self.logger = SemanticLogger['ActionCable'] }
168
175
  end
169
176
 
170
- # Support fork frameworks
171
- config.after_initialize do
172
- # Silence asset logging by applying a filter to the Rails logger itself, not any of the appenders.
173
- if config.rails_semantic_logger.quiet_assets && config.assets.prefix #&& defined?(Rails::Rack::Logger)
174
- assets_regex = %r(\A/{0,2}#{config.assets.prefix})
175
- if Rails.version.to_i >= 5
176
- Rails::Rack::Logger.logger.filter = -> log { log.payload[:path] !~ assets_regex if log.payload }
177
- else
178
- # Also strips the empty log lines
179
- Rails::Rack::Logger.logger.filter = -> log { log.payload.nil? ? (log.message != '') : (log.payload[:path] !~ assets_regex) }
180
- end
181
- end
182
-
183
- # Passenger provides the :starting_worker_process event for executing
184
- # code after it has forked, so we use that and reconnect immediately.
185
- if defined?(PhusionPassenger)
186
- PhusionPassenger.on_event(:starting_worker_process) do |forked|
187
- ::SemanticLogger.reopen if forked
188
- end
189
- end
190
-
191
- # Re-open appenders after Resque has forked a worker
192
- if defined?(Resque)
193
- Resque.after_fork { |job| ::SemanticLogger.reopen }
194
- end
177
+ # Before any initializers run, but after the gems have been loaded
178
+ config.before_initialize do
179
+ if config.respond_to?(:assets) && defined?(Rails::Rack::Logger) && config.rails_semantic_logger.semantic
180
+ config.rails_semantic_logger.quiet_assets = true if config.assets.quiet
195
181
 
196
- # Re-open appenders after Spring has forked a process
197
- if defined?(Spring)
198
- Spring.after_fork { |job| ::SemanticLogger.reopen }
182
+ # Otherwise Sprockets can't find the Rails::Rack::Logger middleware
183
+ config.assets.quiet = false
199
184
  end
200
- end
201
185
 
202
- # Before any initializers run, but after the gems have been loaded
203
- config.before_initialize do
204
186
  # Replace the Mongo Loggers
205
187
  Mongoid.logger = SemanticLogger[Mongoid] if defined?(Mongoid)
206
188
  Moped.logger = SemanticLogger[Moped] if defined?(Moped)
@@ -216,15 +198,13 @@ module RailsSemanticLogger
216
198
  Sidetiq.logger = SemanticLogger[Sidetiq] if defined?(Sidetiq)
217
199
 
218
200
  # Replace the DelayedJob logger
219
- Delayed::Worker.logger = SemanticLogger[Delayed::Worker] if defined?(Delayed::Worker)
201
+ if defined?(Delayed::Worker)
202
+ Delayed::Worker.logger = SemanticLogger[Delayed::Worker]
203
+ Delayed::Worker.plugins << RailsSemanticLogger::DelayedJob::Plugin
204
+ end
220
205
 
221
206
  # Replace the Bugsnag logger
222
207
  Bugsnag.configure { |config| config.logger = SemanticLogger[Bugsnag] } if defined?(Bugsnag)
223
-
224
- # Backward compatibility
225
- if config.rails_semantic_logger.named_tags
226
- config.log_tags = config.rails_semantic_logger.named_tags
227
- end
228
208
  end
229
209
 
230
210
  # After any initializers run, but after the gems have been loaded
@@ -241,23 +221,53 @@ module RailsSemanticLogger
241
221
  require('rails_semantic_logger/extensions/active_model_serializers/logging') if defined?(ActiveModelSerializers)
242
222
 
243
223
  if config.rails_semantic_logger.semantic
244
- require('rails_semantic_logger/extensions/rails/rack/logger') if defined?(Rails::Rack::Logger)
245
- require('rails_semantic_logger/extensions/action_controller/log_subscriber') if defined?(ActionController)
246
- require('rails_semantic_logger/extensions/active_record/log_subscriber') if defined?(ActiveRecord::LogSubscriber)
247
- end
224
+ # Active Record
225
+ RailsSemanticLogger.swap_subscriber(
226
+ ::ActiveRecord::LogSubscriber,
227
+ RailsSemanticLogger::ActiveRecord::LogSubscriber,
228
+ :active_record
229
+ )
248
230
 
249
- unless config.rails_semantic_logger.started
250
- require('rails_semantic_logger/extensions/rails/rack/logger_info_as_debug') if defined?(Rails::Rack::Logger)
251
- end
231
+ # Rack
232
+ RailsSemanticLogger::Rack::Logger.started_request_log_level = :info if config.rails_semantic_logger.started
233
+
234
+ # Silence asset logging by applying a filter to the Rails logger itself, not any of the appenders.
235
+ if config.rails_semantic_logger.quiet_assets && config.assets.prefix
236
+ assets_regex = %r(\A/{0,2}#{config.assets.prefix})
237
+ RailsSemanticLogger::Rack::Logger.logger.filter = ->(log) { log.payload[:path] !~ assets_regex if log.payload }
238
+ end
239
+
240
+ # Action View
241
+ RailsSemanticLogger::ActionView::LogSubscriber.rendered_log_level = :info if config.rails_semantic_logger.rendered
242
+ RailsSemanticLogger.swap_subscriber(
243
+ ::ActionView::LogSubscriber,
244
+ RailsSemanticLogger::ActionView::LogSubscriber,
245
+ :action_view
246
+ )
252
247
 
253
- unless config.rails_semantic_logger.rendered
254
- require('rails_semantic_logger/extensions/action_view/log_subscriber') if defined?(ActionView::LogSubscriber)
248
+ # Action Controller
249
+ RailsSemanticLogger.swap_subscriber(
250
+ ::ActionController::LogSubscriber,
251
+ RailsSemanticLogger::ActionController::LogSubscriber,
252
+ :action_controller
253
+ )
255
254
  end
256
255
 
257
- if config.rails_semantic_logger.processing
258
- require('rails_semantic_logger/extensions/action_controller/log_subscriber_processing') if defined?(ActionView::LogSubscriber)
256
+ #
257
+ # Forking Frameworks
258
+ #
259
+
260
+ # Passenger provides the :starting_worker_process event for executing
261
+ # code after it has forked, so we use that and reconnect immediately.
262
+ if defined?(PhusionPassenger)
263
+ PhusionPassenger.on_event(:starting_worker_process) { |forked| ::SemanticLogger.reopen if forked }
259
264
  end
260
- end
261
265
 
266
+ # Re-open appenders after Resque has forked a worker
267
+ Resque.after_fork { |_job| ::SemanticLogger.reopen } if defined?(Resque)
268
+
269
+ # Re-open appenders after Spring has forked a process
270
+ Spring.after_fork { |_job| ::SemanticLogger.reopen } if defined?(Spring)
271
+ end
262
272
  end
263
273
  end
@@ -1,7 +1,9 @@
1
1
  # Log actual exceptions, not a string representation
2
2
  ActionController::Live
3
- module ActionController::Live
4
- def log_error(exception)
5
- logger.fatal(exception)
3
+ module ActionController
4
+ module Live
5
+ def log_error(exception)
6
+ logger.fatal(exception)
7
+ end
6
8
  end
7
9
  end
@@ -1,11 +1,13 @@
1
1
  # Log actual exceptions, not a string representation
2
2
  ActionDispatch::DebugExceptions
3
- class ActionDispatch::DebugExceptions
4
- private
5
- def log_error(request, wrapper)
6
- ActiveSupport::Deprecation.silence do
7
- ActionController::Base.logger.fatal(wrapper.exception)
3
+ module ActionDispatch
4
+ class DebugExceptions
5
+ private
6
+
7
+ def log_error(_request, wrapper)
8
+ ActiveSupport::Deprecation.silence do
9
+ ActionController::Base.logger.fatal(wrapper.exception)
10
+ end
8
11
  end
9
12
  end
10
13
  end
11
-
@@ -1,11 +1,14 @@
1
1
  # Log actual exceptions, not a string representation
2
2
  ActionView::StreamingTemplateRenderer
3
3
 
4
- class ActionView::StreamingTemplateRenderer
5
- class Body
6
- private
7
- def log_error(exception) #:nodoc:
8
- ActionView::Base.logger.fatal(exception)
4
+ module ActionView
5
+ class StreamingTemplateRenderer
6
+ class Body
7
+ private
8
+
9
+ def log_error(exception)
10
+ ActionView::Base.logger.fatal(exception)
11
+ end
9
12
  end
10
13
  end
11
14
  end
@@ -1,11 +1,14 @@
1
1
  # Patch ActiveJob logger
2
2
  require 'active_job/logging'
3
3
 
4
- module ActiveJob::Logging
5
- include SemanticLogger::Loggable
4
+ module ActiveJob
5
+ module Logging
6
+ include SemanticLogger::Loggable
6
7
 
7
- private
8
- def tag_logger(*tags, &block)
9
- logger.tagged(*tags, &block)
8
+ private
9
+
10
+ def tag_logger(*tags, &block)
11
+ logger.tagged(*tags, &block)
12
+ end
10
13
  end
11
14
  end
@@ -1,15 +1,18 @@
1
1
  # Patch ActiveModelSerializers logger
2
2
  require 'active_model_serializers/logging'
3
3
 
4
- module ActiveModelSerializers::Logging
5
- include SemanticLogger::Loggable
4
+ module ActiveModelSerializers
5
+ module Logging
6
+ include SemanticLogger::Loggable
6
7
 
7
- private
8
- def tag_logger(*tags, &block)
9
- logger.tagged(*tags, &block)
8
+ private
9
+
10
+ def tag_logger(*tags, &block)
11
+ logger.tagged(*tags, &block)
12
+ end
10
13
  end
11
- end
12
14
 
13
- class ActiveModelSerializers::SerializableResource
14
- include SemanticLogger::Loggable
15
+ class SerializableResource
16
+ include SemanticLogger::Loggable
17
+ end
15
18
  end
@@ -1,7 +1,7 @@
1
1
  # Patch the Rails::Server log_to_stdout so that it logs via SemanticLogger
2
2
  Rails::Server
3
- module Rails #:nodoc:
4
- class Server #:nodoc:
3
+ module Rails
4
+ class Server
5
5
  private
6
6
 
7
7
  def log_to_stdout
@@ -0,0 +1,103 @@
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
+
7
+ module RailsSemanticLogger
8
+ module Rack
9
+ class Logger < ActiveSupport::LogSubscriber
10
+ class << self
11
+ attr_reader :logger
12
+ attr_accessor :started_request_log_level
13
+ end
14
+
15
+ def initialize(app, taggers = nil)
16
+ @app = app
17
+ @taggers = taggers || []
18
+ end
19
+
20
+ def call(env)
21
+ request = ActionDispatch::Request.new(env)
22
+
23
+ # Check for named tags (Hash)
24
+ if @taggers && !@taggers.empty?
25
+ tags = @taggers.is_a?(Hash) ? compute_named_tags(request) : compute_tags(request)
26
+ logger.tagged(tags) { call_app(request, env) }
27
+ else
28
+ call_app(request, env)
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ @logger = SemanticLogger['Rack']
35
+ @started_request_log_level = :debug
36
+
37
+ def call_app(request, env)
38
+ instrumenter = ActiveSupport::Notifications.instrumenter
39
+ instrumenter.start 'request.action_dispatch', request: request
40
+
41
+ logger.send(self.class.started_request_log_level) { started_request_message(request) }
42
+
43
+ status, headers, body = @app.call(env)
44
+ body = ::Rack::BodyProxy.new(body) { finish(request) }
45
+ [status, headers, body]
46
+ rescue Exception
47
+ finish(request)
48
+ raise
49
+ end
50
+
51
+ def started_request_message(request)
52
+ {
53
+ message: 'Started',
54
+ payload: {
55
+ method: request.request_method,
56
+ path: request.filtered_path,
57
+ ip: request.ip
58
+ }
59
+ }
60
+ end
61
+
62
+ def compute_tags(request)
63
+ @taggers.collect do |tag|
64
+ case tag
65
+ when Proc
66
+ tag.call(request)
67
+ when Symbol
68
+ request.send(tag)
69
+ else
70
+ tag
71
+ end
72
+ end
73
+ end
74
+
75
+ # Leave out any named tags with a nil value
76
+ def compute_named_tags(request)
77
+ tagged = {}
78
+ @taggers.each_pair do |tag, value|
79
+ resolved =
80
+ case value
81
+ when Proc
82
+ value.call(request)
83
+ when Symbol
84
+ request.send(value)
85
+ else
86
+ value
87
+ end
88
+ tagged[tag] = resolved unless resolved.nil?
89
+ end
90
+ tagged
91
+ end
92
+
93
+ def finish(request)
94
+ instrumenter = ActiveSupport::Notifications.instrumenter
95
+ instrumenter.finish 'request.action_dispatch', request: request
96
+ end
97
+
98
+ def logger
99
+ self.class.logger
100
+ end
101
+ end
102
+ end
103
+ end