debug_logging 3.1.9 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  module DebugLogging
4
2
  class Configuration
5
3
  include Constants
@@ -11,21 +9,20 @@ module DebugLogging
11
9
  # alias the readers to the debug_* prefix so an instance of this class
12
10
  # can have the same API granted by `extend DebugLogging`
13
11
  #
14
- # include DebugLogging::InstanceLogger.new(
15
- # i_methods: [:drive, :stop],
16
- # config: {
17
- # logger: Logger.new(STDOUT) # probably want to override to be the Rails.logger
18
- # log_level: :debug # at what level do the messages created by this gem sent at?
19
- # last_hash_to_s_proc: nil # e.g. ->(hash) { "keys: #{hash.keys}" }
20
- # last_hash_max_length: 1_000
21
- # args_to_s_proc: nil # e.g. ->(*record) { "record id: #{record.first.id}" }
22
- # args_max_length: 1_000
23
- # instance_benchmarks: false
24
- # class_benchmarks: false
25
- # add_invocation_id: true # invocation id allows you to identify a method call uniquely in a log
26
- # ellipsis: " ✂️ …".freeze
12
+ # extend DebugLogging::InstanceLogger
13
+ # i_logged [:drive, :stop],
14
+ # {
15
+ # logger: Logger.new(STDOUT) # probably want to override to be the Rails.logger
16
+ # log_level: :debug # at what level do the messages created by this gem sent at?
17
+ # last_hash_to_s_proc: nil # e.g. ->(hash) { "keys: #{hash.keys}" }
18
+ # last_hash_max_length: 1_000
19
+ # args_to_s_proc: nil # e.g. ->(*record) { "record id: #{record.first.id}" }
20
+ # args_max_length: 1_000
21
+ # instance_benchmarks: false
22
+ # class_benchmarks: false
23
+ # add_invocation_id: true # invocation id allows you to identify a method call uniquely in a log
24
+ # ellipsis: " ✂️ …".freeze
27
25
  # }
28
- # )
29
26
  #
30
27
  CONFIG_KEYS.each do |key|
31
28
  alias_method :"debug_#{key}", :"#{key}"
@@ -39,12 +36,13 @@ module DebugLogging
39
36
  "@debug_logging_config_#{type}_#{Digest::MD5.hexdigest(method_to_log.to_s)}".to_sym
40
37
  end
41
38
  end
39
+
42
40
  def initialize(**options)
43
41
  CONFIG_ATTRS.each do |key|
44
- send("#{key}=", get_attr_from_options(options, key))
42
+ send(:"#{key}=", get_attr_from_options(options, key))
45
43
  end
46
44
  CONFIG_READERS.each do |key|
47
- send("#{key}=", get_reader_from_options(options, key))
45
+ send(:"#{key}=", get_reader_from_options(options, key))
48
46
  end
49
47
  @methods_to_log = []
50
48
  end
@@ -63,7 +61,7 @@ module DebugLogging
63
61
  def loggable?
64
62
  return @loggable if defined?(@loggable)
65
63
 
66
- @loggable = logger.send("#{log_level}?")
64
+ @loggable = logger.send(:"#{log_level}?")
67
65
  end
68
66
 
69
67
  def benchmarkable_for?(benchmarks)
@@ -95,7 +93,7 @@ module DebugLogging
95
93
 
96
94
  def to_hash
97
95
  CONFIG_KEYS.each_with_object({}) do |key, hash|
98
- hash[key] = instance_variable_get("@#{key}")
96
+ hash[key] = instance_variable_get(:"@#{key}")
99
97
  end
100
98
  end
101
99
 
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  module DebugLogging
4
2
  module Constants
5
3
  DEFAULT_ELLIPSIS = " ✂️ …"
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  # From: https://stackoverflow.com/a/34559282
4
2
  # License: https://creativecommons.org/licenses/by-sa/4.0/
5
3
  module DebugLogging
@@ -16,16 +16,14 @@ module DebugLogging
16
16
  names.each do |name|
17
17
  meth = instance_method(name)
18
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)
19
+ Timeout.timeout(time) do
20
+ meth.bind_call(self, *args, &block)
28
21
  end
22
+ rescue Timeout::Error
23
+ error_args = [TimeoutError, "execution expired", caller]
24
+ raise(*error_args) unless blk
25
+
26
+ instance_exec(*error_args, &blk)
29
27
  end
30
28
  end
31
29
  end
@@ -39,11 +37,9 @@ module DebugLogging
39
37
  names.each do |name|
40
38
  meth = instance_method(name)
41
39
  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
40
+ meth.bind_call(self, *args, &block)
41
+ rescue StandardError => e
42
+ instance_exec(e, &blk)
47
43
  end
48
44
  end
49
45
  end
@@ -58,7 +54,7 @@ module DebugLogging
58
54
  meth = instance_method(name)
59
55
  define_method(name) do |*args, &block|
60
56
  instance_exec(name, *args, block, &blk)
61
- meth.bind(self).call(*args, &block)
57
+ meth.bind_call(self, *args, &block)
62
58
  end
63
59
  end
64
60
  end
@@ -72,7 +68,7 @@ module DebugLogging
72
68
  names.each do |name|
73
69
  meth = instance_method(name)
74
70
  define_method(name) do |*args, &block|
75
- result = meth.bind(self).call(*args, &block)
71
+ result = meth.bind_call(self, *args, &block)
76
72
  instance_exec(result, &blk)
77
73
  end
78
74
  end
@@ -1,24 +1,28 @@
1
- # frozen_string_literal: true
2
-
3
1
  module DebugLogging
4
- class InstanceLogger < Module
5
- def initialize(i_methods: nil, payload: nil, config: nil)
6
- super()
7
- @config = config
8
- @payload = payload
9
- @instance_methods_to_log = Array(i_methods) if i_methods
10
- end
11
-
12
- def included(base)
13
- return unless @instance_methods_to_log
14
-
15
- base.send(:include, ArgumentPrinter)
16
- instance_method_logger = DebugLogging::InstanceLoggerModulizer.to_mod(
17
- methods_to_log: @instance_methods_to_log,
18
- payload: @payload,
19
- config: @config,
2
+ module InstanceLogger
3
+ def i_logged(*methods_to_log)
4
+ methods_to_log, payload, config_opts = DebugLogging::Util.extract_payload_and_config(
5
+ method_names: methods_to_log,
6
+ payload: nil,
7
+ config: nil,
20
8
  )
21
- base.send(:prepend, instance_method_logger)
9
+ instance_method_modules =
10
+ Array(methods_to_log).map do |method_to_log|
11
+ DebugLogging::InstanceLoggerModulizer.to_mod(
12
+ methods_to_log: Array(method_to_log),
13
+ payload: payload,
14
+ config: config_opts,
15
+ )
16
+ end
17
+ wrapped_in_logs = Module.new do
18
+ singleton_class.send(:define_method, :included) do |host_class|
19
+ instance_method_modules.each do |mod|
20
+ host_class.prepend(mod)
21
+ end
22
+ end
23
+ end
24
+
25
+ send(:include, wrapped_in_logs)
22
26
  end
23
27
  end
24
28
  end
@@ -1,65 +1,65 @@
1
- # frozen_string_literal: true
2
-
3
1
  module DebugLogging
4
2
  module InstanceLoggerModulizer
5
- def self.to_mod(methods_to_log: nil, payload: nil, config: nil)
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
- )
12
- Array(methods_to_log).each do |method_to_log|
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,
3
+ class << self
4
+ def to_mod(methods_to_log: nil, payload: nil, config: nil)
5
+ Module.new do
6
+ methods_to_log, payload, config_opts = DebugLogging::Util.extract_payload_and_config(
7
+ method_names: Array(methods_to_log),
8
+ payload:,
9
+ config:,
17
10
  )
18
- define_method(method_to_log) do |*args, &block|
19
- method_return_value = nil
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",
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:,
15
+ config: config_opts,
25
16
  )
26
- log_prefix = self.class.debug_invocation_to_s(
27
- klass: self.class.to_s,
28
- separator: "#",
29
- method_to_log: method_to_log,
30
- config_proxy: config_proxy,
31
- )
32
- invocation_id = self.class.debug_invocation_id_to_s(args: args, config_proxy: config_proxy)
33
- config_proxy.log do
34
- paydirt = DebugLogging::Util.payload_instance_variable_hydration(scope: self, payload: method_payload)
35
- signature = self.class.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_instance_benchmarks)
40
- tms = Benchmark.measure do
41
- method_return_value = super(*args, &block)
42
- end
17
+ define_method(method_to_log) do |*args, **kwargs, &block|
18
+ method_return_value = nil
19
+ config_proxy = DebugLogging::Util.config_proxy_finder(
20
+ scope: self.class,
21
+ config_opts: method_config_opts,
22
+ method_name: method_to_log,
23
+ proxy_ref: "ilm",
24
+ )
25
+ log_prefix = self.class.debug_invocation_to_s(
26
+ klass: self.class.to_s,
27
+ separator: "#",
28
+ method_to_log: method_to_log,
29
+ config_proxy: config_proxy,
30
+ )
31
+ invocation_id = self.class.debug_invocation_id_to_s(args:, kwargs:, config_proxy:)
43
32
  config_proxy.log do
44
- "#{log_prefix} #{self.class.debug_benchmark_to_s(tms: tms)}#{invocation_id}"
33
+ paydirt = DebugLogging::Util.payload_instance_variable_hydration(scope: self, payload: method_payload)
34
+ signature = self.class.debug_signature_to_s(args:, kwargs:, config_proxy:)
35
+ paymud = debug_payload_to_s(payload: paydirt, config_proxy:)
36
+ "#{log_prefix}#{signature}#{invocation_id} debug: #{paymud}"
45
37
  end
46
- else
47
- begin
48
- method_return_value = super(*args, &block)
49
- rescue StandardError => e
50
- if config_proxy.error_handler_proc
51
- config_proxy.error_handler_proc.call(config_proxy, e, self, method_to_log, args)
52
- else
53
- raise e
38
+ if config_proxy.benchmarkable_for?(:debug_instance_benchmarks)
39
+ tms = Benchmark.measure do
40
+ method_return_value = super(*args, **kwargs, &block)
54
41
  end
55
- end
56
- if config_proxy.exit_scope_markable? && invocation_id && !invocation_id.empty?
57
42
  config_proxy.log do
58
- "#{log_prefix} completed#{invocation_id}"
43
+ "#{log_prefix} #{self.class.debug_benchmark_to_s(tms: tms)}#{invocation_id}"
44
+ end
45
+ else
46
+ begin
47
+ method_return_value = super(*args, **kwargs, &block)
48
+ rescue StandardError => e
49
+ if config_proxy.error_handler_proc
50
+ config_proxy.error_handler_proc.call(config_proxy, e, self, method_to_log, args, kwargs)
51
+ else
52
+ raise e
53
+ end
54
+ end
55
+ if config_proxy.exit_scope_markable? && invocation_id && !invocation_id.empty?
56
+ config_proxy.log do
57
+ "#{log_prefix} completed#{invocation_id}"
58
+ end
59
59
  end
60
60
  end
61
+ method_return_value
61
62
  end
62
- method_return_value
63
63
  end
64
64
  end
65
65
  end
@@ -1,24 +1,24 @@
1
- # frozen_string_literal: true
2
-
3
1
  module DebugLogging
4
- class InstanceNotifier < Module
5
- def initialize(i_methods: nil, payload: nil, config: nil)
6
- super()
7
- @config = config
8
- @payload = payload
9
- @instance_methods_to_notify = Array(i_methods) if i_methods
10
- end
11
-
12
- def included(base)
13
- return unless @instance_methods_to_notify
14
-
15
- base.send(:include, ArgumentPrinter)
2
+ module InstanceNotifier
3
+ def i_notified(*methods_to_log)
4
+ method_names, payload, config_opts = DebugLogging::Util.extract_payload_and_config(
5
+ method_names: methods_to_log,
6
+ payload: nil,
7
+ config: nil,
8
+ )
16
9
  instance_method_notifier = DebugLogging::InstanceNotifierModulizer.to_mod(
17
- methods_to_notify: @instance_methods_to_notify,
18
- payload: @payload,
19
- config: @config,
10
+ methods_to_notify: Array(method_names),
11
+ payload: payload,
12
+ config: config_opts,
20
13
  )
21
- base.send(:prepend, instance_method_notifier)
14
+
15
+ wrapped_in_notifier = Module.new do
16
+ singleton_class.send(:define_method, :included) do |host_class|
17
+ host_class.prepend(instance_method_notifier)
18
+ end
19
+ end
20
+
21
+ send(:include, wrapped_in_notifier)
22
22
  end
23
23
  end
24
24
  end
@@ -1,51 +1,45 @@
1
- # frozen_string_literal: true
2
-
3
1
  module DebugLogging
4
2
  module InstanceNotifierModulizer
5
- def self.to_mod(methods_to_notify: nil, payload: nil, config: nil)
6
- Module.new do
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
- )
12
- Array(methods_to_notify).each do |method_to_notify|
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,
3
+ class << self
4
+ def to_mod(methods_to_notify: nil, payload: nil, config: nil)
5
+ Module.new do
6
+ methods_to_notify, payload, config_opts = DebugLogging::Util.extract_payload_and_config(
7
+ method_names: Array(methods_to_notify),
8
+ payload:,
9
+ config:,
17
10
  )
18
- define_method(method_to_notify) do |*args, &block|
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))
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:,
15
+ config: config_opts,
16
+ )
17
+ define_method(method_to_notify) do |*args, **kwargs, &block|
18
+ config_proxy = DebugLogging::Util.config_proxy_finder(
19
+ scope: self.class,
20
+ config_opts: method_config_opts,
21
+ method_name: method_to_notify,
22
+ proxy_ref: "inm",
23
+ ) do |config_proxy|
24
+ ActiveSupport::Notifications.subscribe(
25
+ DebugLogging::ArgumentPrinter.debug_event_name_to_s(method_to_notify:),
26
+ ) do |*subscribe_args|
27
+ config_proxy&.log do
28
+ DebugLogging::LogSubscriber.log_event(ActiveSupport::Notifications::Event.new(*subscribe_args))
29
+ end
30
30
  end
31
31
  end
32
- end
33
- paydirt = DebugLogging::Util.payload_instance_variable_hydration(scope: self, payload: method_payload)
34
- ActiveSupport::Notifications.instrument(
35
- DebugLogging::ArgumentPrinter.debug_event_name_to_s(method_to_notify: method_to_notify),
36
- debug_args: args,
37
- config_proxy: config_proxy,
38
- **paydirt,
39
- ) do
40
- begin
41
- # TODO: I need to split logic based on Ruby version.
42
- # TODO: Use VersionGem's minimum Ruby version check
43
- # TODO: Switch between positional, and kwargs argument handling
44
- # See: https://www.ruby-lang.org/en/news/2019/12/12/separation-of-positional-and-keyword-arguments-in-ruby-3-0/
45
- super(*args, &block)
32
+ paydirt = DebugLogging::Util.payload_instance_variable_hydration(scope: self, payload: method_payload)
33
+ ActiveSupport::Notifications.instrument(
34
+ DebugLogging::ArgumentPrinter.debug_event_name_to_s(method_to_notify:),
35
+ debug_args: kwargs.empty? ? args : args + [kwargs],
36
+ config_proxy: config_proxy,
37
+ **paydirt,
38
+ ) do
39
+ super(*args, **kwargs, &block)
46
40
  rescue StandardError => e
47
41
  if config_proxy.error_handler_proc
48
- config_proxy.error_handler_proc.call(config_proxy, e, self, method_to_notify, args)
42
+ config_proxy.error_handler_proc.call(config_proxy, e, self, method_to_notify, args, kwargs)
49
43
  else
50
44
  raise e
51
45
  end
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  require "active_support"
4
2
  require "active_support/log_subscriber"
5
3
 
@@ -14,6 +14,7 @@ module DebugLogging
14
14
  scoped_payload
15
15
  end
16
16
  config_opts = config&.clone(freeze: false) || {}
17
+ # puts "[EPAC] config: #{config}, scoped_payload: #{scoped_payload}, payload: #{payload}, config_opts: #{config_opts}"
17
18
  unless payload.empty?
18
19
  DebugLogging::Configuration::CONFIG_KEYS.each { |k| config_opts[k] = payload.delete(k) if payload.key?(k) }
19
20
  end
@@ -1,7 +1,5 @@
1
- # frozen_string_literal: true
2
-
3
1
  module DebugLogging
4
2
  module Version
5
- VERSION = "3.1.9"
3
+ VERSION = "4.0.0"
6
4
  end
7
5
  end
data/lib/debug_logging.rb CHANGED
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  # Std Lib
4
2
  require "logger"
5
3
  require "digest"
@@ -44,7 +42,8 @@ require "debug_logging/class_logger"
44
42
  #
45
43
  # # For instance methods:
46
44
  # # Option 1: specify the exact method(s) to add logging to
47
- # include DebugLogging::InstanceLogger.new(i_methods: [:drive, :stop])
45
+ # extend DebugLogging::InstanceLogger
46
+ # i_logged [:drive, :stop]
48
47
  #
49
48
  # # Provides the `logged` method decorator
50
49
  # extend DebugLogging::ClassLogger
@@ -59,7 +58,8 @@ require "debug_logging/class_logger"
59
58
  #
60
59
  # # For instance methods:
61
60
  # # Option 2: add logging to all instance methods defined above (but *not* defined below)
62
- # include DebugLogging::InstanceLogger.new(i_methods: self.instance_methods(false))
61
+ # extend DebugLogging::InstanceLogger
62
+ # i_logged instance_methods(false)
63
63
  #
64
64
  # def will_not_be_logged; false; end
65
65
  #
@@ -68,29 +68,36 @@ require "debug_logging/class_logger"
68
68
  ####################
69
69
 
70
70
  module DebugLogging
71
- def self.extended(base)
72
- base.send(:extend, ArgumentPrinter)
73
- base.send(:extend, ApiClassMethods)
74
- base.send(:extend, ConfigClassMethods)
75
- base.debug_config_reset(Configuration.new(**debug_logging_configuration.to_hash))
76
- base.class_eval do
77
- def base.inherited(subclass)
78
- subclass.debug_config_reset(Configuration.new(**debug_config.to_hash))
71
+ # We can't compare with nil to check for no arguments passed as a configuration value,
72
+ # because nil can be an argument passed, hence:
73
+ ACTUAL_NOTHING = Object.new
74
+
75
+ class << self
76
+ def extended(base)
77
+ base.send(:extend, ArgumentPrinter)
78
+ base.send(:include, ArgumentPrinter)
79
+ base.send(:extend, ApiClassMethods)
80
+ base.send(:extend, ConfigClassMethods)
81
+ base.debug_config_reset(Configuration.new(**debug_logging_configuration.to_hash))
82
+ base.class_eval do
83
+ def base.inherited(subclass)
84
+ subclass.debug_config_reset(Configuration.new(**debug_config.to_hash))
85
+ end
79
86
  end
80
87
  end
81
- end
82
88
 
83
- #### API ####
89
+ #### API ####
84
90
 
85
- # For single statement global config in an initializer
86
- # e.g. DebugLogging.configuration.ellipsis = "..."
87
- def self.configuration
88
- self.debug_logging_configuration ||= Configuration.new
89
- end
91
+ # For single statement global config in an initializer
92
+ # e.g. DebugLogging.configuration.ellipsis = "..."
93
+ def configuration
94
+ self.debug_logging_configuration ||= Configuration.new
95
+ end
90
96
 
91
- # For global config in an initializer with a block
92
- def self.configure
93
- yield(configuration)
97
+ # For global config in an initializer with a block
98
+ def configure
99
+ yield(configuration)
100
+ end
94
101
  end
95
102
 
96
103
  module ApiClassMethods
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  # Simpler version of what the sibling DebugLogging library does. Included as a bauble.
4
2
  #
5
3
  ############# THIS IS A BAUBLE
@@ -57,11 +55,11 @@ class SimpleDebugLogging < Module
57
55
  define_method(method_to_log.to_sym) do |*args|
58
56
  method_return_value = nil
59
57
  invocation_id = " ~#{args.object_id}@#{Time.now.to_i}~" if args
60
- puts "#{self}.#{method_to_log}(#{args.map(&:inspect).join(", ")})#{invocation_id}"
58
+ puts "#{self}::#{method_to_log}(#{args.map(&:inspect).join(", ")})#{invocation_id}"
61
59
  elapsed = Benchmark.realtime do
62
60
  method_return_value = original_method.call(*args)
63
61
  end
64
- puts "#{self}.#{method_to_log} ~#{args.hash}~ complete in #{elapsed}s#{invocation_id}"
62
+ puts "#{self}::#{method_to_log} ~#{args.hash}~ complete in #{elapsed}s#{invocation_id}"
65
63
  method_return_value
66
64
  end
67
65
  end
data.tar.gz.sig CHANGED
Binary file