debug_logging 3.1.2 → 3.1.8

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: 12a45427d0ca5aea996bd2ddce9da4ae3f763afe2e5b0abefea2173f6765ff61
4
+ data.tar.gz: 1a9d1a08b5f49daaa6f01c10c48b3a5345794a46f9b62f25243f13e6ebacd694
5
5
  SHA512:
6
- metadata.gz: 5af7096cfbadcea5695cc19bdce85e4d6ac8eecf02139378cb2dc0d734d99011bc49ff239fe1d816ce9570a883b75b4f6e0772fdfbf7feda147e7890c56d415a
7
- data.tar.gz: f471d3858ad20c1d3347b4ce328254c01572da54fd0e566ccbf6b15827996c561cf86c5fcb23f14ad127d5a9449b045c63281768c082b2375d754e566f3d4561
6
+ metadata.gz: f55f81ffe673ec404dd49fc26db2778abf3311a3f7f148a85c5030369cb469b8570c8728db5526b838caf2e09b22e04ad314ab27c462b8b246905e00945b2d9a
7
+ data.tar.gz: c5bc397f5b50d19551d7db9b6d7fe9cafa034ff36cbac2551d9c2a52d0e9a9f70992d0efb49a46fabf6830f76818b15eaf6653be9fee38aad415af9d2f92510a
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,16 @@ 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.1.3*
41
+ * *Optional instance, and class-instance, variable logging, since v3.1.3*
42
+ * *ActiveRecord style callback-hooks (optional: `require 'debug_logging/hooks'` and `include DebugLogging::Hooks`), since v3.1.3*
43
+ * *All configuration is inheritable to, and overridable by, child classes, since v3.1.3*
44
+ * *[Class finalization hook](https://stackoverflow.com/a/34559282) (optional: `require 'debug_logging/finalize'` and `extend DebugLogging::Finalize`), since v3.1.3*
45
+ * *Error handling hooks you can use to log problems when they happen, since v3.1.7*
41
46
  * **so many free ponies** 🎠🐴🎠🐴🎠🐴
42
47
 
43
48
  ## Next Level Magic
@@ -46,8 +51,10 @@ Herein you will find:
46
51
 
47
52
  * Classes inheriting from Module
48
53
  * Zero tolerance policy on monkey patching
54
+ * When the gem is loaded there are no monkey patches.
55
+ * Rather, your own classes/methods get "patched" and "hooked" as you configure them.
49
56
  * 100% clean, 0% obtrusive
50
- * 100% tested
57
+ * ~100% tested
51
58
  * 100% Ruby 2.1+ compatible
52
59
  - use version `gem "debug_logging", "~> 1.0"` for Ruby < 2.3
53
60
  - use version `gem "debug_logging", "~> 2.0"` for Ruby 2.3
@@ -91,6 +98,7 @@ DebugLogging.configuration.log_level = :debug # at what level do the messages cr
91
98
  DebugLogging.configuration.multiple_last_hashes = false # pass every hash argument to last_hash_to_s_proc?
92
99
  DebugLogging.configuration.last_hash_to_s_proc = nil # e.g. ->(hash) { "keys: #{hash.keys}" }
93
100
  DebugLogging.configuration.last_hash_max_length = 1_000
101
+ DebugLogging.configuration.args_to_s_proc = nil # e.g. ->(record) { "record id: #{record.id}" }
94
102
  DebugLogging.configuration.args_max_length = 1_000
95
103
  DebugLogging.configuration.instance_benchmarks = false
96
104
  DebugLogging.configuration.class_benchmarks = false
@@ -100,6 +108,9 @@ DebugLogging.configuration.colorized_chain_for_class = false # e.g. ->(colorized
100
108
  DebugLogging.configuration.add_invocation_id = true # identify a method call uniquely in a log, pass a proc for colorization, e.g. ->(colorized_string) { colorized_string.light_black }
101
109
  DebugLogging.configuration.ellipsis = ' ✂️ …'.freeze
102
110
  DebugLogging.configuration.mark_scope_exit = true # Only has an effect if benchmarking is off, since benchmarking always marks the scope exit
111
+ DebugLogging.configuration.add_payload = false # or a proc which will be called to print the payload
112
+ DebugLogging.configuration.payload_max_length = 1000
113
+ DebugLogging.configuration.error_handler_proc = nil # e.g. ->(error, config, obj, method_name, args) { config.log { "#{error.class}: #{error.message} in #{method_name}\nargs: #{args.inspect}" } }
103
114
  ```
104
115
 
105
116
  If you prefer to use the block style:
@@ -111,6 +122,7 @@ DebugLogging.configure do |config|
111
122
  config.multiple_last_hashes = false # pass every hash argument to last_hash_to_s_proc?
112
123
  config.last_hash_to_s_proc = nil # e.g. ->(hash) { "keys: #{hash.keys}" }
113
124
  config.last_hash_max_length = 1_000
125
+ config.args_to_s_proc = nil # e.g. ->(record) { "record id: #{record.id}" }
114
126
  config.args_max_length = 1_000
115
127
  config.instance_benchmarks = false
116
128
  config.class_benchmarks = false
@@ -120,6 +132,9 @@ DebugLogging.configure do |config|
120
132
  config.add_invocation_id = true # identify a method call uniquely in a log, pass a proc for colorization, e.g. ->(colorized_string) { colorized_string.light_black }
121
133
  config.ellipsis = ' ✂️ …'.freeze
122
134
  config.mark_scope_exit = true # Only has an effect if benchmarking is off, since benchmarking always marks the scope exit
135
+ config.add_payload = false # or a proc which will be called to print the payload
136
+ config.payload_max_length = 1000
137
+ config.error_handler_proc = nil # e.g. ->(error, config, obj, method_name, args) { config.log { "#{error.class}: #{error.message} in #{method_name}\nargs: #{args.inspect}" } }
123
138
  end
124
139
  ```
125
140
 
@@ -381,6 +396,10 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
381
396
  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
382
397
  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
383
398
 
399
+ ### License Exceptions
400
+
401
+ * [`debug_logging/finalize`](https://stackoverflow.com/a/34559282) is licensed under https://creativecommons.org/licenses/by-sa/4.0/
402
+
384
403
  [semver]: http://semver.org/
385
404
  [pvc]: http://docs.rubygems.org/read/chapter/16#page74
386
405
  [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'
@@ -4,9 +4,14 @@ require 'logger'
4
4
  require 'colorized_string'
5
5
  require 'digest'
6
6
 
7
+ require 'debug_logging/constants'
7
8
  require 'debug_logging/version'
9
+ require 'debug_logging/errors'
8
10
  require 'debug_logging/configuration'
11
+ require 'debug_logging/util'
12
+ require 'debug_logging/finalize'
9
13
  require 'debug_logging/argument_printer'
14
+ require 'debug_logging/hooks'
10
15
  require 'debug_logging/instance_logger_modulizer'
11
16
  require 'debug_logging/instance_logger'
12
17
  require 'debug_logging/class_logger'
@@ -60,26 +65,17 @@ require 'debug_logging/class_logger'
60
65
  module DebugLogging
61
66
  def self.extended(base)
62
67
  base.send(:extend, ArgumentPrinter)
68
+ base.send(:extend, ApiClassMethods)
69
+ base.send(:extend, ConfigClassMethods)
63
70
  base.debug_config_reset(Configuration.new(**debug_logging_configuration.to_hash))
71
+ base.class_eval do
72
+ def base.inherited(subclass)
73
+ subclass.debug_config_reset(Configuration.new(**debug_config.to_hash))
74
+ end
75
+ end
64
76
  end
65
77
 
66
78
  #### API ####
67
- # Not used by this gem internally, but provides an external interface for
68
- # classes to also use this logging tool directly,
69
- # with configured options like benchmarking, colors, or leg level.
70
- def debug_log(message = nil, config_proxy = nil, &block)
71
- # If a, instance-method-level, or class-method-level custom config is not
72
- # passed in, then fall back to the class' default config, which is a
73
- # potentially customized copy of the default config for the whole app.
74
- config_proxy ||= debug_config
75
- config_proxy.log(message, &block)
76
- end
77
-
78
- # There are times when the class will need access to the configuration object,
79
- # such as to override it per instance method
80
- def debug_config
81
- @debug_logging_configuration
82
- end
83
79
 
84
80
  # For single statement global config in an initializer
85
81
  # e.g. DebugLogging.configuration.ellipsis = "..."
@@ -92,130 +88,187 @@ module DebugLogging
92
88
  yield(configuration)
93
89
  end
94
90
 
95
- # For per-class config with a block
96
- def debug_logging_configure
97
- @debug_logging_configuration ||= Configuration.new
98
- yield(@debug_logging_configuration)
91
+ module ApiClassMethods
92
+ # Not used by this gem internally, but provides an external interface for
93
+ # classes to also use this logging tool directly,
94
+ # with configured options like benchmarking, colors, or leg level.
95
+ def debug_log(message = nil, config_proxy = nil, &block)
96
+ # If a, instance-method-level, or class-method-level custom config is not
97
+ # passed in, then fall back to the class' default config, which is a
98
+ # potentially customized copy of the default config for the whole app.
99
+ config_proxy ||= debug_config
100
+ config_proxy.log(message, &block)
101
+ end
102
+
103
+ # There are times when the class will need access to the configuration object,
104
+ # such as to override it per instance method
105
+ def debug_config
106
+ @debug_logging_configuration
107
+ end
99
108
  end
100
109
 
101
110
  #### CONFIG ####
102
111
  class << self
103
112
  attr_accessor :debug_logging_configuration
104
113
  end
105
- def debug_config_reset(config = Configuration.new)
106
- @debug_logging_configuration = config
107
- end
108
114
 
109
- def debug_enabled
110
- @debug_logging_configuration.enabled
111
- end
115
+ module ConfigClassMethods
116
+ include Constants
112
117
 
113
- def debug_enabled=(value)
114
- @debug_logging_configuration.enabled = value
115
- end
118
+ # For per-class config with a block
119
+ def debug_logging_configure
120
+ @debug_logging_configuration ||= Configuration.new
121
+ yield(@debug_logging_configuration)
122
+ end
116
123
 
117
- def debug_logger
118
- @debug_logging_configuration.logger
119
- end
124
+ def debug_config_reset(config = Configuration.new)
125
+ @debug_logging_configuration = config
126
+ end
120
127
 
121
- def debug_logger=(logger)
122
- @debug_logging_configuration.logger = logger
123
- end
128
+ def debug_enabled
129
+ @debug_logging_configuration.enabled
130
+ end
124
131
 
125
- def debug_log_level
126
- @debug_logging_configuration.log_level
127
- end
132
+ def debug_enabled=(value)
133
+ @debug_logging_configuration.enabled = value
134
+ end
128
135
 
129
- def debug_log_level=(log_level)
130
- @debug_logging_configuration.log_level = log_level
131
- end
136
+ def debug_logger
137
+ @debug_logging_configuration.logger
138
+ end
132
139
 
133
- def debug_multiple_last_hashes
134
- @debug_logging_configuration.multiple_last_hashes
135
- end
140
+ def debug_logger=(logger)
141
+ @debug_logging_configuration.logger = logger
142
+ end
136
143
 
137
- def debug_multiple_last_hashes=(multiple_last_hashes)
138
- @debug_logging_configuration.multiple_last_hashes = multiple_last_hashes
139
- end
144
+ def debug_log_level
145
+ @debug_logging_configuration.log_level
146
+ end
140
147
 
141
- def debug_last_hash_to_s_proc
142
- @debug_logging_configuration.last_hash_to_s_proc
143
- end
148
+ def debug_log_level=(log_level)
149
+ @debug_logging_configuration.log_level = log_level
150
+ end
144
151
 
145
- def debug_last_hash_to_s_proc=(last_hash_to_s_proc)
146
- @debug_logging_configuration.last_hash_to_s_proc = last_hash_to_s_proc
147
- end
152
+ def debug_multiple_last_hashes
153
+ @debug_logging_configuration.multiple_last_hashes
154
+ end
148
155
 
149
- def debug_last_hash_max_length
150
- @debug_logging_configuration.last_hash_max_length
151
- end
156
+ def debug_multiple_last_hashes=(multiple_last_hashes)
157
+ @debug_logging_configuration.multiple_last_hashes = multiple_last_hashes
158
+ end
152
159
 
153
- def debug_last_hash_max_length=(last_hash_max_length)
154
- @debug_logging_configuration.last_hash_max_length = last_hash_max_length
155
- end
160
+ def debug_last_hash_to_s_proc
161
+ @debug_logging_configuration.last_hash_to_s_proc
162
+ end
156
163
 
157
- def debug_args_max_length
158
- @debug_logging_configuration.args_max_length
159
- end
164
+ def debug_last_hash_to_s_proc=(last_hash_to_s_proc)
165
+ @debug_logging_configuration.last_hash_to_s_proc = last_hash_to_s_proc
166
+ end
160
167
 
161
- def debug_args_max_length=(args_max_length)
162
- @debug_logging_configuration.args_max_length = args_max_length
163
- end
168
+ def debug_last_hash_max_length
169
+ @debug_logging_configuration.last_hash_max_length
170
+ end
164
171
 
165
- def debug_instance_benchmarks
166
- @debug_logging_configuration.instance_benchmarks
167
- end
172
+ def debug_last_hash_max_length=(last_hash_max_length)
173
+ @debug_logging_configuration.last_hash_max_length = last_hash_max_length
174
+ end
168
175
 
169
- def debug_instance_benchmarks=(instance_benchmarks)
170
- @debug_logging_configuration.instance_benchmarks = instance_benchmarks
171
- end
176
+ def debug_args_to_s_proc
177
+ @debug_logging_configuration.args_to_s_proc
178
+ end
172
179
 
173
- def debug_class_benchmarks
174
- @debug_logging_configuration.class_benchmarks
175
- end
180
+ def debug_args_to_s_proc=(args_to_s_proc)
181
+ @debug_logging_configuration.args_to_s_proc = args_to_s_proc
182
+ end
176
183
 
177
- def debug_class_benchmarks=(class_benchmarks)
178
- @debug_logging_configuration.class_benchmarks = class_benchmarks
179
- end
184
+ def debug_args_max_length
185
+ @debug_logging_configuration.args_max_length
186
+ end
180
187
 
181
- def debug_colorized_chain_for_method
182
- @debug_logging_configuration.colorized_chain_for_method
183
- end
188
+ def debug_args_max_length=(args_max_length)
189
+ @debug_logging_configuration.args_max_length = args_max_length
190
+ end
184
191
 
185
- def debug_colorized_chain_for_method=(colorized_chain_for_method)
186
- @debug_logging_configuration.colorized_chain_for_method = colorized_chain_for_method
187
- end
192
+ def debug_instance_benchmarks
193
+ @debug_logging_configuration.instance_benchmarks
194
+ end
188
195
 
189
- def debug_colorized_chain_for_class
190
- @debug_logging_configuration.colorized_chain_for_class
191
- end
196
+ def debug_instance_benchmarks=(instance_benchmarks)
197
+ @debug_logging_configuration.instance_benchmarks = instance_benchmarks
198
+ end
192
199
 
193
- def debug_colorized_chain_for_class=(colorized_chain_for_class)
194
- @debug_logging_configuration.colorized_chain_for_class = colorized_chain_for_class
195
- end
200
+ def debug_class_benchmarks
201
+ @debug_logging_configuration.class_benchmarks
202
+ end
196
203
 
197
- def debug_add_invocation_id
198
- @debug_logging_configuration.add_invocation_id
199
- end
204
+ def debug_class_benchmarks=(class_benchmarks)
205
+ @debug_logging_configuration.class_benchmarks = class_benchmarks
206
+ end
200
207
 
201
- def debug_add_invocation_id=(add_invocation_id)
202
- @debug_logging_configuration.add_invocation_id = add_invocation_id
203
- end
208
+ def debug_colorized_chain_for_method
209
+ @debug_logging_configuration.colorized_chain_for_method
210
+ end
204
211
 
205
- def debug_mark_scope_exit
206
- @debug_logging_configuration.mark_scope_exit
207
- end
212
+ def debug_colorized_chain_for_method=(colorized_chain_for_method)
213
+ @debug_logging_configuration.colorized_chain_for_method = colorized_chain_for_method
214
+ end
208
215
 
209
- def debug_mark_scope_exit=(mark_scope_exit)
210
- @debug_logging_configuration.mark_scope_exit = mark_scope_exit
211
- end
216
+ def debug_colorized_chain_for_class
217
+ @debug_logging_configuration.colorized_chain_for_class
218
+ end
212
219
 
213
- def debug_ellipsis
214
- @debug_logging_configuration.ellipsis
215
- end
220
+ def debug_colorized_chain_for_class=(colorized_chain_for_class)
221
+ @debug_logging_configuration.colorized_chain_for_class = colorized_chain_for_class
222
+ end
223
+
224
+ def debug_add_invocation_id
225
+ @debug_logging_configuration.add_invocation_id
226
+ end
216
227
 
217
- def debug_ellipsis=(ellipsis)
218
- @debug_logging_configuration.ellipsis = ellipsis
228
+ def debug_add_invocation_id=(add_invocation_id)
229
+ @debug_logging_configuration.add_invocation_id = add_invocation_id
230
+ end
231
+
232
+ def debug_ellipsis
233
+ @debug_logging_configuration.ellipsis
234
+ end
235
+
236
+ def debug_ellipsis=(ellipsis)
237
+ @debug_logging_configuration.ellipsis = ellipsis
238
+ end
239
+
240
+ def debug_mark_scope_exit
241
+ @debug_logging_configuration.mark_scope_exit
242
+ end
243
+
244
+ def debug_mark_scope_exit=(mark_scope_exit)
245
+ @debug_logging_configuration.mark_scope_exit = mark_scope_exit
246
+ end
247
+
248
+ def debug_add_payload
249
+ @debug_logging_configuration.add_payload
250
+ end
251
+
252
+ def debug_add_payload=(add_payload)
253
+ @debug_logging_configuration.add_payload = add_payload
254
+ end
255
+
256
+ def debug_payload_max_length
257
+ @debug_logging_configuration.payload_max_length
258
+ end
259
+
260
+ def debug_payload_max_length=(payload_max_length)
261
+ @debug_logging_configuration.payload_max_length = payload_max_length
262
+ end
263
+
264
+ def debug_error_handler_proc
265
+ @debug_logging_configuration.error_handler_proc
266
+ end
267
+
268
+ def debug_error_handler_proc=(error_handler_proc)
269
+ @debug_logging_configuration.error_handler_proc = error_handler_proc
270
+ end
219
271
  end
272
+
220
273
  self.debug_logging_configuration = Configuration.new # setup defaults
221
274
  end
@@ -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
 
@@ -45,49 +45,90 @@ module DebugLogging
45
45
 
46
46
  add_args_ellipsis = false
47
47
  if config_proxy.debug_last_hash_to_s_proc && args[-1].is_a?(Hash)
48
- add_last_hash_ellipsis = false
48
+ add_other_args_ellipsis = false
49
49
  if args.length > 1
50
50
  if config_proxy.debug_multiple_last_hashes
51
51
  last_hash_args, other_args = args.partition do |arg|
52
52
  arg.is_a?(Hash)
53
53
  end
54
- other_args_string = other_args.map(&:inspect).join(', ')[0..(config_proxy.debug_args_max_length)]
54
+ other_args_string = if config_proxy.debug_args_to_s_proc
55
+ printed, add_other_args_ellipsis = debug_safe_proc(
56
+ proc_name:'args_to_s_proc',
57
+ proc: config_proxy.debug_args_to_s_proc,
58
+ args: other_args,
59
+ max_length: config_proxy.debug_args_max_length
60
+ )
61
+ printed
62
+ else
63
+ other_args.map(&:inspect).join(', ').tap do |x|
64
+ add_other_args_ellipsis = x.length > config_proxy.debug_args_max_length
65
+ end[0..(config_proxy.debug_args_max_length)]
66
+ end
67
+ other_args_string += config_proxy.debug_ellipsis if add_other_args_ellipsis
55
68
  # On the debug_multiple_last_hashes truthy branch we don't print the ellipsis after regular args
56
- # because it will go instead after the last hash (if needed)
69
+ # because it will go instead after each of the last hashes (if needed)
57
70
  # ...join(", ").tap {|x| _add_args_ellipsis = x.length > config_proxy.debug_args_max_length}
58
71
  last_hash_args_string = last_hash_args.map do |arg|
59
72
  arr = []
60
- arr << config_proxy.debug_last_hash_to_s_proc.call(arg).to_s
61
- .tap do |x|
62
- add_last_hash_ellipsis = x.length > config_proxy.debug_last_hash_max_length
63
- end
64
- if add_last_hash_ellipsis
65
- arr[-1] = arr[-1][0..(config_proxy.debug_last_hash_max_length)]
66
- arr << config_proxy.debug_ellipsis
67
- end
73
+ printed, add_last_hash_ellipsis = debug_safe_proc(
74
+ proc_name:'last_hash_to_s_proc',
75
+ proc: config_proxy.debug_last_hash_to_s_proc,
76
+ args: arg,
77
+ max_length: config_proxy.debug_last_hash_max_length
78
+ )
79
+ printed += config_proxy.debug_ellipsis if add_last_hash_ellipsis
80
+ arr << printed
68
81
  arr
69
82
  end.flatten.join(', ')
70
83
  printed_args += other_args_string if other_args_string
71
84
  printed_args += ', ' if !other_args_string.empty? && !last_hash_args_string.empty?
72
85
  printed_args += last_hash_args_string if last_hash_args_string && !last_hash_args_string.empty?
73
86
  else
74
- printed_args += args[0..-2].map(&:inspect).join(', ').tap do |x|
75
- add_args_ellipsis = x.length > config_proxy.debug_args_max_length
76
- end [0..(config_proxy.debug_args_max_length)]
77
- printed_args += config_proxy.debug_ellipsis if add_args_ellipsis
78
- printed_args += ", #{config_proxy.debug_last_hash_to_s_proc.call(args[-1]).tap do |x|
79
- add_last_hash_ellipsis = x.length > config_proxy.debug_last_hash_max_length
80
- end [0..(config_proxy.debug_last_hash_max_length)]}"
87
+ other_args = args[0..-2]
88
+ other_args_string = if config_proxy.debug_args_to_s_proc
89
+ printed, add_other_args_ellipsis = debug_safe_proc(
90
+ proc_name:'args_to_s_proc',
91
+ proc: config_proxy.debug_args_to_s_proc,
92
+ args: other_args,
93
+ max_length: config_proxy.debug_args_max_length
94
+ )
95
+ printed
96
+ else
97
+ other_args.map(&:inspect).join(', ').tap do |x|
98
+ add_other_args_ellipsis = x.length > config_proxy.debug_args_max_length
99
+ end[0..(config_proxy.debug_args_max_length)]
100
+ end
101
+ other_args_string += config_proxy.debug_ellipsis if add_other_args_ellipsis
102
+ printed_args += other_args_string
103
+ printed, add_last_hash_ellipsis = debug_safe_proc(
104
+ proc_name:'last_hash_to_s_proc',
105
+ proc: config_proxy.debug_last_hash_to_s_proc,
106
+ args: args[-1],
107
+ max_length: config_proxy.debug_last_hash_max_length
108
+ )
109
+ printed_args += ", #{printed}"
81
110
  printed_args += config_proxy.debug_ellipsis if add_last_hash_ellipsis
82
111
  end
83
112
  else
84
- printed_args += String(config_proxy.debug_last_hash_to_s_proc.call(args[0])).tap do |x|
85
- add_last_hash_ellipsis = x.length > config_proxy.debug_last_hash_max_length
86
- end [0..(config_proxy.debug_last_hash_max_length)]
113
+ printed, add_last_hash_ellipsis = debug_safe_proc(
114
+ proc_name:'last_hash_to_s_proc',
115
+ proc: config_proxy.debug_last_hash_to_s_proc,
116
+ args: args[0],
117
+ max_length: config_proxy.debug_last_hash_max_length
118
+ )
119
+ printed_args += printed
87
120
  printed_args += config_proxy.debug_ellipsis if add_last_hash_ellipsis
88
121
  end
89
122
  else
90
- printed_args += if args.length == 1 && args[0].is_a?(Hash)
123
+ printed_args += if config_proxy.debug_args_to_s_proc
124
+ printed, add_args_ellipsis = debug_safe_proc(
125
+ proc_name:'args_to_s_proc',
126
+ proc: config_proxy.debug_args_to_s_proc,
127
+ args: args,
128
+ max_length: config_proxy.debug_args_max_length
129
+ )
130
+ printed
131
+ elsif args.length == 1 && args[0].is_a?(Hash)
91
132
  # handle double splat
92
133
  ("**#{args.map(&:inspect).join(', ').tap do |x|
93
134
  add_args_ellipsis = x.length > config_proxy.debug_args_max_length
@@ -95,13 +136,26 @@ module DebugLogging
95
136
  else
96
137
  args.map(&:inspect).join(', ').tap do |x|
97
138
  add_args_ellipsis = x.length > config_proxy.debug_args_max_length
98
- end [0..(config_proxy.debug_args_max_length)]
139
+ end[0..(config_proxy.debug_args_max_length)]
99
140
  end
100
141
  printed_args += config_proxy.debug_ellipsis if add_args_ellipsis
101
142
  end
102
143
  "(#{printed_args})"
103
144
  end
104
145
 
146
+ def debug_safe_proc(proc_name:, proc:, args:, max_length:)
147
+ max_length ||= 1000 # can't be nil
148
+ begin
149
+ add_ellipsis = false
150
+ printed = String(proc.call(args)).tap do |x|
151
+ add_ellipsis = x.length > max_length
152
+ end[0..(max_length)]
153
+ return printed, add_ellipsis
154
+ rescue => e
155
+ return "#{e.class}: #{e.message}\nPlease check that your #{proc_name} is able to handle #{args}", false
156
+ end
157
+ end
158
+
105
159
  def debug_payload_to_s(payload: nil, config_proxy: nil)
106
160
  return '' unless payload && config_proxy
107
161
 
@@ -110,7 +164,16 @@ module DebugLogging
110
164
  when true
111
165
  payload.inspect
112
166
  else
113
- config_proxy.debug_add_payload.call(**payload)
167
+ printed_payload = ""
168
+ printed, add_payload_ellipsis = debug_safe_proc(
169
+ proc_name: "add_payload",
170
+ proc: config_proxy.debug_add_payload,
171
+ args: payload,
172
+ max_length: config_proxy.payload_max_length
173
+ )
174
+ printed_payload += printed
175
+ printed_payload += config_proxy.debug_ellipsis if add_payload_ellipsis
176
+ printed_payload
114
177
  end
115
178
  else
116
179
  ''