debug_logging 3.1.1 → 3.1.7
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/.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
|