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.
@@ -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
+