debug_logging 1.0.0 → 1.0.1
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/README.md +13 -2
- data/lib/debug_logging/argument_printer.rb +34 -13
- data/lib/debug_logging/class_logger.rb +14 -3
- data/lib/debug_logging/configuration.rb +55 -10
- data/lib/debug_logging/instance_logger.rb +6 -6
- data/lib/debug_logging/instance_logger_modulizer.rb +11 -5
- data/lib/debug_logging/version.rb +1 -1
- data/lib/debug_logging.rb +12 -0
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 95c155d2751e4ed8027d638174dd657f1205e009
|
|
4
|
+
data.tar.gz: 26c3390ea291a866f51c77b55961ae12c8439123
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b58918fd56b134e8e1285a4b4551e1b722c58a3138c178dcea67b0250156cb13d34588d8ed5858112024753192ba9f399c3131e50794f68ac47c814045ce1407
|
|
7
|
+
data.tar.gz: 8f6addac4962c57b13dfa9b9140775a548b845ead6df02b0c47393b3723bf26adf997807b38f84f6b6b6eb0536d8e5c0475e25ba2577a0b33344d5031e9585b7
|
data/README.md
CHANGED
|
@@ -79,6 +79,10 @@ end
|
|
|
79
79
|
**All** of the above **config** is **inheritable** and **configurable** at the **per-class** level as well!
|
|
80
80
|
Just prepend `debug_` to any config value you want to override in a class.
|
|
81
81
|
|
|
82
|
+
**All** of the above **config** is **inheritable** and **configurable** at the **per-method** level as well!
|
|
83
|
+
Just send along a hash of the config options when you call `logged` or `include DebugLogging::InstanceLogger.new(i_methods: [:drive, :stop])`. See the example class below:
|
|
84
|
+
|
|
85
|
+
|
|
82
86
|
Every time a method is called, get logs, optionally with arguments, a benchmarck, and a unique invocation identifier:
|
|
83
87
|
|
|
84
88
|
```ruby
|
|
@@ -98,18 +102,25 @@ class Car
|
|
|
98
102
|
|
|
99
103
|
extend DebugLogging::ClassLogger
|
|
100
104
|
|
|
101
|
-
logged def
|
|
105
|
+
logged def make; new; end
|
|
102
106
|
def design(*args); new; end
|
|
103
107
|
def safety(*args); new; end
|
|
108
|
+
def dealer_options(*args); new; end
|
|
104
109
|
logged :design, :safety
|
|
110
|
+
# override options for any instance method(s), by passing a hash as the last argument
|
|
111
|
+
logged :dealer_options, { multiple_last_hashes: true }
|
|
112
|
+
|
|
105
113
|
|
|
106
114
|
def drive(speed); speed; end
|
|
107
|
-
def stop; 0; end
|
|
115
|
+
def stop(**opts); 0; end
|
|
108
116
|
|
|
109
117
|
# For instance methods:
|
|
110
118
|
# Option 2: add logging to all instance methods defined above (but *not* defined below)
|
|
111
119
|
include DebugLogging::InstanceLogger.new(i_methods: debug_instance_methods(false))
|
|
112
120
|
|
|
121
|
+
# override options for any instance method(s)
|
|
122
|
+
include DebugLogging::InstanceLogger.new(i_methods: [:stop], config: { multiple_last_hashes: true })
|
|
123
|
+
|
|
113
124
|
def will_not_be_logged; false; end
|
|
114
125
|
|
|
115
126
|
end
|
|
@@ -1,27 +1,48 @@
|
|
|
1
1
|
module DebugLogging
|
|
2
2
|
module ArgumentPrinter
|
|
3
|
-
def debug_arguments_to_s(args)
|
|
4
|
-
|
|
3
|
+
def debug_arguments_to_s(args: nil, config_proxy: nil)
|
|
4
|
+
printed_args = ""
|
|
5
|
+
add_args_ellipsis = false
|
|
6
|
+
if config_proxy.debug_last_hash_to_s_proc && args[-1].is_a?(Hash)
|
|
5
7
|
if args.length > 1
|
|
6
|
-
add_args_ellipsis = false
|
|
7
8
|
add_last_hash_ellipsis = false
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
if config_proxy.debug_multiple_last_hashes
|
|
10
|
+
last_hash_args, other_args = args.partition do |arg|
|
|
11
|
+
arg.is_a?(Hash)
|
|
12
|
+
end
|
|
13
|
+
other_args_string = other_args.map(&:inspect).join(", ").tap {|x| add_args_ellipsis = x.length > config_proxy.debug_args_max_length}[0..(config_proxy.debug_args_max_length)]
|
|
14
|
+
last_hash_args_string = last_hash_args.map do |arg|
|
|
15
|
+
String(config_proxy.
|
|
16
|
+
debug_last_hash_to_s_proc.
|
|
17
|
+
call(arg)).
|
|
18
|
+
tap {|x|
|
|
19
|
+
add_last_hash_ellipsis = x.length > config_proxy.debug_last_hash_max_length
|
|
20
|
+
}[0..(config_proxy.debug_last_hash_max_length)].
|
|
21
|
+
tap {|x|
|
|
22
|
+
x << config_proxy.debug_ellipsis if add_last_hash_ellipsis
|
|
23
|
+
}
|
|
24
|
+
end.join(", ")
|
|
25
|
+
printed_args << other_args_string if other_args_string
|
|
26
|
+
printed_args << ", " if !other_args_string.empty? && !last_hash_args_string.empty?
|
|
27
|
+
printed_args << last_hash_args_string if last_hash_args_string
|
|
28
|
+
else
|
|
29
|
+
printed_args << args[0..(-2)].map {|x| x.inspect}.join(", ").tap {|x| add_args_ellipsis = x.length > config_proxy.debug_args_max_length}[0..(config_proxy.debug_args_max_length)]
|
|
30
|
+
printed_args << config_proxy.debug_ellipsis if add_args_ellipsis
|
|
31
|
+
printed_args << ", " << config_proxy.debug_last_hash_to_s_proc.call(args[-1]).tap {|x| add_last_hash_ellipsis = x.length > config_proxy.debug_last_hash_max_length}[0..(config_proxy.debug_last_hash_max_length)]
|
|
32
|
+
printed_args << config_proxy.debug_ellipsis if add_last_hash_ellipsis
|
|
33
|
+
end
|
|
12
34
|
else
|
|
13
|
-
printed_args
|
|
14
|
-
printed_args << debug_ellipsis if add_last_hash_ellipsis
|
|
35
|
+
printed_args << String(config_proxy.debug_last_hash_to_s_proc.call(args[0])).tap {|x| add_last_hash_ellipsis = x.length > config_proxy.debug_last_hash_max_length}[0..(config_proxy.debug_last_hash_max_length)]
|
|
36
|
+
printed_args << config_proxy.debug_ellipsis if add_last_hash_ellipsis
|
|
15
37
|
end
|
|
16
38
|
else
|
|
17
|
-
add_args_ellipsis = false
|
|
18
39
|
if args.length == 1 && args[0].is_a?(Hash)
|
|
19
40
|
# handle double splat
|
|
20
|
-
printed_args
|
|
41
|
+
printed_args << ("**" << args.map {|x| x.inspect}.join(", ").tap {|x| add_args_ellipsis = x.length > config_proxy.debug_args_max_length})[0..(config_proxy.debug_args_max_length)]
|
|
21
42
|
else
|
|
22
|
-
printed_args
|
|
43
|
+
printed_args << args.map {|x| x.inspect}.join(", ").tap {|x| add_args_ellipsis = x.length > config_proxy.debug_args_max_length}[0..(config_proxy.debug_args_max_length)]
|
|
23
44
|
end
|
|
24
|
-
printed_args << debug_ellipsis if add_args_ellipsis
|
|
45
|
+
printed_args << config_proxy.debug_ellipsis if add_args_ellipsis
|
|
25
46
|
end
|
|
26
47
|
"(#{printed_args})"
|
|
27
48
|
end
|
|
@@ -1,16 +1,27 @@
|
|
|
1
1
|
module DebugLogging
|
|
2
2
|
module ClassLogger
|
|
3
3
|
def logged(*methods_to_log)
|
|
4
|
+
opts = methods_to_log.last.is_a?(Hash) && methods_to_log.pop
|
|
5
|
+
if methods_to_log.first.is_a?(Array)
|
|
6
|
+
methods_to_log = methods_to_log.shift
|
|
7
|
+
else
|
|
8
|
+
# logged :meth1, :meth2, :meth3 is valid
|
|
9
|
+
end
|
|
4
10
|
methods_to_log.each do |method_to_log|
|
|
5
11
|
# method name must be a symbol
|
|
6
12
|
method_to_log = method_to_log.to_sym
|
|
7
13
|
original_method = method(method_to_log)
|
|
8
14
|
(class << self; self; end).class_eval do
|
|
9
15
|
define_method(method_to_log) do |*args|
|
|
16
|
+
config_proxy = if opts
|
|
17
|
+
Configuration.new(**(debug_config.to_hash.merge(opts)))
|
|
18
|
+
else
|
|
19
|
+
self
|
|
20
|
+
end
|
|
10
21
|
method_return_value = nil
|
|
11
|
-
invocation_id = " ~#{args.object_id}@#{Time.now.to_i}~" if debug_add_invocation_id
|
|
12
|
-
debug_log "#{self}.#{method_to_log}#{debug_arguments_to_s(args)}#{invocation_id}"
|
|
13
|
-
if debug_class_benchmarks
|
|
22
|
+
invocation_id = " ~#{args.object_id}@#{Time.now.to_i}~" if config_proxy.debug_add_invocation_id
|
|
23
|
+
debug_log "#{self}.#{method_to_log}#{debug_arguments_to_s(args: args, config_proxy: config_proxy)}#{invocation_id}"
|
|
24
|
+
if config_proxy.debug_class_benchmarks
|
|
14
25
|
elapsed = Benchmark.realtime do
|
|
15
26
|
method_return_value = original_method.call(*args)
|
|
16
27
|
end
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
module DebugLogging
|
|
2
2
|
class Configuration
|
|
3
|
+
DEFAULT_ELLIPSIS = " ✂️ …".freeze
|
|
3
4
|
attr_accessor :logger
|
|
4
5
|
attr_accessor :log_level
|
|
6
|
+
attr_accessor :multiple_last_hashes
|
|
5
7
|
attr_accessor :last_hash_to_s_proc
|
|
6
8
|
attr_accessor :last_hash_max_length
|
|
7
9
|
attr_accessor :args_max_length
|
|
@@ -9,16 +11,45 @@ module DebugLogging
|
|
|
9
11
|
attr_accessor :class_benchmarks
|
|
10
12
|
attr_accessor :add_invocation_id
|
|
11
13
|
attr_accessor :ellipsis
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
14
|
+
# alias the readers to the debug_* prefix so an instance of this class
|
|
15
|
+
# can have the same API granted by `extend DebugLogging`
|
|
16
|
+
#
|
|
17
|
+
# include DebugLogging::InstanceLogger.new(
|
|
18
|
+
# i_methods: [:drive, :stop],
|
|
19
|
+
# config: {
|
|
20
|
+
# logger: Logger.new(STDOUT) # probably want to override to be the Rails.logger
|
|
21
|
+
# log_level: :debug # at what level do the messages created by this gem sent at?
|
|
22
|
+
# last_hash_to_s_proc: nil # e.g. ->(hash) { "keys: #{hash.keys}" }
|
|
23
|
+
# last_hash_max_length: 1_000
|
|
24
|
+
# args_max_length: 1_000
|
|
25
|
+
# instance_benchmarks: false
|
|
26
|
+
# class_benchmarks: false
|
|
27
|
+
# add_invocation_id: true # invocation id allows you to identify a method call uniquely in a log
|
|
28
|
+
# ellipsis: " ✂️ …".freeze
|
|
29
|
+
# }
|
|
30
|
+
# )
|
|
31
|
+
#
|
|
32
|
+
alias :debug_logger :logger
|
|
33
|
+
alias :debug_log_level :log_level
|
|
34
|
+
alias :debug_multiple_last_hashes :multiple_last_hashes
|
|
35
|
+
alias :debug_last_hash_to_s_proc :last_hash_to_s_proc
|
|
36
|
+
alias :debug_last_hash_max_length :last_hash_max_length
|
|
37
|
+
alias :debug_args_max_length :args_max_length
|
|
38
|
+
alias :debug_instance_benchmarks :instance_benchmarks
|
|
39
|
+
alias :debug_class_benchmarks :class_benchmarks
|
|
40
|
+
alias :debug_add_invocation_id :add_invocation_id
|
|
41
|
+
alias :debug_ellipsis :ellipsis
|
|
42
|
+
def initialize(**options)
|
|
43
|
+
@logger = options.key?(:logger) ? options[:logger] : Logger.new(STDOUT)
|
|
44
|
+
@log_level = options.key?(:log_level) ? options[:log_level] : :debug
|
|
45
|
+
@multiple_last_hashes = options.key?(:multiple_last_hashes) ? options[:multiple_last_hashes] : false
|
|
46
|
+
@last_hash_to_s_proc = options.key?(:last_hash_to_s_proc) ? options[:last_hash_to_s_proc] : nil
|
|
47
|
+
@last_hash_max_length = options.key?(:last_hash_max_length) ? options[:last_hash_max_length] : 1_000
|
|
48
|
+
@args_max_length = options.key?(:args_max_length) ? options[:args_max_length] : 1_000
|
|
49
|
+
@instance_benchmarks = options.key?(:instance_benchmarks) ? options[:instance_benchmarks] : false
|
|
50
|
+
@class_benchmarks = options.key?(:class_benchmarks) ? options[:class_benchmarks] : false
|
|
51
|
+
@add_invocation_id = options.key?(:add_invocation_id) ? options[:add_invocation_id] : true
|
|
52
|
+
@ellipsis = options.key?(:ellipsis) ? options[:ellipsis] : DEFAULT_ELLIPSIS
|
|
22
53
|
end
|
|
23
54
|
def instance_benchmarks=(instance_benchmarks)
|
|
24
55
|
require "benchmark" if instance_benchmarks
|
|
@@ -28,5 +59,19 @@ module DebugLogging
|
|
|
28
59
|
require "benchmark" if class_benchmarks
|
|
29
60
|
@class_benchmarks = class_benchmarks
|
|
30
61
|
end
|
|
62
|
+
def to_hash
|
|
63
|
+
{
|
|
64
|
+
logger: logger,
|
|
65
|
+
log_level: log_level,
|
|
66
|
+
multiple_last_hashes: multiple_last_hashes,
|
|
67
|
+
last_hash_to_s_proc: last_hash_to_s_proc,
|
|
68
|
+
last_hash_max_length: last_hash_max_length,
|
|
69
|
+
args_max_length: args_max_length,
|
|
70
|
+
instance_benchmarks: instance_benchmarks,
|
|
71
|
+
class_benchmarks: class_benchmarks,
|
|
72
|
+
add_invocation_id: add_invocation_id,
|
|
73
|
+
ellipsis: ellipsis
|
|
74
|
+
}
|
|
75
|
+
end
|
|
31
76
|
end
|
|
32
77
|
end
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
module DebugLogging
|
|
2
2
|
class InstanceLogger < Module
|
|
3
|
-
def initialize(i_methods: nil)
|
|
3
|
+
def initialize(i_methods: nil, config: nil)
|
|
4
|
+
@config = config
|
|
4
5
|
@instance_methods_to_log = Array(i_methods) if i_methods
|
|
5
6
|
end
|
|
6
7
|
def included(base)
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
end
|
|
8
|
+
return unless @instance_methods_to_log
|
|
9
|
+
base.send(:include, ArgumentPrinter)
|
|
10
|
+
instance_method_logger = DebugLogging::InstanceLoggerModulizer.to_mod(methods_to_log: @instance_methods_to_log, config_proxy: @config)
|
|
11
|
+
base.send(:prepend, instance_method_logger)
|
|
12
12
|
end
|
|
13
13
|
end
|
|
14
14
|
end
|
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
module DebugLogging
|
|
2
2
|
module InstanceLoggerModulizer
|
|
3
|
-
def self.to_mod(methods_to_log
|
|
3
|
+
def self.to_mod(methods_to_log: nil, config_proxy: nil)
|
|
4
4
|
Module.new do
|
|
5
5
|
Array(methods_to_log).each do |method_to_log|
|
|
6
6
|
# method name must be a symbol
|
|
7
7
|
define_method(method_to_log.to_sym) do |*args, &block|
|
|
8
|
+
config_proxy = if config_proxy.is_a?(Hash)
|
|
9
|
+
Configuration.new(**(self.class.debug_config.to_hash.merge(config_proxy)))
|
|
10
|
+
else
|
|
11
|
+
self.class
|
|
12
|
+
end
|
|
8
13
|
method_return_value = nil
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
14
|
+
log_prefix = "#{self.class}##{method_to_log}"
|
|
15
|
+
invocation_id = " ~#{args.object_id}@#{Time.now.to_i}~" if config_proxy.debug_add_invocation_id && args
|
|
16
|
+
self.class.debug_log "#{log_prefix}#{self.class.debug_arguments_to_s(args: args, config_proxy: config_proxy)}#{invocation_id}"
|
|
17
|
+
if config_proxy.debug_instance_benchmarks
|
|
12
18
|
elapsed = Benchmark.realtime do
|
|
13
19
|
method_return_value = super(*args, &block)
|
|
14
20
|
end
|
|
15
|
-
self.class.debug_log "#{
|
|
21
|
+
self.class.debug_log "#{log_prefix} completed in #{sprintf("%f", elapsed)}s#{invocation_id}"
|
|
16
22
|
else
|
|
17
23
|
method_return_value = super(*args, &block)
|
|
18
24
|
end
|
data/lib/debug_logging.rb
CHANGED
|
@@ -62,6 +62,12 @@ module DebugLogging
|
|
|
62
62
|
debug_logger.send(debug_log_level, message)
|
|
63
63
|
end
|
|
64
64
|
|
|
65
|
+
# There are times when the class will need access to the configuration object,
|
|
66
|
+
# such as to override it per instance method
|
|
67
|
+
def debug_config
|
|
68
|
+
@debug_logging_configuration
|
|
69
|
+
end
|
|
70
|
+
|
|
65
71
|
# For single statement global config in an initializer
|
|
66
72
|
# e.g. DebugLogging.configuration.ellipsis = "..."
|
|
67
73
|
def self.configuration
|
|
@@ -98,6 +104,12 @@ module DebugLogging
|
|
|
98
104
|
def debug_log_level=(log_level)
|
|
99
105
|
@debug_logging_configuration.log_level = log_level
|
|
100
106
|
end
|
|
107
|
+
def debug_multiple_last_hashes
|
|
108
|
+
@debug_logging_configuration.multiple_last_hashes
|
|
109
|
+
end
|
|
110
|
+
def debug_multiple_last_hashes=(multiple_last_hashes)
|
|
111
|
+
@debug_logging_configuration.multiple_last_hashes = multiple_last_hashes
|
|
112
|
+
end
|
|
101
113
|
def debug_last_hash_to_s_proc
|
|
102
114
|
@debug_logging_configuration.last_hash_to_s_proc
|
|
103
115
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: debug_logging
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter Boling
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2017-03-
|
|
11
|
+
date: 2017-03-29 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rspec-pending_for
|
|
@@ -124,7 +124,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
124
124
|
version: '0'
|
|
125
125
|
requirements: []
|
|
126
126
|
rubyforge_project:
|
|
127
|
-
rubygems_version: 2.6.
|
|
127
|
+
rubygems_version: 2.6.11
|
|
128
128
|
signing_key:
|
|
129
129
|
specification_version: 4
|
|
130
130
|
summary: Drop-in debug logging useful when a call stack gets unruly
|