sapience 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.simplecov +6 -2
  3. data/.travis.yml +8 -25
  4. data/CODE_OF_CONDUCT.md +1 -1
  5. data/Gemfile +5 -5
  6. data/README.md +146 -15
  7. data/Rakefile +2 -1
  8. data/config/default.yml +29 -0
  9. data/dev-entrypoint.sh +10 -0
  10. data/docker-compose.yml +42 -0
  11. data/lib/sapience/appender/datadog.rb +100 -0
  12. data/lib/sapience/appender/file.rb +11 -22
  13. data/lib/sapience/appender/sentry.rb +61 -55
  14. data/lib/sapience/appender/wrapper.rb +5 -4
  15. data/lib/sapience/base.rb +21 -13
  16. data/lib/sapience/config_loader.rb +66 -0
  17. data/lib/sapience/configuration/grape.rb +9 -0
  18. data/lib/sapience/configuration.rb +32 -22
  19. data/lib/sapience/core_ext/hash.rb +25 -0
  20. data/lib/sapience/core_ext/thread.rb +2 -2
  21. data/lib/sapience/extensions/action_cable/tagged_logger_proxy.rb +6 -0
  22. data/lib/sapience/extensions/action_controller/live.rb +6 -0
  23. data/lib/sapience/extensions/action_controller/log_subscriber.rb +127 -0
  24. data/lib/sapience/extensions/action_controller/log_subscriber_processing.rb +24 -0
  25. data/lib/sapience/extensions/action_dispatch/debug_exceptions.rb +11 -0
  26. data/lib/sapience/extensions/action_view/log_subscriber.rb +9 -0
  27. data/lib/sapience/extensions/action_view/streaming_template_renderer.rb +11 -0
  28. data/lib/sapience/extensions/active_job/logging.rb +14 -0
  29. data/lib/sapience/extensions/active_model_serializers/logging.rb +14 -0
  30. data/lib/sapience/extensions/active_record/log_subscriber.rb +35 -0
  31. data/lib/sapience/extensions/grape/middleware/logging.rb +91 -0
  32. data/lib/sapience/extensions/grape/timings.rb +25 -0
  33. data/lib/sapience/extensions/rails/rack/logger.rb +11 -0
  34. data/lib/sapience/extensions/rails/rack/logger_info_as_debug.rb +24 -0
  35. data/lib/sapience/formatters/color.rb +3 -3
  36. data/lib/sapience/formatters/default.rb +1 -1
  37. data/lib/sapience/grape.rb +25 -0
  38. data/lib/sapience/log.rb +8 -6
  39. data/lib/sapience/loggable.rb +19 -17
  40. data/lib/sapience/logger.rb +46 -126
  41. data/lib/sapience/rails.rb +65 -8
  42. data/lib/sapience/sapience.rb +74 -73
  43. data/lib/sapience/subscriber.rb +5 -1
  44. data/lib/sapience/version.rb +1 -1
  45. data/lib/sapience.rb +4 -1
  46. data/sapience.gemspec +7 -4
  47. data/test_app/Gemfile +5 -1
  48. data/test_app/Rakefile +5 -1
  49. data/test_app/app/controllers/posts_controller.rb +12 -11
  50. data/test_app/config/application.rb +0 -1
  51. data/test_app/spec/controllers/posts_controller_spec.rb +1 -1
  52. data/test_app/spec/fixtures/sapience.yml +14 -0
  53. data/test_app/spec/helpers/posts_helper_spec.rb +1 -1
  54. data/test_app/spec/integration/sapience_spec.rb +14 -0
  55. data/test_app/spec/models/post_spec.rb +1 -1
  56. data/test_app/spec/models/user_spec.rb +1 -1
  57. data/test_app/spec/rails_helper.rb +15 -0
  58. data/test_app/spec/requests/posts_spec.rb +1 -1
  59. data/test_app/spec/routing/posts_routing_spec.rb +8 -10
  60. data/test_app/spec/spec_helper.rb +0 -44
  61. metadata +76 -11
  62. data/lib/sapience/appender/statsd.rb +0 -68
@@ -38,6 +38,7 @@ module Sapience
38
38
  # logger = Sapience['test']
39
39
  # logger.info('Hello World', some: :payload)
40
40
  #
41
+ # rubocop:disable LineLength
41
42
  def initialize(options, &block)
42
43
  # Backward compatibility
43
44
  options = { logger: options } unless options.is_a?(Hash)
@@ -45,20 +46,20 @@ module Sapience
45
46
  @logger = options.delete(:logger)
46
47
 
47
48
  # Check if the custom appender responds to all the log levels. For example Ruby ::Logger
48
- if does_not_implement = LEVELS[1..-1].find { |i| !@logger.respond_to?(i) }
49
- fail(ArgumentError, "Supplied logger does not implement:#{does_not_implement}. It must implement all of #{LEVELS[1..-1].inspect}")
49
+ if (does_not_implement = LEVELS[1..-1].find { |i| !@logger.respond_to?(i) })
50
+ fail ArgumentError, "Supplied logger does not implement:#{does_not_implement}. It must implement all of #{LEVELS[1..-1].inspect}"
50
51
  end
51
52
 
52
- fail "Sapience::Appender::Wrapper missing mandatory parameter :logger" unless @logger
53
+ fail ArgumentError, "Sapience::Appender::Wrapper missing mandatory parameter :logger" unless @logger
53
54
  super(options, &block)
54
55
  end
56
+ # rubocop:enable LineLength
55
57
 
56
58
  # Pass log calls to the underlying Rails, log4j or Ruby logger
57
59
  # trace entries are mapped to debug since :trace is not supported by the
58
60
  # Ruby or Rails Loggers
59
61
  def log(log)
60
62
  return false unless should_log?(log)
61
-
62
63
  @logger.send(log.level == :trace ? :debug : log.level, formatter.call(log, self))
63
64
  true
64
65
  end
data/lib/sapience/base.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  module Sapience
2
+ # rubocop:disable ClassLength
2
3
  class Base
3
4
  # Class name to be logged
4
5
  attr_accessor :name, :filter
@@ -176,7 +177,7 @@ module Sapience
176
177
 
177
178
  # Write log data to underlying data storage
178
179
  def log(_log_)
179
- raise NotImplementedError.new('Logging Appender must implement #log(log)')
180
+ fail NotImplementedError, "Logging Appender must implement #log(log)"
180
181
  end
181
182
 
182
183
  private
@@ -198,10 +199,11 @@ module Sapience
198
199
  # regular expression. All other messages will be ignored
199
200
  # Proc: Only include log messages where the supplied Proc returns true
200
201
  # The Proc must return true or false
201
- def initialize(klass, level = nil, filter = nil) # rubocop:disable AbcSize, PerceivedComplexity, CyclomaticComplexity
202
+ # rubocop:disable AbcSize, PerceivedComplexity, CyclomaticComplexity, LineLength
203
+ def initialize(klass, level = nil, filter = nil)
202
204
  # Support filtering all messages to this logger using a Regular Expression
203
205
  # or Proc
204
- raise ':filter must be a Regexp or Proc' unless filter.nil? || filter.is_a?(Regexp) || filter.is_a?(Proc)
206
+ fail ArgumentError, ":filter must be a Regexp or Proc" unless filter.nil? || filter.is_a?(Regexp) || filter.is_a?(Proc)
205
207
 
206
208
  @filter = filter.is_a?(Regexp) ? filter.freeze : filter
207
209
  @name = klass.is_a?(String) ? klass : klass.name
@@ -213,6 +215,7 @@ module Sapience
213
215
  self.level = level
214
216
  end
215
217
  end
218
+ # rubocop:enable AbcSize, PerceivedComplexity, CyclomaticComplexity, LineLength
216
219
 
217
220
  # Return the level index for fast comparisons
218
221
  # Returns the global default level index if the level has not been explicitly
@@ -226,7 +229,7 @@ module Sapience
226
229
  return true if @filter.nil?
227
230
 
228
231
  if @filter.is_a?(Regexp)
229
- (@filter =~ log.name) != nil
232
+ !(@filter =~ log.name).nil?
230
233
  elsif @filter.is_a?(Proc)
231
234
  @filter.call(log) == true
232
235
  end
@@ -239,7 +242,8 @@ module Sapience
239
242
  end
240
243
 
241
244
  # Log message at the specified level
242
- def log_internal(level, index, message = nil, payload = nil, exception = nil) # rubocop:disable AbcSize, PerceivedComplexity, CyclomaticComplexity
245
+ # rubocop:disable AbcSize, PerceivedComplexity, CyclomaticComplexity, LineLength
246
+ def log_internal(level, index, message = nil, payload = nil, exception = nil)
243
247
  # Exception being logged?
244
248
  if exception.nil? && payload.nil? && message.respond_to?(:backtrace) && message.respond_to?(:message)
245
249
  exception = message
@@ -281,7 +285,7 @@ module Sapience
281
285
  log.message = payload.delete(:message)
282
286
  log.metric = payload.delete(:metric)
283
287
  log.metric_amount = payload.delete(:metric_amount) || 1
284
- if duration = payload.delete(:duration)
288
+ if (duration = payload.delete(:duration))
285
289
  return false if duration <= min_duration
286
290
  log.duration = duration
287
291
  end
@@ -290,8 +294,9 @@ module Sapience
290
294
 
291
295
  self.log(log) if include_message?(log)
292
296
  end
297
+ # rubocop:enable AbcSize, PerceivedComplexity, CyclomaticComplexity, LineLength
293
298
 
294
- SELF_PATTERN = File.join('lib', 'sapience')
299
+ SELF_PATTERN = File.join("lib", "sapience")
295
300
 
296
301
  # Extract the callers backtrace leaving out Sapience
297
302
  def extract_backtrace
@@ -303,13 +308,14 @@ module Sapience
303
308
  end
304
309
 
305
310
  # Measure the supplied block and log the message
306
- def measure_internal(level, index, message, params) # rubocop:disable AbcSize, PerceivedComplexity, CyclomaticComplexity
311
+ # rubocop:disable AbcSize, PerceivedComplexity, CyclomaticComplexity, LineLength
312
+ def measure_internal(level, index, message, params)
307
313
  start = Time.now
308
314
  exception = nil
309
315
  begin
310
316
  if block_given?
311
317
  result =
312
- if silence_level = params[:silence]
318
+ if (silence_level = params[:silence])
313
319
  # In case someone accidentally sets `silence: true` instead of `silence: :error`
314
320
  silence_level = :error if silence_level == true
315
321
  silence(silence_level) { yield(params) }
@@ -333,7 +339,7 @@ module Sapience
333
339
  if block_given?
334
340
  1000.0 * (end_time - start)
335
341
  else
336
- params[:duration] || fail('Mandatory block missing when :duration option is not supplied')
342
+ params[:duration] || fail("Mandatory block missing when :duration option is not supplied")
337
343
  end
338
344
 
339
345
  # Add scoped payload
@@ -364,18 +370,20 @@ module Sapience
364
370
  logged_exception = nil
365
371
  backtrace = exception.backtrace
366
372
  end
367
- log = Log.new(level, Thread.current.name, name, message, payload, end_time, duration, tags, index, logged_exception, metric, backtrace)
373
+ log = Log.new(level, Thread.current.name, name, message, payload, end_time, duration, tags, index, logged_exception, metric, backtrace) # rubocop:disable LineLength
368
374
  self.log(log) if include_message?(log)
369
- raise exception
375
+ fail exception
370
376
  elsif duration >= min_duration
371
377
  # Only log if the block took longer than 'min_duration' to complete
372
378
  # Add caller stack trace
373
379
  backtrace = extract_backtrace if index >= Sapience.config.backtrace_level_index
374
380
 
375
- log = Log.new(level, Thread.current.name, name, message, payload, end_time, duration, tags, index, nil, metric, backtrace)
381
+ log = Log.new(level, Thread.current.name, name, message, payload, end_time, duration, tags, index, nil, metric, backtrace) # rubocop:disable LineLength
376
382
  self.log(log) if include_message?(log)
377
383
  end
378
384
  end
379
385
  end
386
+ # rubocop:enable AbcSize, PerceivedComplexity, CyclomaticComplexity, LineLength
380
387
  end
388
+ # rubocop:enable ClassLength
381
389
  end
@@ -0,0 +1,66 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ require "yaml"
5
+ require "pathname"
6
+ require "erb"
7
+
8
+ module Sapience
9
+ # This class represents the configuration of the RuboCop application
10
+ # and all its cops. A Config is associated with a YAML configuration
11
+ # file from which it was read. Several different Configs can be used
12
+ # during a run of the sapience program, if files in several
13
+ # directories are inspected.
14
+ module ConfigLoader
15
+ SAPIENCE_FILE = "sapience.yml".freeze
16
+ SAPIENCE_HOME = File.realpath(File.join(File.dirname(__FILE__), "..", ".."))
17
+ DEFAULT_FILE = File.join(SAPIENCE_HOME, "config", "default.yml")
18
+
19
+ def self.load_from_file
20
+ file_path = config_file_path
21
+ path = File.absolute_path(file_path)
22
+ load_yaml_configuration(path)
23
+ end
24
+
25
+ class << self
26
+ private
27
+
28
+ def config_file_path
29
+ return application_config_file if File.exist?(application_config_file)
30
+
31
+ DEFAULT_FILE
32
+ end
33
+
34
+ def application_config_file
35
+ File.join(Rack::Directory.new("").root, "config", SAPIENCE_FILE)
36
+ end
37
+
38
+ def load_yaml_configuration(absolute_path)
39
+ text = IO.read(absolute_path, encoding: "UTF-8")
40
+ erb = ERB.new(text)
41
+ yaml_code = erb.result
42
+
43
+ hash = yaml_safe_load(yaml_code, absolute_path) || {}
44
+
45
+ unless hash.is_a?(Hash)
46
+ fail(TypeError, "Malformed configuration in #{absolute_path}")
47
+ end
48
+
49
+ hash
50
+ end
51
+
52
+ def yaml_safe_load(yaml_code, filename)
53
+ if YAML.respond_to?(:safe_load) # Ruby 2.1+
54
+ if defined?(SafeYAML) && SafeYAML.respond_to?(:load)
55
+ SafeYAML.load(yaml_code, filename,
56
+ whitelisted_tags: %w(!ruby/regexp))
57
+ else
58
+ YAML.safe_load(yaml_code, [Regexp], [], false, filename)
59
+ end
60
+ else
61
+ YAML.load(yaml_code, filename)
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,9 @@
1
+ module Sapience
2
+ class Configuration
3
+ class Grape
4
+ def self.configure
5
+ Grape::API.send(:include, Sapience::Loggable)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -1,19 +1,29 @@
1
1
  require "ostruct"
2
2
 
3
3
  module Sapience
4
+ # rubocop:disable ClassVars
4
5
  class Configuration
5
6
  attr_reader :default_level, :backtrace_level, :backtrace_level_index
6
7
  attr_writer :host
7
8
  attr_accessor :application, :ap_options, :appenders
8
9
 
9
- def initialize
10
- # Initial default Level for all new instances of Sapience::Logger
11
- self.default_level = :info
12
- self.backtrace_level = :info
13
- self.application = "Sapience"
14
- self.host = nil
15
- self.ap_options = { multiline: false }
16
- self.appenders = [ { file: {io: STDOUT, formatter: :color } } ]
10
+ DEFAULT = {
11
+ log_level: :info,
12
+ application: "Sapience",
13
+ host: nil,
14
+ ap_options: { multiline: false },
15
+ appenders: [{ file: { io: STDOUT, formatter: :color } }],
16
+ }.freeze
17
+
18
+ # Initial default Level for all new instances of Sapience::Logger
19
+ def initialize(options = {}) # rubocop:disable AbcSize
20
+ @options = DEFAULT.merge(options.deep_symbolize_keys!)
21
+ self.default_level = @options[:log_level].to_sym
22
+ self.backtrace_level = @options[:log_level].to_sym
23
+ self.application = @options[:application]
24
+ self.host = @options[:host]
25
+ self.ap_options = @options[:ap_options]
26
+ self.appenders = @options[:appenders]
17
27
  end
18
28
 
19
29
  # Sets the global default log level
@@ -34,22 +44,22 @@ module Sapience
34
44
  return if level.nil?
35
45
 
36
46
  index =
37
- if level.is_a?(Symbol)
38
- LEVELS.index(level)
39
- elsif level.is_a?(String)
40
- level = level.downcase.to_sym
41
- LEVELS.index(level)
42
- elsif level.is_a?(Integer) && defined?(::Logger::Severity)
43
- # Mapping of Rails and Ruby Logger levels to Sapience levels
44
- @@map_levels ||= begin
45
- levels = []
46
- ::Logger::Severity.constants.each do |constant|
47
- levels[::Logger::Severity.const_get(constant)] = LEVELS.find_index(constant.downcase.to_sym) || LEVELS.find_index(:error)
48
- end
49
- levels
47
+ if level.is_a?(Symbol)
48
+ LEVELS.index(level)
49
+ elsif level.is_a?(String)
50
+ level = level.downcase.to_sym
51
+ LEVELS.index(level)
52
+ elsif level.is_a?(Integer) && defined?(::Logger::Severity)
53
+ # Mapping of Rails and Ruby Logger levels to Sapience levels
54
+ @@map_levels ||= begin
55
+ levels = []
56
+ ::Logger::Severity.constants.each do |constant|
57
+ levels[::Logger::Severity.const_get(constant)] = LEVELS.find_index(constant.downcase.to_sym) || LEVELS.find_index(:error) # rubocop:disable LineLength
50
58
  end
51
- @@map_levels[level]
59
+ levels
52
60
  end
61
+ @@map_levels[level]
62
+ end
53
63
  fail "Invalid level:#{level.inspect} being requested. Must be one of #{LEVELS.inspect}" unless index
54
64
  index
55
65
  end
@@ -0,0 +1,25 @@
1
+ class Hash
2
+ # Returns a Hash with all keys symbolized
3
+ def deep_symbolize_keys!
4
+ deep_transform_keys! { |key| key.to_sym rescue key } # rubocop:disable RescueModifier
5
+ end
6
+
7
+ def deep_transform_keys!(&block)
8
+ _deep_transform_keys_in_object!(self, &block)
9
+ end
10
+
11
+ def _deep_transform_keys_in_object!(object, &block)
12
+ case object
13
+ when Hash
14
+ object.keys.each do |key|
15
+ value = object.delete(key)
16
+ object[yield(key)] = _deep_transform_keys_in_object!(value, &block)
17
+ end
18
+ object
19
+ when Array
20
+ object.map! { |e| _deep_transform_keys_in_object!(e, &block) }
21
+ else
22
+ object
23
+ end
24
+ end
25
+ end
@@ -5,10 +5,10 @@ class Thread
5
5
  # String representation of this thread's object_id
6
6
  def name
7
7
  @name ||= object_id.to_s
8
- end unless defined?(:name)
8
+ end
9
9
 
10
10
  # Set the name of this thread
11
11
  def name=(name)
12
12
  @name = name.to_s
13
- end unless defined?(:name=)
13
+ end
14
14
  end
@@ -0,0 +1,6 @@
1
+ class ActionCable::Connection::TaggedLoggerProxy # rubocop:disable ClassAndModuleChildren
2
+ def tag(logger, &block)
3
+ current_tags = tags - logger.tags
4
+ logger.tagged(*current_tags, &block)
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ # Log actual exceptions, not a string representation
2
+ module ActionController::Live # rubocop:disable ClassAndModuleChildren
3
+ def log_error(exception)
4
+ logger.fatal(exception)
5
+ end
6
+ end
@@ -0,0 +1,127 @@
1
+ require "action_controller/log_subscriber"
2
+
3
+ class ActionController::LogSubscriber # rubocop:disable ClassAndModuleChildren
4
+ # Log as debug to hide Processing messages in production
5
+ def start_processing(event)
6
+ controller_logger(event).debug { "Processing ##{event.payload[:action]}" }
7
+ end
8
+
9
+ def process_action(event) # rubocop:disable AbcSize, CyclomaticComplexity, PerceivedComplexity
10
+ controller_logger(event).info do
11
+ payload = event.payload.dup
12
+ payload[:params].except!(*INTERNAL_PARAMS)
13
+ payload.delete(:params) if payload[:params].empty?
14
+
15
+ format = payload[:format]
16
+ payload[:format] = format.to_s.upcase if format.is_a?(Symbol)
17
+
18
+ payload[:path] = extract_path(payload[:path]) if payload.key?(:path)
19
+
20
+ exception = payload.delete(:exception)
21
+ if payload[:status].nil? && exception.present?
22
+ exception_class_name = exception.first
23
+ payload[:status] = ActionDispatch::ExceptionWrapper.status_code_for_exception(exception_class_name)
24
+ end
25
+
26
+ # Rounds off the runtimes. For example, :view_runtime, :mongo_runtime, etc.
27
+ payload.keys.each do |key|
28
+ payload[key] = payload[key].to_f.round(2) if key.to_s.match(/(.*)_runtime/)
29
+ end
30
+
31
+ payload[:message] = "Completed ##{payload[:action]}"
32
+ payload[:status_message] = Rack::Utils::HTTP_STATUS_CODES[payload[:status]] if payload[:status].present?
33
+ payload[:duration] = event.duration
34
+ # Causes excessive log output with Rails 5 RC1
35
+ payload.delete(:headers)
36
+ payload
37
+ end
38
+ end
39
+
40
+ def halted_callback(event)
41
+ controller_logger(event).info do
42
+ "Filter chain halted as #{event.payload[:filter].inspect} rendered or redirected"
43
+ end
44
+ end
45
+
46
+ def send_file(event)
47
+ controller_logger(event).info("Sent file") { { path: event.payload[:path], duration: event.duration } }
48
+ end
49
+
50
+ def redirect_to(event)
51
+ controller_logger(event).info("Redirected to") { { location: event.payload[:location] } }
52
+ end
53
+
54
+ def send_data(event)
55
+ controller_logger(event).info("Sent data") { { file_name: event.payload[:filename], duration: event.duration } }
56
+ end
57
+
58
+ def unpermitted_parameters(event)
59
+ controller_logger(event).debug do
60
+ unpermitted_keys = event.payload[:keys]
61
+ "Unpermitted parameter#{"s" if unpermitted_keys.size > 1}: #{unpermitted_keys.join(", ")}"
62
+ end
63
+ end
64
+
65
+ private
66
+
67
+ # Returns the logger for the supplied event.
68
+ # Returns ActionController::Base.logger if no controller is present
69
+ def controller_logger(event)
70
+ if (controller = event.payload[:controller])
71
+ begin
72
+ controller.constantize.logger
73
+ rescue NameError
74
+ ActionController::Base.logger
75
+ end
76
+ else
77
+ ActionController::Base.logger
78
+ end
79
+ end
80
+
81
+ def extract_path(path)
82
+ index = path.index("?")
83
+ index ? path[0, index] : path
84
+ end
85
+
86
+ def write_fragment(event)
87
+ controller_logger(event).info do
88
+ key_or_path = event.payload[:key] || event.payload[:path]
89
+ { message: "Write fragment #{key_or_path}", duration: event.duration }
90
+ end
91
+ end
92
+
93
+ def read_fragment(event)
94
+ controller_logger(event).info do
95
+ key_or_path = event.payload[:key] || event.payload[:path]
96
+ { message: "Read fragment #{key_or_path}", duration: event.duration }
97
+ end
98
+ end
99
+
100
+ def exist_fragment(event)
101
+ controller_logger(event).info do
102
+ key_or_path = event.payload[:key] || event.payload[:path]
103
+ { message: "Exist fragment #{key_or_path}", duration: event.duration }
104
+ end
105
+ end
106
+
107
+ def expire_fragment(event)
108
+ controller_logger(event).info do
109
+ key_or_path = event.payload[:key] || event.payload[:path]
110
+ { message: "Expire fragment #{key_or_path}", duration: event.duration }
111
+ end
112
+ end
113
+
114
+ def expire_page(event)
115
+ controller_logger(event).info do
116
+ key_or_path = event.payload[:key] || event.payload[:path]
117
+ { message: "Expire page #{key_or_path}", duration: event.duration }
118
+ end
119
+ end
120
+
121
+ def write_page(event)
122
+ controller_logger(event).info do
123
+ key_or_path = event.payload[:key] || event.payload[:path]
124
+ { message: "Write page #{key_or_path}", duration: event.duration }
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,24 @@
1
+ require "action_controller/log_subscriber"
2
+
3
+ class ActionController::LogSubscriber # rubocop:disable ClassAndModuleChildren
4
+ # Log as info to show Processing messages in production
5
+ def start_processing(event)
6
+ controller_logger(event).info { "Processing ##{event.payload[:action]}" }
7
+ end
8
+
9
+ private
10
+
11
+ # Returns the logger for the supplied event.
12
+ # Returns ActionController::Base.logger if no controller is present
13
+ def controller_logger(event)
14
+ if (controller = event.payload[:controller])
15
+ begin
16
+ controller.constantize.logger
17
+ rescue NameError
18
+ ActionController::Base.logger
19
+ end
20
+ else
21
+ ActionController::Base.logger
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,11 @@
1
+ # Log actual exceptions, not a string representation
2
+
3
+ class ActionDispatch::DebugExceptions # rubocop:disable ClassAndModuleChildren
4
+ private
5
+
6
+ def log_error(_request, wrapper)
7
+ ActiveSupport::Deprecation.silence do
8
+ ActionController::Base.logger.fatal(wrapper.exception)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ class ActionView::LogSubscriber # rubocop:disable ClassAndModuleChildren
2
+ def info(message = nil, &block)
3
+ debug(message, &block)
4
+ end
5
+
6
+ def info?
7
+ debug?
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ # Log actual exceptions, not a string representation
2
+
3
+ class ActionView::StreamingTemplateRenderer # rubocop:disable ClassAndModuleChildren
4
+ class Body
5
+ private
6
+
7
+ def log_error(exception) #:nodoc:
8
+ ActionView::Base.logger.fatal(exception)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ # Patch ActiveJob logger
2
+ require "active_job/logging"
3
+
4
+ module ActiveJob::Logging # rubocop:disable ClassAndModuleChildren
5
+ include Sapience::Loggable
6
+
7
+ private
8
+
9
+ alias_method :tag_logger_old, :tag_logger
10
+
11
+ def tag_logger(*tags, &block)
12
+ logger.tagged(*tags, &block)
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ # Patch ActiveModelSerializers logger
2
+ require "active_model_serializers/logging"
3
+
4
+ module ActiveModelSerializers::Logging # rubocop:disable ClassAndModuleChildren
5
+ include Sapience::Loggable
6
+
7
+ private
8
+
9
+ alias_method :tag_logger_old, :tag_logger
10
+
11
+ def tag_logger(*tags, &block)
12
+ logger.tagged(*tags, &block)
13
+ end
14
+ end
@@ -0,0 +1,35 @@
1
+ ActiveRecord::LogSubscriber # rubocop:disable Lint/Void
2
+
3
+ class ActiveRecord::LogSubscriber # rubocop:disable ClassAndModuleChildren
4
+ def sql(event) # rubocop:disable AbcSize
5
+ self.class.runtime += event.duration
6
+
7
+ return unless logger.debug?
8
+
9
+ payload = event.payload
10
+ name = payload[:name]
11
+ return if IGNORE_PAYLOAD_NAMES.include?(name)
12
+
13
+ log = {
14
+ message: name,
15
+ sql: payload[:sql],
16
+ duration: event.duration,
17
+ }
18
+ unless (payload[:binds] || []).empty?
19
+ log[:binds] = binds = {}
20
+ # Changed with Rails 5
21
+ if Rails.version.to_i >= 5
22
+ payload[:binds].each do |attr|
23
+ attr_name, value = render_bind(attr)
24
+ binds[attr_name] = value
25
+ end
26
+ else
27
+ payload[:binds].each do |col, v|
28
+ attr_name, value = render_bind(col, v)
29
+ binds[attr_name] = value
30
+ end
31
+ end
32
+ end
33
+ debug(log)
34
+ end
35
+ end