enhanced_errors 0.1.4 → 0.1.6
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/.yardoc/checksums +2 -2
- data/.yardoc/object_types +0 -0
- data/.yardoc/objects/root.dat +0 -0
- data/README.md +57 -10
- data/benchmark/memory_bench.rb +78 -0
- data/doc/Binding.html +1 -1
- data/doc/Colors.html +1 -1
- data/doc/Debugging.html +1 -1
- data/doc/EnhancedErrors.html +197 -183
- data/doc/ErrorEnhancements.html +15 -9
- data/doc/_index.html +1 -1
- data/doc/file.README.html +42 -53
- data/doc/index.html +42 -53
- data/doc/top-level-namespace.html +38 -1
- data/enhanced_errors.gemspec +2 -2
- data/lib/enhanced_errors.rb +69 -12
- data/lib/error_enhancements.rb +7 -4
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 58869aa7d7b2b2e3fb4f983ec425c909fd231396920da0283dc53a84afd943fe
|
4
|
+
data.tar.gz: 3ec8adc214e86d163930a0500ccb869221be072469dcc99cb0ab5f6150b851e5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cd0dcfd36be230736ce342db302c01002b6ce06bc9e7eb967d5870121002707fc6d30cb25efc0f7cec101350d8b670db7b4168ca5759a8fe1940537de2b7e620
|
7
|
+
data.tar.gz: e5d1bc47e7cc8efe21627225e520a332bc48efba549eb408d1420332f510f88f8f491ff4caf3979c07c620c9a5c5423db670ba0eec32ef769f764b0a9afdab2a
|
data/.yardoc/checksums
CHANGED
@@ -1,4 +1,4 @@
|
|
1
1
|
lib/colors.rb a4314ef9531d4713907c3fea22955c943fdb8cf3
|
2
2
|
lib/binding.rb fdd7d5a2dd2edde22e3b10773510738dcdce4aeb
|
3
|
-
lib/enhanced_errors.rb
|
4
|
-
lib/error_enhancements.rb
|
3
|
+
lib/enhanced_errors.rb d12ce0629f2565e5179ae5076be8a495e19ecda2
|
4
|
+
lib/error_enhancements.rb a97d0f139d35f6e1b5bf49386271b1f4cf71761c
|
data/.yardoc/object_types
CHANGED
Binary file
|
data/.yardoc/objects/root.dat
CHANGED
Binary file
|
data/README.md
CHANGED
@@ -64,14 +64,14 @@ end
|
|
64
64
|
## Features
|
65
65
|
|
66
66
|
- **Pure Ruby**: No external dependencies, C extensions, or C API calls.
|
67
|
-
- **Lightweight**: Minimal performance impact, as tracing is only active during exception raising.
|
68
67
|
- **Customizable Output**: Supports multiple output formats (`:json`, `:plaintext`, `:terminal`).
|
69
|
-
- **Flexible Hooks**: Redact or modifying captured data via the `on_capture` hook.
|
68
|
+
- **Flexible Hooks**: Redact or modifying captured data via the `on_capture` hook. Update the final string with on_format.
|
70
69
|
- **Environment-Based Defaults**: For Rails apps, automatically adjusts settings based on the environment (`development`, `test`, `production`, `ci`).
|
71
70
|
- **Pre-Populated Skip List**: Comes with predefined skip lists to exclude irrelevant variables from being captured.
|
72
71
|
- **Capture Levels**: Supports `info` and `debug` levels, where `debug` level ignores the skip lists for more comprehensive data capture.
|
73
72
|
- **Capture Types**: Captures variables from the first `raise` and the last `rescue` for an exception by default.
|
74
73
|
- **No dependencies**: EnhancedErrors does not ___require___ any dependencies--it uses [awesome_print](https://github.com/awesome-print/awesome_print) for nicer output if it is installed and available.
|
74
|
+
- **Lightweight**: Minimal performance impact, as tracing is only active during exception raising.
|
75
75
|
|
76
76
|
EnhancedErrors has a few big use-cases:
|
77
77
|
|
@@ -79,20 +79,20 @@ EnhancedErrors has a few big use-cases:
|
|
79
79
|
You also can't just print out all the data, because it's too big. You want to know what the data was the cause of the error.
|
80
80
|
Ideally, without long instrument-re-run-fix loops. If your logging didn't capture the data, normally, you'd be stuck.
|
81
81
|
|
82
|
-
* **Debug** a complex application erroring deep in the stack when you can't tell where the error originates
|
82
|
+
* **Debug** a complex application erroring deep in the stack when you can't tell where the error originates.
|
83
83
|
|
84
|
-
* **
|
84
|
+
* **Reduce MTTR** Reduce mean time to resolution.
|
85
85
|
|
86
86
|
* **Faster CI -> Fix loop**. When a bug happens in CI, usually there's a step where you first reproduce it locally.
|
87
87
|
EnhancedErrors can help you skip that step.
|
88
88
|
|
89
|
-
* **Faster
|
89
|
+
* **Faster TDD**. In general, you can skip the add-instrumentation step and jump to the fix. Usually, you won't have to re-run to see an error.
|
90
90
|
|
91
91
|
* **Heisenbugs** - bugs that disappear when you try to debug them. EnhancedErrors can help you capture the data that causes the bug before it disappears.
|
92
92
|
|
93
93
|
* **Unknown Unknowns** - you can't pre-emptively log variables from failure cases you never imagined.
|
94
94
|
|
95
|
-
* **Cron jobs** and **daemons** - when it fails for unknown reasons at 4am, check the log and fix--it probably has what you need.
|
95
|
+
* **Cron jobs** and **daemons** - when it fails for unknown reasons at 4am, check the log and fix--it probably has what you need. Note that
|
96
96
|
|
97
97
|
## Installation
|
98
98
|
|
@@ -202,7 +202,7 @@ it yields out a hash with the structure below. Modify it as needed and return th
|
|
202
202
|
globals: globals
|
203
203
|
},
|
204
204
|
exception: exception.class.name,
|
205
|
-
|
205
|
+
capture_event: capture_event # 'raise' or 'rescue'
|
206
206
|
}
|
207
207
|
```
|
208
208
|
|
@@ -266,6 +266,26 @@ end
|
|
266
266
|
The skip list is pre-populated with common variables to exclude and can be extended based on your application's requirements.
|
267
267
|
|
268
268
|
|
269
|
+
#### Capture Rules
|
270
|
+
|
271
|
+
These exceptions are always ignored:
|
272
|
+
|
273
|
+
```ruby
|
274
|
+
SystemExit,
|
275
|
+
NoMemoryError,
|
276
|
+
SignalException,
|
277
|
+
Interrupt,
|
278
|
+
ScriptError,
|
279
|
+
LoadError,
|
280
|
+
NotImplementedError,
|
281
|
+
SyntaxError,
|
282
|
+
SystemStackError
|
283
|
+
```
|
284
|
+
|
285
|
+
While this is close to "Things that don't descend from StandardError", it's not exactly that.
|
286
|
+
|
287
|
+
In Info mode, variables starting with @_ are also ignored.
|
288
|
+
|
269
289
|
|
270
290
|
### Capture Levels
|
271
291
|
|
@@ -316,7 +336,7 @@ When an exception is raised or rescued, it captures:
|
|
316
336
|
- **Let Variables**: RSpec let variables, if applicable. Only memoized (evaluated) let variables are captured.
|
317
337
|
- **Global Variables**: Global variables, in debug mode.
|
318
338
|
|
319
|
-
The captured data includes a `
|
339
|
+
The captured data includes a `capture_event` field indicating whether the data was captured during a `raise` or `rescue` event. By default, EnhancedErrors returns the first `raise` and the last `rescue` event for each exception, providing a clear trace of the exception lifecycle.
|
320
340
|
|
321
341
|
The captured data is then appended to the exception's message, providing rich context for debugging.
|
322
342
|
|
@@ -333,11 +353,38 @@ if you want to use it.
|
|
333
353
|
gem 'awesome_print'
|
334
354
|
```
|
335
355
|
|
356
|
+
## Alternatives
|
357
|
+
|
358
|
+
Why not use:
|
359
|
+
|
360
|
+
[binding_of_caller](https://github.com/banister/binding_of_caller) or [Pry](https://github.com/pry/pry) or [better_errors](https://github.com/BetterErrors/better_errors)?
|
361
|
+
|
362
|
+
First off, these gems are, I cannot stress this enough, a-m-a-z-i-n-g!!! I use them every day--kudos to their creators and maintainers!
|
363
|
+
|
364
|
+
This is intended for different use-cases. In sum, the goal of this gem is an every-day driver for __non-interactive__ variable inspection.
|
365
|
+
|
366
|
+
With EnhancedErrors is that I want extra details when I run into a problem I __didn't anticipate ahead of time__.
|
367
|
+
To make that work, it has to be able to safely be 'on' all the time, and it has to gather the data in
|
368
|
+
a way I naturally will see it without requiring extra preparation I obviously didn't know to do.
|
369
|
+
|
370
|
+
- That won't interrupt CI, but also, that lets me know what happened without reproduction
|
371
|
+
- That could, theoretically, also be fine in production (if data security, redaction, access, and encryption concerns were all addressed--Ok, big
|
372
|
+
list, but another option is to selectively enable targeted capture)
|
373
|
+
- Has decent performance characteristics
|
374
|
+
- **Only** becomes active in exception raise/rescue scenarios
|
375
|
+
|
376
|
+
This gem could have been implemented using binding_of_caller, or the gem it depends on, [debug_inspector](https://rubygems.org/gems/debug_inspector/versions/1.1.0?locale=en).
|
377
|
+
However, the recommendation is not to use those in production as they use C API extensions. This doesn't. This selectively uses
|
378
|
+
Ruby's TracePoint binding capture very narrowly with no other C API or dependencies, and only to target Exceptions--not to allow universal calls to the prior binding. It doesn't work as a debugger, but that also means it can, with care, operate safely in a narrow scope--becoming active only when exceptions are raised.
|
379
|
+
|
336
380
|
|
337
381
|
## Performance Considerations
|
338
382
|
|
339
|
-
- **Minimal Overhead**: Since TracePoint is only activated during exception raising and rescuing, the performance impact is negligible during normal operation.
|
340
|
-
|
383
|
+
- **Minimal Overhead**: Since TracePoint is only activated during exception raising and rescuing, the performance impact is negligible during normal operation. (Benchmark included)
|
384
|
+
|
385
|
+
- **TBD**: Memory considerations. This does capture data when an exception happens. EnhancedErrors hides under the bed when it sees **NoMemoryError**.
|
386
|
+
|
387
|
+
- **Goal: Production Safety**: The gem is designed to, once vetted, be safe for production use, giving you valuable insights without compromising performance. I suggest letting it get well-vetted before making the leap and testing it for both performance and memory under load internally, as well.
|
341
388
|
|
342
389
|
## Contributing
|
343
390
|
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# benchmark_tracepoint.rb
|
2
|
+
|
3
|
+
def memory_usage
|
4
|
+
pid = Process.pid
|
5
|
+
`ps -o rss= -p #{pid}`.to_i # Returns memory usage in KB
|
6
|
+
end
|
7
|
+
|
8
|
+
# Generate a 100 MB string outside the iterations
|
9
|
+
large_string = 'a' * 10_000_000 # 10 million characters
|
10
|
+
|
11
|
+
def test_with_tracepoint(iterations, large_string)
|
12
|
+
puts "\nTest with TracePoint capturing bindings:"
|
13
|
+
captured_bindings = []
|
14
|
+
|
15
|
+
trace = TracePoint.new(:raise) do |tp|
|
16
|
+
captured_bindings << tp.binding
|
17
|
+
end
|
18
|
+
|
19
|
+
trace.enable
|
20
|
+
|
21
|
+
puts "Memory usage before exceptions: #{memory_usage} KB"
|
22
|
+
|
23
|
+
iterations.times do
|
24
|
+
begin
|
25
|
+
# Use the large string within the local scope
|
26
|
+
local_large_string = large_string
|
27
|
+
raise 'Test exception'
|
28
|
+
rescue => e
|
29
|
+
raise e rescue nil # Suppress the exception to continue the loop
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
puts "Memory usage after exceptions: #{memory_usage} KB"
|
34
|
+
|
35
|
+
trace.disable
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_without_tracepoint(iterations, large_string)
|
39
|
+
puts "\nTest without TracePoint capturing bindings:"
|
40
|
+
|
41
|
+
puts "Memory usage before exceptions: #{memory_usage} KB"
|
42
|
+
|
43
|
+
iterations.times do
|
44
|
+
begin
|
45
|
+
# Use the large string within the local scope
|
46
|
+
local_large_string = large_string
|
47
|
+
raise 'Test exception'
|
48
|
+
rescue => e
|
49
|
+
raise e rescue nil
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
puts "Memory usage after exceptions: #{memory_usage} KB"
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_exception_with_large_variable(iterations, large_string)
|
57
|
+
puts "\nTest with exceptions storing large variable:"
|
58
|
+
|
59
|
+
puts "Memory usage before exceptions: #{memory_usage} KB"
|
60
|
+
|
61
|
+
iterations.times do
|
62
|
+
begin
|
63
|
+
raise 'Test exception'
|
64
|
+
rescue => e
|
65
|
+
# Store a reference to the large string in the exception
|
66
|
+
e.instance_variable_set(:@large_string, large_string)
|
67
|
+
raise e rescue nil
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
puts "Memory usage after exceptions: #{memory_usage} KB"
|
72
|
+
end
|
73
|
+
|
74
|
+
iterations = 10 # Adjust iterations as needed
|
75
|
+
|
76
|
+
test_with_tracepoint(iterations, large_string)
|
77
|
+
test_without_tracepoint(iterations, large_string)
|
78
|
+
test_exception_with_large_variable(iterations, large_string)
|
data/doc/Binding.html
CHANGED
@@ -127,7 +127,7 @@
|
|
127
127
|
</div>
|
128
128
|
|
129
129
|
<div id="footer">
|
130
|
-
Generated on
|
130
|
+
Generated on Sun Nov 10 12:01:14 2024 by
|
131
131
|
<a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
132
132
|
0.9.37 (ruby-3.1.3).
|
133
133
|
</div>
|
data/doc/Colors.html
CHANGED
@@ -374,7 +374,7 @@
|
|
374
374
|
</div>
|
375
375
|
|
376
376
|
<div id="footer">
|
377
|
-
Generated on
|
377
|
+
Generated on Sun Nov 10 12:01:14 2024 by
|
378
378
|
<a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
379
379
|
0.9.37 (ruby-3.1.3).
|
380
380
|
</div>
|
data/doc/Debugging.html
CHANGED
@@ -171,7 +171,7 @@
|
|
171
171
|
</div>
|
172
172
|
|
173
173
|
<div id="footer">
|
174
|
-
Generated on
|
174
|
+
Generated on Sun Nov 10 12:01:14 2024 by
|
175
175
|
<a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
176
176
|
0.9.37 (ruby-3.1.3).
|
177
177
|
</div>
|