/
trace_with_bindings.rb
75 lines (64 loc) · 1.86 KB
/
trace_with_bindings.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
module Rollbar
class Notifier
class TraceWithBindings # :nodoc:
attr_reader :frames, :exception_frames
def initialize
reset
end
def reset
@frames = []
@exception_frames = []
@exception_signature = nil
end
def enable
reset
trace_point.enable if defined?(TracePoint)
end
def disable
trace_point.disable if defined?(TracePoint)
end
private
def exception_signature(trace)
# use the exception backtrace to detect reraised exception.
trace.raised_exception.backtrace.first
end
def detect_reraise(trace)
@exception_signature == exception_signature(trace)
end
def trace_point
return unless defined?(TracePoint)
@trace_point ||= TracePoint.new(:call, :return, :b_call, :b_return, :c_call,
:c_return, :raise) do |tp|
case tp.event
when :call, :b_call, :c_call, :class
frames.push frame(tp)
when :return, :b_return, :c_return, :end
frames.pop
when :raise
unless detect_reraise(tp) # ignore reraised exceptions
# may be possible to optimize better than #dup
@exception_frames = @frames.dup
@exception_signature = exception_signature(tp)
end
end
end
end
def frame(trace)
{
:binding => binding(trace),
:defined_class => trace.defined_class,
:method_id => trace.method_id,
:path => trace.path,
:lineno => trace.lineno
}
end
def binding(trace)
trace.binding
rescue StandardError
# Ruby internals will raise if we're on a Fiber,
# since bindings aren't valid on Fibers.
nil
end
end
end
end