debug_logging 3.1.2 → 3.1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fb9df42efa08fe95b6c9270a4474132b2dbb55ed8d154d17c20dfde074781a8c
4
- data.tar.gz: 459f277689fcb9b328b4c904730ae25bfe1c55fc87a5ab292157393f6b13c36b
3
+ metadata.gz: e6eee794d14ae44299b2737ff61beab4165c434132262861104d60b4da781445
4
+ data.tar.gz: c9fdb194a05fa751879a60bb73bd4eb3fe4507b0680b1ee437f5d88fa65b3fa0
5
5
  SHA512:
6
- metadata.gz: 5af7096cfbadcea5695cc19bdce85e4d6ac8eecf02139378cb2dc0d734d99011bc49ff239fe1d816ce9570a883b75b4f6e0772fdfbf7feda147e7890c56d415a
7
- data.tar.gz: f471d3858ad20c1d3347b4ce328254c01572da54fd0e566ccbf6b15827996c561cf86c5fcb23f14ad127d5a9449b045c63281768c082b2375d754e566f3d4561
6
+ metadata.gz: 8eeb20c2a01e99b3069f8b592f54271497a6835402e76d73edba964645c2b6600e83e3d497b7eddf5720087b89421e61caa7e5224124f5205fdde6f0b82d5426
7
+ data.tar.gz: fce74d216e19def9b2e8b208036138732fc82add3e889fdd3a09199dab285354c5863b1a11b12feb451faa9e39294507ec704e40031568272ac03a6c1be13077
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # DebugLogging
2
2
 
3
3
  Unobtrusive, inheritable-overridable-configurable, drop-in debug logging, that won't leave a mess behind when it is time to remove it.
4
+ Supports ActiveSupport::Notifications (thanks [@jgillson](https://github.com/jgillson)). Optional ActiveRecord callback-style hooks that you can decorate your methods with. Hooks logic was taken from the [`slippy_method_hooks` gem](https://github.com/guckin/slippy_method_hooks), (thanks [@guckin](https://github.com/guckin)), and prefaced with `debug_` for this implementation. `DebugLogging::Finalize` is lightly modified from [this stackoverflow answer](https://stackoverflow.com/a/34559282).
4
5
 
5
6
  ## What do I mean by "unobtrusive"?
6
7
 
@@ -32,12 +33,15 @@ Unobtrusive, inheritable-overridable-configurable, drop-in debug logging, that w
32
33
  * *colorization by class/method*
33
34
  * *robust argument printer with customizable ellipsis*
34
35
  * *unique invocation identifiers*
35
- * *single line config, per class/instance/method config*
36
- * *separate logger, if needed*
36
+ * *simple single line global config, or per class/instance/method config*
37
+ * *separate loggers, if needed*
37
38
  * *log method calls, also when exit scope*
38
39
  * *Prevents heavy computation of strings with `logger.debug { 'log me' }` block format, since v1.0.12*
39
- * *ActiveSupport::Notifications integration for instrumenting/logging events on class and instance methods, since v3.1*
40
- * *Optional instance variable logging, sine v3.1*
40
+ * *ActiveSupport::Notifications integration for instrumenting/logging events on class and instance methods, since v3.2*
41
+ * *Optional instance, and class-instance, variable logging, since v3.2*
42
+ * *ActiveRecord style callback-hooks (optional: `require 'debug_logging/hooks'` and `include DebugLogging::Hooks`), since v3.2*
43
+ * *All configuration is inheritable to, and overridable by, child classes, since v3.2*
44
+ * *[Class finalization hook](https://stackoverflow.com/a/34559282) (optional: `require 'debug_logging/finalize'` and `extend DebugLogging::Finalize`), since v3.2*
41
45
  * **so many free ponies** 🎠🐴🎠🐴🎠🐴
42
46
 
43
47
  ## Next Level Magic
@@ -381,6 +385,10 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
381
385
  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
382
386
  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
383
387
 
388
+ ### License Exceptions
389
+
390
+ * [`debug_logging/finalize`](https://stackoverflow.com/a/34559282) is licensed under https://creativecommons.org/licenses/by-sa/4.0/
391
+
384
392
  [semver]: http://semver.org/
385
393
  [pvc]: http://docs.rubygems.org/read/chapter/16#page74
386
394
  [railsbling]: http://www.railsbling.com
@@ -7,7 +7,7 @@ require 'debug_logging/version'
7
7
  Gem::Specification.new do |spec|
8
8
  spec.name = 'debug_logging'
9
9
  spec.version = DebugLogging::VERSION
10
- spec.authors = ['Peter Boling']
10
+ spec.authors = ['Peter Boling', 'guckin']
11
11
  spec.email = ['peter.boling@gmail.com']
12
12
 
13
13
  spec.summary = 'Drop-in debug logging useful when a call stack gets unruly'
@@ -5,8 +5,12 @@ require 'colorized_string'
5
5
  require 'digest'
6
6
 
7
7
  require 'debug_logging/version'
8
+ require 'debug_logging/errors'
8
9
  require 'debug_logging/configuration'
10
+ require 'debug_logging/util'
11
+ require 'debug_logging/finalize'
9
12
  require 'debug_logging/argument_printer'
13
+ require 'debug_logging/hooks'
10
14
  require 'debug_logging/instance_logger_modulizer'
11
15
  require 'debug_logging/instance_logger'
12
16
  require 'debug_logging/class_logger'
@@ -61,6 +65,11 @@ module DebugLogging
61
65
  def self.extended(base)
62
66
  base.send(:extend, ArgumentPrinter)
63
67
  base.debug_config_reset(Configuration.new(**debug_logging_configuration.to_hash))
68
+ base.class_eval do
69
+ def base.inherited(subclass)
70
+ subclass.debug_config_reset(Configuration.new(**debug_config.to_hash))
71
+ end
72
+ end
64
73
  end
65
74
 
66
75
  #### API ####
@@ -2,7 +2,7 @@
2
2
 
3
3
  module DebugLogging
4
4
  module ArgumentPrinter
5
- def debug_benchmark_to_s(tms: nil)
5
+ def debug_benchmark_to_s(tms:)
6
6
  "completed in #{format('%f', tms.real)}s (#{format('%f', tms.total)}s CPU)"
7
7
  end
8
8
 
@@ -73,17 +73,17 @@ module DebugLogging
73
73
  else
74
74
  printed_args += args[0..-2].map(&:inspect).join(', ').tap do |x|
75
75
  add_args_ellipsis = x.length > config_proxy.debug_args_max_length
76
- end [0..(config_proxy.debug_args_max_length)]
76
+ end[0..(config_proxy.debug_args_max_length)]
77
77
  printed_args += config_proxy.debug_ellipsis if add_args_ellipsis
78
78
  printed_args += ", #{config_proxy.debug_last_hash_to_s_proc.call(args[-1]).tap do |x|
79
79
  add_last_hash_ellipsis = x.length > config_proxy.debug_last_hash_max_length
80
- end [0..(config_proxy.debug_last_hash_max_length)]}"
80
+ end[0..(config_proxy.debug_last_hash_max_length)]}"
81
81
  printed_args += config_proxy.debug_ellipsis if add_last_hash_ellipsis
82
82
  end
83
83
  else
84
84
  printed_args += String(config_proxy.debug_last_hash_to_s_proc.call(args[0])).tap do |x|
85
85
  add_last_hash_ellipsis = x.length > config_proxy.debug_last_hash_max_length
86
- end [0..(config_proxy.debug_last_hash_max_length)]
86
+ end[0..(config_proxy.debug_last_hash_max_length)]
87
87
  printed_args += config_proxy.debug_ellipsis if add_last_hash_ellipsis
88
88
  end
89
89
  else
@@ -95,7 +95,7 @@ module DebugLogging
95
95
  else
96
96
  args.map(&:inspect).join(', ').tap do |x|
97
97
  add_args_ellipsis = x.length > config_proxy.debug_args_max_length
98
- end [0..(config_proxy.debug_args_max_length)]
98
+ end[0..(config_proxy.debug_args_max_length)]
99
99
  end
100
100
  printed_args += config_proxy.debug_ellipsis if add_args_ellipsis
101
101
  end
@@ -3,52 +3,31 @@
3
3
  module DebugLogging
4
4
  module ClassLogger
5
5
  def logged(*methods_to_log)
6
- # When opts are present it will always be a new configuration instance per method
7
- # When opts are not present it will reuse the class' configuration object
8
- payload = methods_to_log.last.is_a?(Hash) && methods_to_log.pop.dup || {}
9
- config_opts = {}
10
- unless payload.empty?
11
- DebugLogging::Configuration::CONFIG_KEYS.each { |k| config_opts[k] = payload.delete(k) if payload.key?(k) }
12
- end
13
- if methods_to_log.first.is_a?(Array)
14
- methods_to_log = methods_to_log.shift
15
- else
16
- # logged :meth1, :meth2, :meth3 without options is valid too
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 = if (proxy = instance_variable_get(DebugLogging::Configuration.config_pointer('kl',
25
- method_to_log)))
26
- proxy
27
- else
28
- proxy = if config_opts.empty?
29
- debug_config
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
29
  config_proxy.log do
42
- paydirt = {}
43
- # TODO: Could make instance variable introspection configurable before or after method execution
44
- if payload.key?(:instance_variables)
45
- paydirt.merge!(payload.reject { |k| k == :instance_variables })
46
- payload[:instance_variables].each do |k|
47
- paydirt[k] = instance_variable_get("@#{k}") if instance_variable_defined?("@#{k}")
48
- end
49
- else
50
- paydirt.merge!(payload)
51
- end
30
+ paydirt = DebugLogging::Util.payload_instance_vaiable_hydration(scope: self, payload: method_payload)
52
31
  log_prefix = debug_invocation_to_s(klass: to_s, separator: '.', method_to_log: method_to_log,
53
32
  config_proxy: config_proxy)
54
33
  invocation_id = debug_invocation_id_to_s(args: args, config_proxy: config_proxy)
@@ -3,51 +3,41 @@
3
3
  module DebugLogging
4
4
  module ClassNotifier
5
5
  def notifies(*methods_to_notify)
6
- # When opts are present it will always be a new configuration instance per method
7
- # When opts are not present it will reuse the class' configuration object
8
- payload = methods_to_notify.last.is_a?(Hash) && methods_to_notify.pop.dup || {}
9
- config_opts = {}
10
- unless payload.empty?
11
- DebugLogging::Configuration::CONFIG_KEYS.each { |k| config_opts[k] = payload.delete(k) if payload.key?(k) }
12
- end
13
- if methods_to_notify.first.is_a?(Array)
14
- methods_to_notify = methods_to_notify.shift
15
- else
16
- # logged :meth1, :meth2, :meth3 without options is valid too
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 = if (proxy = instance_variable_get(DebugLogging::Configuration.config_pointer('kn',
25
- method_to_notify)))
26
- proxy
27
- else
28
- proxy = if config_opts.empty?
29
- debug_config
30
- else
31
- DebugLogging::Configuration.new(**debug_config.to_hash.merge(config_opts))
32
- end
33
- proxy.register(method_to_notify)
34
- instance_variable_set(DebugLogging::Configuration.config_pointer('kn', method_to_notify),
35
- proxy)
36
- ActiveSupport::Notifications.subscribe(
37
- DebugLogging::ArgumentPrinter.debug_event_name_to_s(method_to_notify: method_to_notify)
38
- ) do |*debug_args|
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
- **payload
40
+ **paydirt
51
41
  }
52
42
  ) do
53
43
  if args.size == 1 && (harsh = args[0]) && harsh.is_a?(Hash)
@@ -0,0 +1,7 @@
1
+ module DebugLogging
2
+ class Error < StandardError; end
3
+
4
+ class TimeoutError < Error; end
5
+
6
+ class NoBlockGiven < Error; end
7
+ 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
@@ -2,52 +2,32 @@
2
2
 
3
3
  module DebugLogging
4
4
  module InstanceLoggerModulizer
5
- def self.to_mod(methods_to_log: nil, config: nil)
5
+ def self.to_mod(methods_to_log: nil, payload: nil, config: nil)
6
6
  Module.new do
7
+ methods_to_log, payload, config_opts = DebugLogging::Util.extract_payload_and_config(
8
+ method_names: Array(methods_to_log),
9
+ payload: payload,
10
+ config: config
11
+ )
7
12
  Array(methods_to_log).each do |method_to_log|
8
- payload = (method_to_log.is_a?(Array) && method_to_log.last.is_a?(Hash) && method_to_log.pop.dup) || {}
9
- config_opts = {}
10
- unless payload.empty?
11
- DebugLogging::Configuration::CONFIG_KEYS.each { |k| config_opts[k] = payload.delete(k) if payload.key?(k) }
12
- end
13
- # method name must be a symbol
14
- method_to_log = if method_to_log.is_a?(Array)
15
- method_to_log.first&.to_sym
16
- else
17
- method_to_log.to_sym
18
- end
13
+ method_to_log, method_payload, method_config_opts = DebugLogging::Util.extract_payload_and_config(
14
+ method_names: method_to_log,
15
+ payload: payload,
16
+ config: config_opts
17
+ )
19
18
  define_method(method_to_log) do |*args, &block|
20
19
  method_return_value = nil
21
- config_proxy = if (proxy = instance_variable_get(DebugLogging::Configuration.config_pointer('ilm',
22
- method_to_log)))
23
- proxy
24
- else
25
- proxy = if config
26
- Configuration.new(**self.class.debug_config.to_hash.merge(config.merge(config_opts)))
27
- elsif !config_opts.empty?
28
- Configuration.new(**self.class.debug_config.to_hash.merge(config_opts))
29
- else
30
- self.class.debug_config
31
- end
32
- proxy.register(method_to_log)
33
- instance_variable_set(DebugLogging::Configuration.config_pointer('ilm', method_to_log),
34
- proxy)
35
- proxy
36
- end
20
+ config_proxy = DebugLogging::Util.config_proxy_finder(
21
+ scope: self.class,
22
+ config_opts: method_config_opts,
23
+ method_name: method_to_log,
24
+ proxy_ref: 'ilm'
25
+ )
37
26
  log_prefix = self.class.debug_invocation_to_s(klass: self.class.to_s, separator: '#',
38
27
  method_to_log: method_to_log, config_proxy: config_proxy)
39
28
  invocation_id = self.class.debug_invocation_id_to_s(args: args, config_proxy: config_proxy)
40
29
  config_proxy.log do
41
- paydirt = {}
42
- # TODO: Could make instance variable introspection configurable before or after method execution
43
- if payload.key?(:instance_variables)
44
- paydirt.merge!(payload.reject { |k| k == :instance_variables })
45
- payload[:instance_variables].each do |k|
46
- paydirt[k] = instance_variable_get("@#{k}") if instance_variable_defined?("@#{k}")
47
- end
48
- else
49
- paydirt.merge!(payload)
50
- end
30
+ paydirt = DebugLogging::Util.payload_instance_vaiable_hydration(scope: self, payload: method_payload)
51
31
  signature = self.class.debug_signature_to_s(args: args, config_proxy: config_proxy)
52
32
  paymud = debug_payload_to_s(payload: paydirt, config_proxy: config_proxy)
53
33
  "#{log_prefix}#{signature}#{invocation_id} debug: #{paymud}"
@@ -2,8 +2,10 @@
2
2
 
3
3
  module DebugLogging
4
4
  class InstanceNotifier < Module
5
- def initialize(i_methods: nil)
5
+ def initialize(i_methods: nil, payload: nil, config: nil)
6
6
  super()
7
+ @config = config
8
+ @payload = payload
7
9
  @instance_methods_to_notify = Array(i_methods) if i_methods
8
10
  end
9
11
 
@@ -11,7 +13,9 @@ module DebugLogging
11
13
  return unless @instance_methods_to_notify
12
14
 
13
15
  base.send(:include, ArgumentPrinter)
14
- instance_method_notifier = DebugLogging::InstanceNotifierModulizer.to_mod(methods_to_notify: @instance_methods_to_notify)
16
+ instance_method_notifier = DebugLogging::InstanceNotifierModulizer.to_mod(methods_to_notify: @instance_methods_to_notify,
17
+ payload: @payload,
18
+ config: @config)
15
19
  base.send(:prepend, instance_method_notifier)
16
20
  end
17
21
  end
@@ -2,47 +2,35 @@
2
2
 
3
3
  module DebugLogging
4
4
  module InstanceNotifierModulizer
5
- def self.to_mod(methods_to_notify: nil)
5
+ def self.to_mod(methods_to_notify: nil, payload: nil, config: nil)
6
6
  Module.new do
7
- config_proxy = nil
8
-
7
+ methods_to_notify, payload, config_opts = DebugLogging::Util.extract_payload_and_config(
8
+ method_names: Array(methods_to_notify),
9
+ payload: payload,
10
+ config: config
11
+ )
9
12
  Array(methods_to_notify).each do |method_to_notify|
10
- # method name must be a symbol
11
- payload = (method_to_notify.is_a?(Array) && method_to_notify.last.is_a?(Hash) && method_to_notify.pop.dup) || {}
12
- config_opts = {}
13
- unless payload.empty?
14
- DebugLogging::Configuration::CONFIG_KEYS.each { |k| config_opts[k] = payload.delete(k) if payload.key?(k) }
15
- end
16
- method_to_notify = if method_to_notify.is_a?(Array)
17
- method_to_notify.first&.to_sym
18
- else
19
- method_to_notify.to_sym
20
- end
13
+ method_to_notify, method_payload, method_config_opts = DebugLogging::Util.extract_payload_and_config(
14
+ method_names: method_to_notify,
15
+ payload: payload,
16
+ config: config_opts
17
+ )
21
18
  define_method(method_to_notify) do |*args, &block|
22
- config_proxy = if (proxy = instance_variable_get(DebugLogging::Configuration.config_pointer('inm',
23
- method_to_notify)))
24
- proxy
25
- else
26
- proxy = if config_opts.empty?
27
- self.class.debug_config
28
- else
29
- Configuration.new(**self.class.debug_config.to_hash.merge(config_opts))
30
- end
31
- proxy.register(method_to_notify)
32
- instance_variable_set(
33
- DebugLogging::Configuration.config_pointer('inm', method_to_notify), proxy
34
- )
35
- proxy
36
- end
37
- paydirt = {}
38
- if payload.key?(:instance_variables)
39
- paydirt.merge!(payload.reject { |k| k == :instance_variables })
40
- payload[:instance_variables].each do |k|
41
- paydirt[k] = instance_variable_get("@#{k}") if instance_variable_defined?("@#{k}")
19
+ config_proxy = DebugLogging::Util.config_proxy_finder(
20
+ scope: self.class,
21
+ config_opts: method_config_opts,
22
+ method_name: method_to_notify,
23
+ proxy_ref: 'inm'
24
+ ) do |config_proxy|
25
+ ActiveSupport::Notifications.subscribe(
26
+ DebugLogging::ArgumentPrinter.debug_event_name_to_s(method_to_notify: method_to_notify)
27
+ ) do |*args|
28
+ config_proxy&.log do
29
+ DebugLogging::LogSubscriber.log_event(ActiveSupport::Notifications::Event.new(*args))
30
+ end
42
31
  end
43
- else
44
- paydirt.merge!(payload)
45
32
  end
33
+ paydirt = DebugLogging::Util.payload_instance_vaiable_hydration(scope: self, payload: method_payload)
46
34
  ActiveSupport::Notifications.instrument(
47
35
  DebugLogging::ArgumentPrinter.debug_event_name_to_s(method_to_notify: method_to_notify),
48
36
  debug_args: args,
@@ -52,13 +40,6 @@ module DebugLogging
52
40
  super(*args, &block)
53
41
  end
54
42
  end
55
- ActiveSupport::Notifications.subscribe(
56
- DebugLogging::ArgumentPrinter.debug_event_name_to_s(method_to_notify: method_to_notify)
57
- ) do |*args|
58
- config_proxy&.log do
59
- DebugLogging::LogSubscriber.log_event(ActiveSupport::Notifications::Event.new(*args))
60
- end
61
- end
62
43
  end
63
44
  end
64
45
  end
@@ -0,0 +1,75 @@
1
+ module DebugLogging
2
+ module Util
3
+ module_function
4
+
5
+ # methods_to_log may be an array of a single method name, followed by config options and payload,
6
+ # or it could be an array of method names followed by config options and payload to be shared by the whole set.
7
+ def extract_payload_and_config(method_names:, payload: nil, config: nil)
8
+ # When scoped config is present it will always be a new configuration instance per method
9
+ # When scoped config is not present it will reuse the class' configuration object
10
+ scoped_payload = (method_names.is_a?(Array) && method_names.last.is_a?(Hash) && method_names.pop.clone(freeze: false)) || {}
11
+ payload = if payload
12
+ payload.merge(scoped_payload)
13
+ else
14
+ scoped_payload
15
+ end
16
+ config_opts = config&.clone(freeze: false) || {}
17
+ unless payload.empty?
18
+ DebugLogging::Configuration::CONFIG_KEYS.each { |k| config_opts[k] = payload.delete(k) if payload.key?(k) }
19
+ end
20
+ method_names =
21
+ case method_names
22
+ when Symbol
23
+ method_names
24
+ when String
25
+ method_names.to_sym
26
+ when Array
27
+ if method_names.first.is_a?(Array)
28
+ # Array of arrays?
29
+ method_names.shift
30
+ elsif method_names.size == 1 && method_names.first.is_a?(Symbol)
31
+ # when set as i_methods: [[:i_with_dsplat_payload, { tags: %w[blue green] }], ...]
32
+ method_names.shift.to_sym
33
+ else
34
+ # Or an array of method name symbols?
35
+ # logged :meth1, :meth2, :meth3 without options is valid
36
+ method_names
37
+ end
38
+ end
39
+ [method_names, payload, config_opts]
40
+ end
41
+
42
+ def payload_instance_vaiable_hydration(scope:, payload:)
43
+ paydirt = {}
44
+ # TODO: Could make instance variable introspection configurable before or after method execution
45
+ if payload.key?(:instance_variables)
46
+ paydirt.merge!(payload.reject { |k| k == :instance_variables })
47
+ payload[:instance_variables].each do |k|
48
+ paydirt[k] = scope.send(:instance_variable_get, "@#{k}") if scope.send(:instance_variable_defined?, "@#{k}")
49
+ end
50
+ else
51
+ paydirt.merge!(payload)
52
+ end
53
+ paydirt
54
+ end
55
+
56
+ def config_proxy_finder(scope:, method_name:, proxy_ref:, config_opts: {}, &block)
57
+ if (proxy = scope.send(:instance_variable_get, DebugLogging::Configuration.config_pointer(proxy_ref,
58
+ method_name)))
59
+ proxy
60
+ else
61
+ base = scope.respond_to?(:debug_config) ? scope.debug_config : DebugLogging.debug_logging_configuration
62
+ proxy = if config_opts.empty?
63
+ base
64
+ else
65
+ DebugLogging::Configuration.new(**base.to_hash.merge(config_opts))
66
+ end
67
+ proxy.register(method_name)
68
+ scope.send(:instance_variable_set, DebugLogging::Configuration.config_pointer(proxy_ref, method_name),
69
+ proxy)
70
+ yield proxy if block
71
+ proxy
72
+ end
73
+ end
74
+ end
75
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DebugLogging
4
- VERSION = '3.1.2'
4
+ VERSION = '3.1.3'
5
5
  end
metadata CHANGED
@@ -1,14 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: debug_logging
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.2
4
+ version: 3.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Boling
8
+ - guckin
8
9
  autorequire:
9
10
  bindir: exe
10
11
  cert_chain: []
11
- date: 2020-12-10 00:00:00.000000000 Z
12
+ date: 2020-12-18 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: colorize
@@ -226,11 +227,15 @@ files:
226
227
  - lib/debug_logging/class_logger.rb
227
228
  - lib/debug_logging/class_notifier.rb
228
229
  - lib/debug_logging/configuration.rb
230
+ - lib/debug_logging/errors.rb
231
+ - lib/debug_logging/finalize.rb
232
+ - lib/debug_logging/hooks.rb
229
233
  - lib/debug_logging/instance_logger.rb
230
234
  - lib/debug_logging/instance_logger_modulizer.rb
231
235
  - lib/debug_logging/instance_notifier.rb
232
236
  - lib/debug_logging/instance_notifier_modulizer.rb
233
237
  - lib/debug_logging/log_subscriber.rb
238
+ - lib/debug_logging/util.rb
234
239
  - lib/debug_logging/version.rb
235
240
  - lib/simple_debug_logging.rb
236
241
  homepage: https://github.com/pboling/debug_logging
@@ -252,7 +257,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
252
257
  - !ruby/object:Gem::Version
253
258
  version: '0'
254
259
  requirements: []
255
- rubygems_version: 3.1.4
260
+ rubygems_version: 3.2.1
256
261
  signing_key:
257
262
  specification_version: 4
258
263
  summary: Drop-in debug logging useful when a call stack gets unruly