forked from airbrake/airbrake
/
backtrace.rb
100 lines (77 loc) · 2.28 KB
/
backtrace.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
module Airbrake
# Front end to parsing the backtrace for each notice
class Backtrace
# Handles backtrace parsing line by line
class Line
# regexp (optionnally allowing leading X: for windows support)
INPUT_FORMAT = %r{^((?:[a-zA-Z]:)?[^:]+):(\d+)(?::in `([^']+)')?$}.freeze
# The file portion of the line (such as app/models/user.rb)
attr_reader :file
# The line number portion of the line
attr_reader :number
# The method of the line (such as index)
attr_reader :method
# Parses a single line of a given backtrace
# @param [String] unparsed_line The raw line from +caller+ or some backtrace
# @return [Line] The parsed backtrace line
def self.parse(unparsed_line)
_, file, number, method = unparsed_line.match(INPUT_FORMAT).to_a
new(file, number, method)
end
def initialize(file, number, method)
self.file = file
self.number = number
self.method = method
end
# Reconstructs the line in a readable fashion
def to_s
"#{file}:#{number}:in `#{method}'"
end
def ==(other)
to_s == other.to_s
end
def inspect
"<Line:#{to_s}>"
end
private
attr_writer :file, :number, :method
end
# holder for an Array of Backtrace::Line instances
attr_reader :lines
def self.parse(ruby_backtrace, opts = {})
ruby_lines = split_multiline_backtrace(ruby_backtrace)
filters = opts[:filters] || []
filtered_lines = ruby_lines.to_a.map do |line|
filters.inject(line) do |line, proc|
proc.call(line)
end
end.compact
lines = filtered_lines.collect do |unparsed_line|
Line.parse(unparsed_line)
end
instance = new(lines)
end
def initialize(lines)
self.lines = lines
end
def inspect
"<Backtrace: " + lines.collect { |line| line.inspect }.join(", ") + ">"
end
def ==(other)
if other.respond_to?(:lines)
lines == other.lines
else
false
end
end
private
attr_writer :lines
def self.split_multiline_backtrace(backtrace)
if backtrace.to_a.size == 1
backtrace.to_a.first.split(/\n\s*/)
else
backtrace
end
end
end
end