backtrace_shortener 0.1.0
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.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/README.markdown +119 -0
- data/Rakefile +1 -0
- data/backtrace_shortener.gemspec +19 -0
- data/lib/backtrace_shortener.rb +72 -0
- data/lib/backtrace_shortener/version.rb +3 -0
- metadata +74 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.markdown
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
bactrace_shortener
|
2
|
+
------------------
|
3
|
+
|
4
|
+
This shortens the backtraces of exceptions to make debugging more friendly. Exceptions which are thrown in
|
5
|
+
Ruby apps which use rbenv and gems like Sinatra can be taller than one terminal screen, and each line can be
|
6
|
+
long. See below for an example of the pain. Shortening these backtraces makes debugging more friendly.
|
7
|
+
|
8
|
+
I use this in many projects, so it's now packaged as a gem.
|
9
|
+
|
10
|
+
Usage
|
11
|
+
-----
|
12
|
+
|
13
|
+
$ gem install backtrace_shortener
|
14
|
+
|
15
|
+
(or you can just take backtrace_shortener.rb and copy it to your project. It's short.)
|
16
|
+
|
17
|
+
In your code:
|
18
|
+
|
19
|
+
require "backtrace_shortener"
|
20
|
+
BacktraceShortener.monkey_patch_the_exception_class!
|
21
|
+
|
22
|
+
Features
|
23
|
+
--------
|
24
|
+
|
25
|
+
With backtrace_shortener enabled, an unwieldy exception backtrace which previously looked like this:
|
26
|
+
|
27
|
+
RuntimeError: It's no good, I can't maneuver!
|
28
|
+
/Users/philc/api_server/server.rb:86:in `block in <class:ServerRoot>'
|
29
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:1212:in `call'
|
30
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:1212:in `block in compile!'
|
31
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:785:in `[]'
|
32
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:785:in `block (3 levels) in route!'
|
33
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:801:in `route_eval'
|
34
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:785:in `block (2 levels) in route!'
|
35
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:822:in `block in process_route'
|
36
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:820:in `catch'
|
37
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:820:in `process_route'
|
38
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:784:in `block in route!'
|
39
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:783:in `each'
|
40
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:783:in `route!'
|
41
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:886:in `dispatch!'
|
42
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:719:in `block in call!'
|
43
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:871:in `block in invoke'
|
44
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:871:in `catch'
|
45
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:871:in `invoke'
|
46
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:719:in `call!'
|
47
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:705:in `call'
|
48
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/rack-protection-1.2.0/lib/rack/protection/xss_header.rb:22:in `call'
|
49
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/rack-protection-1.2.0/lib/rack/protection/path_traversal.rb:16:in `call'
|
50
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/rack-protection-1.2.0/lib/rack/protection/json_csrf.rb:17:in `call'
|
51
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/rack-protection-1.2.0/lib/rack/protection/base.rb:47:in `call'
|
52
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/rack-protection-1.2.0/lib/rack/protection/xss_header.rb:22:in `call'
|
53
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/rack-1.4.1/lib/rack/nulllogger.rb:9:in `call'
|
54
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/rack-1.4.1/lib/rack/head.rb:9:in `call'
|
55
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:1334:in `block in call'
|
56
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:1416:in `synchronize'
|
57
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/sinatra-1.3.2/lib/sinatra/base.rb:1334:in `call'
|
58
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/rack-1.4.1/lib/rack/lint.rb:48:in `_call'
|
59
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/rack-1.4.1/lib/rack/lint.rb:36:in `call'
|
60
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/rack-1.4.1/lib/rack/showexceptions.rb:24:in `call'
|
61
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/rack-1.4.1/lib/rack/commonlogger.rb:20:in `call'
|
62
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/rack-1.4.1/lib/rack/chunked.rb:43:in `call'
|
63
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/rack-1.4.1/lib/rack/content_length.rb:14:in `call'
|
64
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/thin-1.3.1/lib/thin/connection.rb:80:in `block in pre_process'
|
65
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/thin-1.3.1/lib/thin/connection.rb:78:in `catch'
|
66
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/thin-1.3.1/lib/thin/connection.rb:78:in `pre_process'
|
67
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/thin-1.3.1/lib/thin/connection.rb:53:in `process'
|
68
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/thin-1.3.1/lib/thin/connection.rb:38:in `receive_data'
|
69
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/eventmachine-0.12.10/lib/eventmachine.rb:256:in `run_machine'
|
70
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/eventmachine-0.12.10/lib/eventmachine.rb:256:in `run'
|
71
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/thin-1.3.1/lib/thin/backends/base.rb:61:in `start'
|
72
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/thin-1.3.1/lib/thin/server.rb:159:in `start'
|
73
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/rack-1.4.1/lib/rack/handler/thin.rb:13:in `run'
|
74
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/rack-1.4.1/lib/rack/server.rb:265:in `start'
|
75
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/rack-1.4.1/lib/rack/server.rb:137:in `start'
|
76
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/rack-1.4.1/bin/rackup:4:in `<top (required)>'
|
77
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/bin/rackup:19:in `load'
|
78
|
+
/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/bin/rackup:19:in `<main>'api_server
|
79
|
+
|
80
|
+
<br/>
|
81
|
+
|
82
|
+
gets shortened to what you see below. Long method chains from gems get collapsed, and the RubyGems path (in my case, `/Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1`) gets trimmed from each line.
|
83
|
+
|
84
|
+
RuntimeError: It's no good, I can't maneuver!
|
85
|
+
/Users/philc/html5player/api_server/app/server_root.rb:88:in `block in <class:ServerRoot>'
|
86
|
+
<..>
|
87
|
+
.../gems/sinatra-1.3.2/lib/sinatra/base.rb:705:in `call'
|
88
|
+
<..>
|
89
|
+
.../gems/rack-protection-1.2.0/lib/rack/protection/xss_header.rb:22:in `call'
|
90
|
+
.../gems/rack-1.4.1/lib/rack/nulllogger.rb:9:in `call'
|
91
|
+
.../gems/rack-1.4.1/lib/rack/head.rb:9:in `call'
|
92
|
+
<..>
|
93
|
+
.../gems/sinatra-1.3.2/lib/sinatra/base.rb:1334:in `call'
|
94
|
+
<..>
|
95
|
+
.../gems/rack-1.4.1/lib/rack/content_length.rb:14:in `call'
|
96
|
+
<..>
|
97
|
+
.../gems/thin-1.3.1/lib/thin/connection.rb:38:in `receive_data'
|
98
|
+
.../gems/eventmachine-0.12.10/lib/eventmachine.rb:256:in `run_machine'
|
99
|
+
.../gems/eventmachine-0.12.10/lib/eventmachine.rb:256:in `run'
|
100
|
+
.../gems/thin-1.3.1/lib/thin/backends/base.rb:61:in `start'
|
101
|
+
.../gems/thin-1.3.1/lib/thin/server.rb:159:in `start'
|
102
|
+
<..>
|
103
|
+
.../gems/rack-1.4.1/bin/rackup:4:in `<top (required)>'
|
104
|
+
.../bin/rackup:19:in `load'
|
105
|
+
.../bin/rackup:19:in `<main>
|
106
|
+
|
107
|
+
|
108
|
+
If you want to see even less or filter things specific to your application, add your own filters. For example,
|
109
|
+
this filter rejects any line originating from a gem:
|
110
|
+
|
111
|
+
BacktraceShortener.filters.unshift(Proc.new do |backtrace|
|
112
|
+
backtrace.reject { |line| line.include?(Gem.dir) }
|
113
|
+
end)
|
114
|
+
|
115
|
+
Another example which truncates the backtrace to include only the first 10 lines:
|
116
|
+
|
117
|
+
BacktraceShortener.filters.unshift(Proc.new { |backtrace| backtrace[0, 10] }
|
118
|
+
|
119
|
+
If you need to access the full backtrace while debugging, you can call `the_exception.full_backtrace`.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "backtrace_shortener/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "backtrace_shortener"
|
7
|
+
s.version = BacktraceShortener::VERSION
|
8
|
+
s.authors = ["Phil Crosby"]
|
9
|
+
s.email = ["phil.crosby@gmail.com"]
|
10
|
+
s.homepage = "http://github.com/philc/backtrace_shortener"
|
11
|
+
s.summary = "Shortens the backtraces of exceptions to make debugging more friendly."
|
12
|
+
|
13
|
+
s.rubyforge_project = "backtrace_shortener"
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
17
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
18
|
+
s.require_paths = ["lib"]
|
19
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# This can patch the Exception class to prune the size of the backtraces and to make each line shorter.
|
2
|
+
# The idea is to improve the developer experience, because exceptions in apps using rbenv and gems can be
|
3
|
+
# taller than one terminal screen and each line can be long. See how painful this is with a 50 line backtrace:
|
4
|
+
# ...
|
5
|
+
# /Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/sequel-3.28.0/lib/sequel/adapters/mysql.rb:175:in `query'
|
6
|
+
# /Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/sequel-3.28.0/lib/sequel/adapters/mysql.rb:175:in `block in _execute'
|
7
|
+
# ...
|
8
|
+
#
|
9
|
+
# To apply this patch, invoke BacktraceCleanear.monkey_patch_the_exception_class!
|
10
|
+
#
|
11
|
+
# If you want to access the full backtrace while debugging, you can use my_exception.full_backtrace.
|
12
|
+
# If you want to write your own filter, append your own Proc to BacktraceShortener.filters:
|
13
|
+
# BacktraceShortener.filters.unshift(Proc.new { |backtrace| backtrace[0, 10] }) # Shortens to 10 lines.
|
14
|
+
module BacktraceShortener
|
15
|
+
def self.monkey_patch_the_exception_class!
|
16
|
+
return if Exception.new.respond_to?(:backtrace_prior_to_backtrace_shortener_monkey_patch)
|
17
|
+
|
18
|
+
Exception.class_eval do
|
19
|
+
alias :backtrace_prior_to_backtrace_shortener_monkey_patch :backtrace
|
20
|
+
alias :full_backtrace :backtrace_prior_to_backtrace_shortener_monkey_patch
|
21
|
+
|
22
|
+
def backtrace
|
23
|
+
backtrace = backtrace_prior_to_backtrace_shortener_monkey_patch
|
24
|
+
return nil if backtrace.nil?
|
25
|
+
BacktraceShortener.filters.inject(backtrace) { |backtrace, filter| filter.call(backtrace) }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Abbreviate any long gem paths, e.g.
|
31
|
+
# /Users/philc/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/sequel-3.28.0/lib
|
32
|
+
# => .../gems/1.9.1/gems/sequel-3.28.0/lib
|
33
|
+
def self.abbreviate_gem_directory_name(backtrace)
|
34
|
+
backtrace.map do |line|
|
35
|
+
line.sub(Gem.dir, "...")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Backtraces which involve gems can include many lines from within the gem's internals. This usually
|
40
|
+
# isn't helpful. Collapse those long sequences of lines and include just the first and last line.
|
41
|
+
def self.collapse_gems(backtrace)
|
42
|
+
current_gem = nil
|
43
|
+
current_gem_line_number = nil
|
44
|
+
i = backtrace.size - 1
|
45
|
+
|
46
|
+
while i >= 0
|
47
|
+
line_gem = gem_from_line(backtrace[i])
|
48
|
+
if line_gem != current_gem || i == 0
|
49
|
+
if current_gem && (current_gem_line_number - i) > 2
|
50
|
+
backtrace[i..current_gem_line_number] = [backtrace[i], "<..>", backtrace[current_gem_line_number]]
|
51
|
+
end
|
52
|
+
current_gem = line_gem
|
53
|
+
current_gem_line_number = i
|
54
|
+
end
|
55
|
+
i -= 1
|
56
|
+
end
|
57
|
+
backtrace
|
58
|
+
end
|
59
|
+
|
60
|
+
# Returns the gem in the given backtrace line, or nil if the line does not include a gem in it.
|
61
|
+
def self.gem_from_line(backtrace_line)
|
62
|
+
# Pull out "sequel-3.28.0" from this path: ".../lib/ruby/gems/1.9.1/gems/sequel-3.28.0/lib/..."
|
63
|
+
(%r{/ruby/gems/[^/]+/gems/([^/]+)/}.match(backtrace_line) || [])[1]
|
64
|
+
end
|
65
|
+
|
66
|
+
class << self
|
67
|
+
attr_accessor :filters
|
68
|
+
end
|
69
|
+
|
70
|
+
# The two default filters are 1) collapsing long runs of lines from gems and 2) abbreviating those lines.
|
71
|
+
self.filters = [method(:collapse_gems), method(:abbreviate_gem_directory_name)]
|
72
|
+
end
|
metadata
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: backtrace_shortener
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Phil Crosby
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2012-03-29 00:00:00 -07:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description:
|
23
|
+
email:
|
24
|
+
- phil.crosby@gmail.com
|
25
|
+
executables: []
|
26
|
+
|
27
|
+
extensions: []
|
28
|
+
|
29
|
+
extra_rdoc_files: []
|
30
|
+
|
31
|
+
files:
|
32
|
+
- .gitignore
|
33
|
+
- Gemfile
|
34
|
+
- README.markdown
|
35
|
+
- Rakefile
|
36
|
+
- backtrace_shortener.gemspec
|
37
|
+
- lib/backtrace_shortener.rb
|
38
|
+
- lib/backtrace_shortener/version.rb
|
39
|
+
has_rdoc: true
|
40
|
+
homepage: http://github.com/philc/backtrace_shortener
|
41
|
+
licenses: []
|
42
|
+
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options: []
|
45
|
+
|
46
|
+
require_paths:
|
47
|
+
- lib
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
hash: 3
|
54
|
+
segments:
|
55
|
+
- 0
|
56
|
+
version: "0"
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
hash: 3
|
63
|
+
segments:
|
64
|
+
- 0
|
65
|
+
version: "0"
|
66
|
+
requirements: []
|
67
|
+
|
68
|
+
rubyforge_project: backtrace_shortener
|
69
|
+
rubygems_version: 1.6.2
|
70
|
+
signing_key:
|
71
|
+
specification_version: 3
|
72
|
+
summary: Shortens the backtraces of exceptions to make debugging more friendly.
|
73
|
+
test_files: []
|
74
|
+
|