sapience 0.1.1 → 0.1.2
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 +4 -4
- data/.simplecov +6 -2
- data/.travis.yml +8 -25
- data/CODE_OF_CONDUCT.md +1 -1
- data/Gemfile +5 -5
- data/README.md +146 -15
- data/Rakefile +2 -1
- data/config/default.yml +29 -0
- data/dev-entrypoint.sh +10 -0
- data/docker-compose.yml +42 -0
- data/lib/sapience/appender/datadog.rb +100 -0
- data/lib/sapience/appender/file.rb +11 -22
- data/lib/sapience/appender/sentry.rb +61 -55
- data/lib/sapience/appender/wrapper.rb +5 -4
- data/lib/sapience/base.rb +21 -13
- data/lib/sapience/config_loader.rb +66 -0
- data/lib/sapience/configuration/grape.rb +9 -0
- data/lib/sapience/configuration.rb +32 -22
- data/lib/sapience/core_ext/hash.rb +25 -0
- data/lib/sapience/core_ext/thread.rb +2 -2
- data/lib/sapience/extensions/action_cable/tagged_logger_proxy.rb +6 -0
- data/lib/sapience/extensions/action_controller/live.rb +6 -0
- data/lib/sapience/extensions/action_controller/log_subscriber.rb +127 -0
- data/lib/sapience/extensions/action_controller/log_subscriber_processing.rb +24 -0
- data/lib/sapience/extensions/action_dispatch/debug_exceptions.rb +11 -0
- data/lib/sapience/extensions/action_view/log_subscriber.rb +9 -0
- data/lib/sapience/extensions/action_view/streaming_template_renderer.rb +11 -0
- data/lib/sapience/extensions/active_job/logging.rb +14 -0
- data/lib/sapience/extensions/active_model_serializers/logging.rb +14 -0
- data/lib/sapience/extensions/active_record/log_subscriber.rb +35 -0
- data/lib/sapience/extensions/grape/middleware/logging.rb +91 -0
- data/lib/sapience/extensions/grape/timings.rb +25 -0
- data/lib/sapience/extensions/rails/rack/logger.rb +11 -0
- data/lib/sapience/extensions/rails/rack/logger_info_as_debug.rb +24 -0
- data/lib/sapience/formatters/color.rb +3 -3
- data/lib/sapience/formatters/default.rb +1 -1
- data/lib/sapience/grape.rb +25 -0
- data/lib/sapience/log.rb +8 -6
- data/lib/sapience/loggable.rb +19 -17
- data/lib/sapience/logger.rb +46 -126
- data/lib/sapience/rails.rb +65 -8
- data/lib/sapience/sapience.rb +74 -73
- data/lib/sapience/subscriber.rb +5 -1
- data/lib/sapience/version.rb +1 -1
- data/lib/sapience.rb +4 -1
- data/sapience.gemspec +7 -4
- data/test_app/Gemfile +5 -1
- data/test_app/Rakefile +5 -1
- data/test_app/app/controllers/posts_controller.rb +12 -11
- data/test_app/config/application.rb +0 -1
- data/test_app/spec/controllers/posts_controller_spec.rb +1 -1
- data/test_app/spec/fixtures/sapience.yml +14 -0
- data/test_app/spec/helpers/posts_helper_spec.rb +1 -1
- data/test_app/spec/integration/sapience_spec.rb +14 -0
- data/test_app/spec/models/post_spec.rb +1 -1
- data/test_app/spec/models/user_spec.rb +1 -1
- data/test_app/spec/rails_helper.rb +15 -0
- data/test_app/spec/requests/posts_spec.rb +1 -1
- data/test_app/spec/routing/posts_routing_spec.rb +8 -10
- data/test_app/spec/spec_helper.rb +0 -44
- metadata +76 -11
- 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
|
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
|
-
|
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
|
-
|
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
|
-
|
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)
|
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
|
-
|
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(
|
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
|
-
|
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(
|
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
|
-
|
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
|
@@ -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
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
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
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
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
|
-
|
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
|
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
|
13
|
+
end
|
14
14
|
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,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
|