flail 0.0.7 → 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/Gemfile.lock +1 -1
- data/lib/flail/backtrace.rb +122 -0
- data/lib/flail/exception.rb +21 -5
- data/lib/flail/version.rb +1 -1
- data/lib/flail.rb +1 -0
- data/spec/backtrace_spec.rb +85 -0
- data/spec/exception_spec.rb +27 -0
- data/spec/rescue_action_spec.rb +34 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/support/rr.rb +42 -0
- metadata +9 -2
data/Gemfile.lock
CHANGED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
class Flail
|
|
2
|
+
# Front end to parsing the backtrace for each notice
|
|
3
|
+
class Backtrace
|
|
4
|
+
|
|
5
|
+
DEFAULT_FILTERS = [
|
|
6
|
+
lambda { |line| line.gsub(/^\.\//, "") },
|
|
7
|
+
lambda { |line|
|
|
8
|
+
if defined?(Gem)
|
|
9
|
+
Gem.path.inject(line) do |line, path|
|
|
10
|
+
line.gsub(/#{path}/, "[GEM_ROOT]")
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
},
|
|
14
|
+
lambda { |line| line if line !~ %r{lib/flail} }
|
|
15
|
+
].freeze
|
|
16
|
+
|
|
17
|
+
# Handles backtrace parsing line by line
|
|
18
|
+
class Line
|
|
19
|
+
|
|
20
|
+
# regexp (optionnally allowing leading X: for windows support)
|
|
21
|
+
INPUT_FORMAT = %r{^((?:[a-zA-Z]:)?[^:]+):(\d+)(?::in `([^']+)')?$}.freeze # `
|
|
22
|
+
|
|
23
|
+
# The file portion of the line (such as app/models/user.rb)
|
|
24
|
+
attr_reader :file
|
|
25
|
+
|
|
26
|
+
# The line number portion of the line
|
|
27
|
+
attr_reader :number
|
|
28
|
+
|
|
29
|
+
# The method of the line (such as index)
|
|
30
|
+
attr_reader :method
|
|
31
|
+
|
|
32
|
+
# Parses a single line of a given backtrace
|
|
33
|
+
# @param [String] unparsed_line The raw line from +caller+ or some backtrace
|
|
34
|
+
# @return [Line] The parsed backtrace line
|
|
35
|
+
def self.parse(unparsed_line)
|
|
36
|
+
_, file, number, method = unparsed_line.match(INPUT_FORMAT).to_a
|
|
37
|
+
new(file, number, method)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def initialize(file, number, method)
|
|
41
|
+
self.file = file
|
|
42
|
+
self.number = number
|
|
43
|
+
self.method = method
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Reconstructs the line in a readable fashion
|
|
47
|
+
def to_s
|
|
48
|
+
"#{file}:#{number}:in `#{method}'"
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def ==(other)
|
|
52
|
+
to_s == other.to_s
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def inspect
|
|
56
|
+
"<Line:#{to_s}>"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
attr_writer :file, :number, :method
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# holder for an Array of Backtrace::Line instances
|
|
65
|
+
attr_reader :lines
|
|
66
|
+
|
|
67
|
+
def self.parse(ruby_backtrace, opts = {})
|
|
68
|
+
ruby_lines = split_multiline_backtrace(ruby_backtrace)
|
|
69
|
+
|
|
70
|
+
filters = opts[:filters] || []
|
|
71
|
+
filtered_lines = ruby_lines.to_a.map do |line|
|
|
72
|
+
filters.inject(line) do |line, proc|
|
|
73
|
+
proc.call(line)
|
|
74
|
+
end
|
|
75
|
+
end.compact
|
|
76
|
+
|
|
77
|
+
lines = filtered_lines.collect do |unparsed_line|
|
|
78
|
+
Line.parse(unparsed_line)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
instance = new(lines)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def initialize(lines)
|
|
85
|
+
self.lines = lines
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def inspect
|
|
89
|
+
"<Backtrace: " + lines.collect { |line| line.inspect }.join(", ") + ">"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def ==(other)
|
|
93
|
+
if other.respond_to?(:lines)
|
|
94
|
+
lines == other.lines
|
|
95
|
+
else
|
|
96
|
+
false
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def to_ary
|
|
101
|
+
lines.inject([]) do |collector, line|
|
|
102
|
+
collector << {
|
|
103
|
+
:number => line.number,
|
|
104
|
+
:file => line.file,
|
|
105
|
+
:method => line.method
|
|
106
|
+
}
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
private
|
|
111
|
+
|
|
112
|
+
attr_writer :lines
|
|
113
|
+
|
|
114
|
+
def self.split_multiline_backtrace(backtrace)
|
|
115
|
+
if backtrace.to_a.size == 1
|
|
116
|
+
backtrace.to_a.first.split(/\n\s*/)
|
|
117
|
+
else
|
|
118
|
+
backtrace
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
data/lib/flail/exception.rb
CHANGED
|
@@ -42,12 +42,26 @@ class Flail
|
|
|
42
42
|
clean_unserializable_data(value, stack + [data.object_id])
|
|
43
43
|
end
|
|
44
44
|
else
|
|
45
|
-
|
|
45
|
+
input = if ''.respond_to?(:encode)
|
|
46
|
+
data.to_s.encode(Encoding::UTF_8, :undef => :replace)
|
|
47
|
+
else
|
|
48
|
+
require 'iconv'
|
|
49
|
+
ic = Iconv.new("UTF-8//IGNORE", "UTF-8")
|
|
50
|
+
ic.iconv(data.to_s + ' ')[0..-2]
|
|
51
|
+
end
|
|
52
|
+
begin
|
|
53
|
+
input.to_json
|
|
54
|
+
rescue Exception => e
|
|
55
|
+
input = "redundant utf-8 sequence"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
input
|
|
46
59
|
end
|
|
47
60
|
end
|
|
48
61
|
|
|
49
62
|
def clean_rack_env(data)
|
|
50
63
|
data.delete("rack.request.form_vars")
|
|
64
|
+
data.delete("rack.input")
|
|
51
65
|
data
|
|
52
66
|
end
|
|
53
67
|
|
|
@@ -64,16 +78,18 @@ class Flail
|
|
|
64
78
|
info = {}
|
|
65
79
|
|
|
66
80
|
# rack env
|
|
67
|
-
info[:rack] = clean_rack_env(
|
|
81
|
+
info[:rack] = clean_unserializable_data(clean_rack_env(@env))
|
|
68
82
|
|
|
69
|
-
info[:class_name] = @exception.class.
|
|
83
|
+
info[:class_name] = @exception.class.name # @exception class
|
|
70
84
|
info[:message] = @exception.to_s # error message
|
|
71
|
-
info[:trace] = @exception.backtrace # backtrace of error
|
|
72
85
|
info[:target_url] = request_data[:target_url] # url of request
|
|
73
86
|
info[:referer_url] = request_data[:referer_url] # referer
|
|
74
87
|
info[:user_agent] = request_data[:user_agent] # user agent
|
|
75
88
|
info[:user] = request_data[:user] # current user
|
|
76
89
|
|
|
90
|
+
# backtrace of error
|
|
91
|
+
info[:trace] = Flail::Backtrace.parse(@exception.backtrace, :filters => Flail::Backtrace::DEFAULT_FILTERS).to_ary
|
|
92
|
+
|
|
77
93
|
# request parameters
|
|
78
94
|
info[:parameters] = clean_unserializable_data(request_data[:parameters])
|
|
79
95
|
|
|
@@ -83,7 +99,7 @@ class Flail
|
|
|
83
99
|
# special variables
|
|
84
100
|
info[:environment] = Flail.configuration.env
|
|
85
101
|
info[:hostname] = Flail.configuration.hostname
|
|
86
|
-
info[:tag]
|
|
102
|
+
info[:tag] = Flail.configuration.tag
|
|
87
103
|
|
|
88
104
|
info
|
|
89
105
|
end
|
data/lib/flail/version.rb
CHANGED
data/lib/flail.rb
CHANGED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
require 'flail/backtrace'
|
|
4
|
+
|
|
5
|
+
describe Flail::Backtrace do
|
|
6
|
+
|
|
7
|
+
SAMPLE_BACKTRACE = [
|
|
8
|
+
"app/models/user.rb:13:in `magic'",
|
|
9
|
+
"app/controllers/users_controller.rb:8:in `index'"
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
it "should parse a backtrace into lines" do
|
|
14
|
+
backtrace = Flail::Backtrace.parse(SAMPLE_BACKTRACE)
|
|
15
|
+
|
|
16
|
+
line = backtrace.lines.first
|
|
17
|
+
line.number.should == '13'
|
|
18
|
+
line.file.should == 'app/models/user.rb'
|
|
19
|
+
line.method.should == 'magic'
|
|
20
|
+
|
|
21
|
+
line = backtrace.lines.last
|
|
22
|
+
line.number.should == '8'
|
|
23
|
+
line.file.should == 'app/controllers/users_controller.rb'
|
|
24
|
+
line.method.should == 'index'
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
it "should parse a windows backtrace into lines" do
|
|
29
|
+
array = [
|
|
30
|
+
"C:/Program Files/Server/app/models/user.rb:13:in `magic'",
|
|
31
|
+
"C:/Program Files/Server/app/controllers/users_controller.rb:8:in `index'"
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
backtrace = Flail::Backtrace.parse(array)
|
|
35
|
+
|
|
36
|
+
line = backtrace.lines.first
|
|
37
|
+
line.number.should == '13'
|
|
38
|
+
line.file.should == 'C:/Program Files/Server/app/models/user.rb'
|
|
39
|
+
line.method.should == 'magic'
|
|
40
|
+
|
|
41
|
+
line = backtrace.lines.last
|
|
42
|
+
line.number.should == '8'
|
|
43
|
+
line.file.should == 'C:/Program Files/Server/app/controllers/users_controller.rb'
|
|
44
|
+
line.method.should == 'index'
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "should be equal with equal lines" do
|
|
48
|
+
one = SAMPLE_BACKTRACE
|
|
49
|
+
two = one.dup
|
|
50
|
+
|
|
51
|
+
Flail::Backtrace.parse(one).should == Flail::Backtrace.parse(two)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "should parse massive one-line exceptions into multiple lines" do
|
|
55
|
+
original_backtrace = Flail::Backtrace.parse(["one:1:in `one'\n two:2:in `two'\n three:3:in `three`"])
|
|
56
|
+
expected_backtrace = Flail::Backtrace.parse(["one:1:in `one'", "two:2:in `two'", "three:3:in `three`"])
|
|
57
|
+
|
|
58
|
+
expected_backtrace.should == original_backtrace
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it "should remove notifier trace" do
|
|
62
|
+
inside_notifier = ['lib/flail/exception.rb:13:in `voodoo`']
|
|
63
|
+
outside_notifier = ['users_controller:8:in `index`']
|
|
64
|
+
|
|
65
|
+
without_inside = Flail::Backtrace.parse(outside_notifier)
|
|
66
|
+
with_inside = Flail::Backtrace.parse(inside_notifier + outside_notifier,
|
|
67
|
+
:filters => Flail::Backtrace::DEFAULT_FILTERS)
|
|
68
|
+
|
|
69
|
+
without_inside.should == with_inside
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it "should run filters on the backtrace" do
|
|
73
|
+
filters = [lambda { |line| line.sub('foo', 'bar') }]
|
|
74
|
+
|
|
75
|
+
input = Flail::Backtrace.parse(["foo:13:in `one'",
|
|
76
|
+
"baz:14:in `two'"
|
|
77
|
+
], :filters => filters)
|
|
78
|
+
|
|
79
|
+
expected = Flail::Backtrace.parse(["bar:13:in `one'",
|
|
80
|
+
"baz:14:in `two'"
|
|
81
|
+
])
|
|
82
|
+
|
|
83
|
+
expected.should == input
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
require 'spec_helper'
|
|
3
|
+
|
|
4
|
+
require 'ostruct'
|
|
5
|
+
require 'flail/backtrace'
|
|
6
|
+
require 'flail/exception'
|
|
7
|
+
|
|
8
|
+
describe Flail::Exception do
|
|
9
|
+
|
|
10
|
+
subject { Flail::Exception.new({}, Exception.new) }
|
|
11
|
+
SAMPLE_BACKTRACE = [
|
|
12
|
+
"app/models/user.rb:13:in `magic'",
|
|
13
|
+
"app/controllers/users_controller.rb:8:in `index'"
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
it "should not choke on bad utf-8" do
|
|
17
|
+
b1r = 0xc0..0xc2
|
|
18
|
+
b2r = 0x80..0xbf
|
|
19
|
+
b1r.each do |b1|
|
|
20
|
+
b2r.each do |b2|
|
|
21
|
+
string = [b1,b2].pack("C*")
|
|
22
|
+
|
|
23
|
+
lambda { subject.clean_unserializable_data({:test => string}).to_json }.should_not raise_error
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
data/spec/rescue_action_spec.rb
CHANGED
|
@@ -49,5 +49,39 @@ describe Flail::Rails::RescueAction do
|
|
|
49
49
|
|
|
50
50
|
FlailArmory.payload['user'].should == {'id' => 1, 'login' => 'jlong'}
|
|
51
51
|
end
|
|
52
|
+
|
|
53
|
+
it "should call session.to_hash if available" do
|
|
54
|
+
hash_data = {:key => :value}
|
|
55
|
+
|
|
56
|
+
session = ActionController::TestSession.new
|
|
57
|
+
stub(ActionController::TestSession).new { session }
|
|
58
|
+
stub(session).to_hash { hash_data }
|
|
59
|
+
|
|
60
|
+
FlailArmory.process_action_with_error
|
|
61
|
+
|
|
62
|
+
session.should have_received.to_hash
|
|
63
|
+
session.should_not have_received.data
|
|
64
|
+
FlailArmory.payload.should_not be_nil
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "should call session.to_hash if available" do
|
|
68
|
+
hash_data = {:key => :value}
|
|
69
|
+
|
|
70
|
+
session = ActionController::TestSession.new
|
|
71
|
+
stub(ActionController::TestSession).new { session }
|
|
72
|
+
stub(session).data { hash_data }
|
|
73
|
+
|
|
74
|
+
if session.respond_to?(:to_hash)
|
|
75
|
+
class << session
|
|
76
|
+
undef :to_hash
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
FlailArmory.process_action_with_error
|
|
81
|
+
|
|
82
|
+
session.should_not have_received.to_hash
|
|
83
|
+
session.should have_received.data
|
|
84
|
+
FlailArmory.payload.should_not be_nil
|
|
85
|
+
end
|
|
52
86
|
end
|
|
53
87
|
end
|
data/spec/spec_helper.rb
CHANGED
data/spec/support/rr.rb
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# --- add this as spec/support/rr.rb ---
|
|
2
|
+
|
|
3
|
+
# RR doesn't have support for RSpec 2.
|
|
4
|
+
#
|
|
5
|
+
# Source: <https://github.com/btakita/rr/issues#issue/45>
|
|
6
|
+
|
|
7
|
+
require 'rr'
|
|
8
|
+
|
|
9
|
+
module RR
|
|
10
|
+
module Adapters
|
|
11
|
+
module RSpec2
|
|
12
|
+
include RRMethods
|
|
13
|
+
|
|
14
|
+
def setup_mocks_for_rspec
|
|
15
|
+
RR.reset
|
|
16
|
+
end
|
|
17
|
+
def verify_mocks_for_rspec
|
|
18
|
+
RR.verify
|
|
19
|
+
end
|
|
20
|
+
def teardown_mocks_for_rspec
|
|
21
|
+
RR.reset
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def have_received(method = nil)
|
|
25
|
+
RR::Adapters::Rspec::InvocationMatcher.new(method)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
module RSpec
|
|
32
|
+
module Core
|
|
33
|
+
module MockFrameworkAdapter
|
|
34
|
+
include RR::Adapters::RSpec2
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
RSpec.configure do |config|
|
|
40
|
+
config.mock_framework = RSpec::Core::MockFrameworkAdapter
|
|
41
|
+
config.backtrace_clean_patterns.push(RR::Errors::BACKTRACE_IDENTIFIER)
|
|
42
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: flail
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0
|
|
4
|
+
version: 0.1.0
|
|
5
5
|
prerelease:
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2012-08-
|
|
12
|
+
date: 2012-08-22 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: actionpack
|
|
@@ -157,6 +157,7 @@ files:
|
|
|
157
157
|
- Rakefile
|
|
158
158
|
- flail.gemspec
|
|
159
159
|
- lib/flail.rb
|
|
160
|
+
- lib/flail/backtrace.rb
|
|
160
161
|
- lib/flail/base.rb
|
|
161
162
|
- lib/flail/configuration.rb
|
|
162
163
|
- lib/flail/exception.rb
|
|
@@ -168,9 +169,12 @@ files:
|
|
|
168
169
|
- lib/flail/railtie.rb
|
|
169
170
|
- lib/flail/version.rb
|
|
170
171
|
- rails/init.rb
|
|
172
|
+
- spec/backtrace_spec.rb
|
|
171
173
|
- spec/base_spec.rb
|
|
174
|
+
- spec/exception_spec.rb
|
|
172
175
|
- spec/rescue_action_spec.rb
|
|
173
176
|
- spec/spec_helper.rb
|
|
177
|
+
- spec/support/rr.rb
|
|
174
178
|
homepage: https://github.com/asceth/flail
|
|
175
179
|
licenses: []
|
|
176
180
|
post_install_message:
|
|
@@ -196,6 +200,9 @@ signing_key:
|
|
|
196
200
|
specification_version: 3
|
|
197
201
|
summary: Rails exception handler
|
|
198
202
|
test_files:
|
|
203
|
+
- spec/backtrace_spec.rb
|
|
199
204
|
- spec/base_spec.rb
|
|
205
|
+
- spec/exception_spec.rb
|
|
200
206
|
- spec/rescue_action_spec.rb
|
|
201
207
|
- spec/spec_helper.rb
|
|
208
|
+
- spec/support/rr.rb
|