backtrace_shortener 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in backtrace_shortener.gemspec
4
+ gemspec
@@ -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`.
@@ -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
@@ -0,0 +1,3 @@
1
+ module BacktraceShortener
2
+ VERSION = "0.1.0"
3
+ 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
+