debug_logging 3.1.1 → 3.1.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +8 -0
- data/.rubocop_todo.yml +97 -63
- data/.travis.yml +2 -2
- data/README.md +91 -30
- data/debug_logging.gemspec +6 -3
- data/lib/debug_logging.rb +159 -106
- data/lib/debug_logging/argument_printer.rb +89 -26
- data/lib/debug_logging/class_logger.rb +48 -61
- data/lib/debug_logging/class_notifier.rb +39 -41
- data/lib/debug_logging/configuration.rb +4 -27
- data/lib/debug_logging/constants.rb +33 -0
- data/lib/debug_logging/errors.rb +7 -0
- data/lib/debug_logging/finalize.rb +20 -0
- data/lib/debug_logging/hooks.rb +82 -0
- data/lib/debug_logging/instance_logger.rb +3 -1
- data/lib/debug_logging/instance_logger_modulizer.rb +27 -39
- data/lib/debug_logging/instance_notifier.rb +6 -2
- data/lib/debug_logging/instance_notifier_modulizer.rb +33 -44
- data/lib/debug_logging/util.rb +75 -0
- data/lib/debug_logging/version.rb +1 -1
- metadata +56 -8
@@ -3,83 +3,70 @@
|
|
3
3
|
module DebugLogging
|
4
4
|
module ClassLogger
|
5
5
|
def logged(*methods_to_log)
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
end
|
18
|
-
methods_to_log.each do |method_to_log|
|
19
|
-
# method name must be a symbol
|
20
|
-
method_to_log = method_to_log.to_sym
|
6
|
+
methods_to_log, payload, config_opts = DebugLogging::Util.extract_payload_and_config(
|
7
|
+
method_names: methods_to_log,
|
8
|
+
payload: nil,
|
9
|
+
config: nil
|
10
|
+
)
|
11
|
+
Array(methods_to_log).each do |method_to_log|
|
12
|
+
method_to_log, method_payload, method_config_opts = DebugLogging::Util.extract_payload_and_config(
|
13
|
+
method_names: method_to_log,
|
14
|
+
payload: payload,
|
15
|
+
config: config_opts
|
16
|
+
)
|
21
17
|
original_method = method(method_to_log)
|
22
18
|
(class << self; self; end).class_eval do
|
23
19
|
define_method(method_to_log) do |*args, &block|
|
24
|
-
config_proxy =
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
else
|
31
|
-
DebugLogging::Configuration.new(**debug_config.to_hash.merge(config_opts))
|
32
|
-
end
|
33
|
-
proxy.register(method_to_log)
|
34
|
-
instance_variable_set(DebugLogging::Configuration.config_pointer('kl', method_to_log),
|
35
|
-
proxy)
|
36
|
-
proxy
|
37
|
-
end
|
20
|
+
config_proxy = DebugLogging::Util.config_proxy_finder(
|
21
|
+
scope: self,
|
22
|
+
config_opts: method_config_opts,
|
23
|
+
method_name: method_to_log,
|
24
|
+
proxy_ref: 'kl'
|
25
|
+
)
|
38
26
|
method_return_value = nil
|
39
27
|
log_prefix = nil
|
40
28
|
invocation_id = nil
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
29
|
+
begin
|
30
|
+
config_proxy.log do
|
31
|
+
paydirt = DebugLogging::Util.payload_instance_vaiable_hydration(scope: self, payload: method_payload)
|
32
|
+
log_prefix = debug_invocation_to_s(klass: to_s, separator: '.', method_to_log: method_to_log,
|
33
|
+
config_proxy: config_proxy)
|
34
|
+
invocation_id = debug_invocation_id_to_s(args: args, config_proxy: config_proxy)
|
35
|
+
signature = debug_signature_to_s(args: args, config_proxy: config_proxy)
|
36
|
+
paymud = debug_payload_to_s(payload: paydirt, config_proxy: config_proxy)
|
37
|
+
"#{log_prefix}#{signature}#{invocation_id} debug: #{paymud}"
|
38
|
+
end
|
39
|
+
if config_proxy.benchmarkable_for?(:debug_class_benchmarks)
|
40
|
+
tms = Benchmark.measure do
|
41
|
+
method_return_value = if args.size == 1 && (harsh = args[0]) && harsh.is_a?(Hash)
|
42
|
+
original_method.call(**harsh, &block)
|
43
|
+
else
|
44
|
+
original_method.call(*args, &block)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
config_proxy.log do
|
48
|
+
"#{log_prefix} #{debug_benchmark_to_s(tms: tms)}#{invocation_id}"
|
48
49
|
end
|
49
50
|
else
|
50
|
-
paydirt.merge!(payload)
|
51
|
-
end
|
52
|
-
log_prefix = debug_invocation_to_s(klass: to_s, separator: '.', method_to_log: method_to_log,
|
53
|
-
config_proxy: config_proxy)
|
54
|
-
invocation_id = debug_invocation_id_to_s(args: args, config_proxy: config_proxy)
|
55
|
-
signature = debug_signature_to_s(args: args, config_proxy: config_proxy)
|
56
|
-
paymud = debug_payload_to_s(payload: paydirt, config_proxy: config_proxy)
|
57
|
-
"#{log_prefix}#{signature}#{invocation_id} debug: #{paymud}"
|
58
|
-
end
|
59
|
-
if config_proxy.benchmarkable_for?(:debug_class_benchmarks)
|
60
|
-
tms = Benchmark.measure do
|
61
51
|
method_return_value = if args.size == 1 && (harsh = args[0]) && harsh.is_a?(Hash)
|
62
52
|
original_method.call(**harsh, &block)
|
63
53
|
else
|
64
54
|
original_method.call(*args, &block)
|
65
55
|
end
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
else
|
71
|
-
method_return_value = if args.size == 1 && (harsh = args[0]) && harsh.is_a?(Hash)
|
72
|
-
original_method.call(**harsh, &block)
|
73
|
-
else
|
74
|
-
original_method.call(*args, &block)
|
75
|
-
end
|
76
|
-
if config_proxy.exit_scope_markable? && invocation_id && !invocation_id.empty?
|
77
|
-
config_proxy.log do
|
78
|
-
"#{log_prefix} completed#{invocation_id}"
|
56
|
+
if config_proxy.exit_scope_markable? && invocation_id && !invocation_id.empty?
|
57
|
+
config_proxy.log do
|
58
|
+
"#{log_prefix} completed#{invocation_id}"
|
59
|
+
end
|
79
60
|
end
|
80
61
|
end
|
62
|
+
method_return_value
|
63
|
+
rescue => error
|
64
|
+
if config_proxy.error_handler_proc
|
65
|
+
config_proxy.error_handler_proc.call(config_proxy, error, self)
|
66
|
+
else
|
67
|
+
raise error
|
68
|
+
end
|
81
69
|
end
|
82
|
-
method_return_value
|
83
70
|
end
|
84
71
|
end
|
85
72
|
end
|
@@ -3,57 +3,55 @@
|
|
3
3
|
module DebugLogging
|
4
4
|
module ClassNotifier
|
5
5
|
def notifies(*methods_to_notify)
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
end
|
18
|
-
methods_to_notify.each do |method_to_notify|
|
19
|
-
# method name must be a symbol
|
20
|
-
method_to_notify = method_to_notify.to_sym
|
6
|
+
methods_to_notify, payload, config_opts = DebugLogging::Util.extract_payload_and_config(
|
7
|
+
method_names: methods_to_notify,
|
8
|
+
payload: nil,
|
9
|
+
config: nil
|
10
|
+
)
|
11
|
+
Array(methods_to_notify).each do |method_to_notify|
|
12
|
+
method_to_notify, method_payload, method_config_opts = DebugLogging::Util.extract_payload_and_config(
|
13
|
+
method_names: method_to_notify,
|
14
|
+
payload: payload,
|
15
|
+
config: config_opts
|
16
|
+
)
|
21
17
|
original_method = method(method_to_notify)
|
22
18
|
(class << self; self; end).class_eval do
|
23
19
|
define_method(method_to_notify) do |*args, &block|
|
24
|
-
config_proxy =
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
proxy.log do
|
40
|
-
DebugLogging::LogSubscriber.log_event(ActiveSupport::Notifications::Event.new(*debug_args))
|
41
|
-
end
|
42
|
-
end
|
43
|
-
proxy
|
44
|
-
end
|
20
|
+
config_proxy = DebugLogging::Util.config_proxy_finder(
|
21
|
+
scope: self,
|
22
|
+
config_opts: method_config_opts,
|
23
|
+
method_name: method_to_notify,
|
24
|
+
proxy_ref: 'kn'
|
25
|
+
) do |proxy|
|
26
|
+
ActiveSupport::Notifications.subscribe(
|
27
|
+
DebugLogging::ArgumentPrinter.debug_event_name_to_s(method_to_notify: method_to_notify)
|
28
|
+
) do |*debug_args|
|
29
|
+
proxy.log do
|
30
|
+
DebugLogging::LogSubscriber.log_event(ActiveSupport::Notifications::Event.new(*debug_args))
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
paydirt = DebugLogging::Util.payload_instance_vaiable_hydration(scope: self, payload: method_payload)
|
45
35
|
ActiveSupport::Notifications.instrument(
|
46
36
|
DebugLogging::ArgumentPrinter.debug_event_name_to_s(method_to_notify: method_to_notify),
|
47
37
|
{
|
48
38
|
debug_args: args,
|
49
39
|
config_proxy: config_proxy,
|
50
|
-
**
|
40
|
+
**paydirt
|
51
41
|
}
|
52
42
|
) do
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
43
|
+
begin
|
44
|
+
if args.size == 1 && (harsh = args[0]) && harsh.is_a?(Hash)
|
45
|
+
original_method.call(**harsh, &block)
|
46
|
+
else
|
47
|
+
original_method.call(*args, &block)
|
48
|
+
end
|
49
|
+
rescue => error
|
50
|
+
if config_proxy.error_handler_proc
|
51
|
+
config_proxy.error_handler_proc.call(config_proxy, error, self)
|
52
|
+
else
|
53
|
+
raise error
|
54
|
+
end
|
57
55
|
end
|
58
56
|
end
|
59
57
|
end
|
@@ -2,31 +2,7 @@
|
|
2
2
|
|
3
3
|
module DebugLogging
|
4
4
|
class Configuration
|
5
|
-
|
6
|
-
CONFIG_ATTRS_DEFAULTS = {
|
7
|
-
enabled: true,
|
8
|
-
logger: Logger.new($stdout),
|
9
|
-
log_level: :debug,
|
10
|
-
multiple_last_hashes: false,
|
11
|
-
last_hash_to_s_proc: nil,
|
12
|
-
last_hash_max_length: 1_000,
|
13
|
-
args_max_length: 1_000,
|
14
|
-
colorized_chain_for_method: false,
|
15
|
-
colorized_chain_for_class: false,
|
16
|
-
add_invocation_id: true,
|
17
|
-
ellipsis: DEFAULT_ELLIPSIS,
|
18
|
-
mark_scope_exit: false,
|
19
|
-
add_payload: true
|
20
|
-
}.freeze
|
21
|
-
CONFIG_ATTRS = CONFIG_ATTRS_DEFAULTS.keys
|
22
|
-
CONFIG_READERS_DEFAULTS = {
|
23
|
-
instance_benchmarks: false,
|
24
|
-
class_benchmarks: false,
|
25
|
-
active_support_notifications: false
|
26
|
-
}.freeze
|
27
|
-
CONFIG_READERS = CONFIG_READERS_DEFAULTS.keys
|
28
|
-
CONFIG_KEYS = CONFIG_ATTRS + CONFIG_READERS
|
29
|
-
|
5
|
+
include Constants
|
30
6
|
# For reference, log levels as integers mapped to symbols:
|
31
7
|
# LEVELS = { 0 => :debug, 1 => :info, 2 => :warn, 3 => :error, 4 => :fatal, 5 => :unknown }
|
32
8
|
attr_accessor(*CONFIG_ATTRS)
|
@@ -42,6 +18,7 @@ module DebugLogging
|
|
42
18
|
# log_level: :debug # at what level do the messages created by this gem sent at?
|
43
19
|
# last_hash_to_s_proc: nil # e.g. ->(hash) { "keys: #{hash.keys}" }
|
44
20
|
# last_hash_max_length: 1_000
|
21
|
+
# args_to_s_proc: nil # e.g. ->(record) { "record id: #{record.id}" }
|
45
22
|
# args_max_length: 1_000
|
46
23
|
# instance_benchmarks: false
|
47
24
|
# class_benchmarks: false
|
@@ -51,7 +28,7 @@ module DebugLogging
|
|
51
28
|
# )
|
52
29
|
#
|
53
30
|
CONFIG_KEYS.each do |key|
|
54
|
-
|
31
|
+
alias_method :"debug_#{key}", :"#{key}"
|
55
32
|
end
|
56
33
|
|
57
34
|
class << self
|
@@ -76,7 +53,7 @@ module DebugLogging
|
|
76
53
|
return unless enabled
|
77
54
|
return unless logger
|
78
55
|
|
79
|
-
if
|
56
|
+
if block
|
80
57
|
logger.send(log_level, &block)
|
81
58
|
else
|
82
59
|
logger.send(log_level, message)
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DebugLogging
|
4
|
+
module Constants
|
5
|
+
DEFAULT_ELLIPSIS = ' ✂️ …'
|
6
|
+
CONFIG_ATTRS_DEFAULTS = {
|
7
|
+
enabled: true,
|
8
|
+
logger: Logger.new($stdout),
|
9
|
+
log_level: :debug,
|
10
|
+
multiple_last_hashes: false,
|
11
|
+
last_hash_to_s_proc: nil,
|
12
|
+
last_hash_max_length: 1_000,
|
13
|
+
args_to_s_proc: nil,
|
14
|
+
args_max_length: 1_000,
|
15
|
+
colorized_chain_for_method: false,
|
16
|
+
colorized_chain_for_class: false,
|
17
|
+
add_invocation_id: true,
|
18
|
+
ellipsis: DEFAULT_ELLIPSIS,
|
19
|
+
mark_scope_exit: false,
|
20
|
+
add_payload: true, # Can also be a proc returning a string, which will be called when printing the payload
|
21
|
+
payload_max_length: 1_000,
|
22
|
+
error_handler_proc: nil
|
23
|
+
}.freeze
|
24
|
+
CONFIG_ATTRS = CONFIG_ATTRS_DEFAULTS.keys
|
25
|
+
CONFIG_READERS_DEFAULTS = {
|
26
|
+
instance_benchmarks: false,
|
27
|
+
class_benchmarks: false,
|
28
|
+
active_support_notifications: false
|
29
|
+
}.freeze
|
30
|
+
CONFIG_READERS = CONFIG_READERS_DEFAULTS.keys
|
31
|
+
CONFIG_KEYS = CONFIG_ATTRS + CONFIG_READERS
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# From: https://stackoverflow.com/a/34559282
|
4
|
+
# License: https://creativecommons.org/licenses/by-sa/4.0/
|
5
|
+
module DebugLogging
|
6
|
+
module Finalize
|
7
|
+
def self.extended(obj)
|
8
|
+
TracePoint.trace(:end) do |t|
|
9
|
+
if obj == t.self
|
10
|
+
if obj.respond_to?(:debug_finalize)
|
11
|
+
obj.debug_finalize
|
12
|
+
else
|
13
|
+
warn "#{obj} does not define a debug_finalize"
|
14
|
+
end
|
15
|
+
t.disable
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'debug_logging/errors'
|
2
|
+
require 'timeout'
|
3
|
+
|
4
|
+
module DebugLogging
|
5
|
+
module Hooks
|
6
|
+
def self.included(mod)
|
7
|
+
mod.extend(ClassMethods)
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.extend(mod)
|
11
|
+
mod.extend(ClassMethods)
|
12
|
+
end
|
13
|
+
|
14
|
+
module ClassMethods
|
15
|
+
def debug_time_box(time, *names, &blk)
|
16
|
+
names.each do |name|
|
17
|
+
meth = instance_method(name)
|
18
|
+
define_method(name) do |*args, &block|
|
19
|
+
begin
|
20
|
+
Timeout.timeout(time) do
|
21
|
+
meth.bind(self).call(*args, &block)
|
22
|
+
end
|
23
|
+
rescue Timeout::Error
|
24
|
+
error_args = [TimeoutError, 'execution expired', caller]
|
25
|
+
raise(*error_args) unless blk
|
26
|
+
|
27
|
+
instance_exec(*error_args, &blk)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def debug_rescue_on_fail(*names, &blk)
|
34
|
+
unless blk
|
35
|
+
raise NoBlockGiven,
|
36
|
+
'.rescue_on_fail must be called with a block',
|
37
|
+
caller
|
38
|
+
end
|
39
|
+
names.each do |name|
|
40
|
+
meth = instance_method(name)
|
41
|
+
define_method(name) do |*args, &block|
|
42
|
+
begin
|
43
|
+
meth.bind(self).call(*args, &block)
|
44
|
+
rescue StandardError => e
|
45
|
+
instance_exec(e, &blk)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def debug_before(*names, &blk)
|
52
|
+
unless blk
|
53
|
+
raise NoBlockGiven,
|
54
|
+
'.before must be called with a block',
|
55
|
+
caller
|
56
|
+
end
|
57
|
+
names.each do |name|
|
58
|
+
meth = instance_method(name)
|
59
|
+
define_method name do |*args, &block|
|
60
|
+
instance_exec(name, *args, block, &blk)
|
61
|
+
meth.bind(self).call(*args, &block)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def debug_after(*names, &blk)
|
67
|
+
unless blk
|
68
|
+
raise NoBlockGiven,
|
69
|
+
'.after must be called with a block',
|
70
|
+
caller
|
71
|
+
end
|
72
|
+
names.each do |name|
|
73
|
+
meth = instance_method(name)
|
74
|
+
define_method name do |*args, &block|
|
75
|
+
result = meth.bind(self).call(*args, &block)
|
76
|
+
instance_exec(result, &blk)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -2,9 +2,10 @@
|
|
2
2
|
|
3
3
|
module DebugLogging
|
4
4
|
class InstanceLogger < Module
|
5
|
-
def initialize(i_methods: nil, config: nil)
|
5
|
+
def initialize(i_methods: nil, payload: nil, config: nil)
|
6
6
|
super()
|
7
7
|
@config = config
|
8
|
+
@payload = payload
|
8
9
|
@instance_methods_to_log = Array(i_methods) if i_methods
|
9
10
|
end
|
10
11
|
|
@@ -13,6 +14,7 @@ module DebugLogging
|
|
13
14
|
|
14
15
|
base.send(:include, ArgumentPrinter)
|
15
16
|
instance_method_logger = DebugLogging::InstanceLoggerModulizer.to_mod(methods_to_log: @instance_methods_to_log,
|
17
|
+
payload: @payload,
|
16
18
|
config: @config)
|
17
19
|
base.send(:prepend, instance_method_logger)
|
18
20
|
end
|