enhanced_errors 0.1.4 → 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- 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>
|