sentry-raven 0.12.3 → 0.13.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.
- checksums.yaml +4 -4
- data/README.md +2 -3
- data/lib/raven/base.rb +43 -53
- data/lib/raven/client.rb +25 -29
- data/lib/raven/configuration.rb +7 -2
- data/lib/raven/event.rb +103 -84
- data/lib/raven/integrations/rack.rb +5 -12
- data/lib/raven/integrations/rails.rb +1 -1
- data/lib/raven/interfaces.rb +5 -6
- data/lib/raven/interfaces/exception.rb +3 -6
- data/lib/raven/interfaces/http.rb +1 -0
- data/lib/raven/interfaces/single_exception.rb +19 -0
- data/lib/raven/interfaces/stack_trace.rb +25 -15
- data/lib/raven/linecache.rb +0 -1
- data/lib/raven/processor.rb +1 -17
- data/lib/raven/processor/removestacktrace.rb +5 -1
- data/lib/raven/processor/sanitizedata.rb +31 -7
- data/lib/raven/version.rb +1 -1
- metadata +3 -17
- data/lib/raven/better_attr_accessor.rb +0 -44
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c09fc2d9d439ff50aa3d575716890797ebb81cb6
|
4
|
+
data.tar.gz: 834dc9c9d24c2bf004f071b9ec77d3c96edb22e7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b07c730db8e117c99f3f3e40bbf66863880bb630b2e57de211335994749a930f3f9ea4a86b49eb3f632a88c09184588c0d38b73ce9f0fb3482845c4ccfe4f904
|
7
|
+
data.tar.gz: 3e3390603c2835ff88c0644c753a3459f721026adc5bb0f03e207158f65528e861363c571d6a73c7185b0f844fdfdb60190b31fe0ed6e6db3e5bcc7363e69b85
|
data/README.md
CHANGED
@@ -2,13 +2,12 @@
|
|
2
2
|
|
3
3
|
[](https://rubygems.org/gems/sentry-raven)
|
4
4
|
[](https://travis-ci.org/getsentry/raven-ruby)
|
5
|
-
[](https://coveralls.io/r/getsentry/raven-ruby)
|
6
5
|
|
7
6
|
A client and integration layer for the [Sentry](https://github.com/getsentry/sentry) error reporting API.
|
8
7
|
|
9
8
|
## Requirements
|
10
9
|
|
11
|
-
We test on Ruby MRI 1.8.7/REE, 1.9.3, 2.0 and 2.
|
10
|
+
We test on Ruby MRI 1.8.7/REE, 1.9.3, 2.0, 2.1 and 2.2. JRuby support is experimental - check TravisCI to see if the build is passing or failing.
|
12
11
|
|
13
12
|
## Getting Started
|
14
13
|
### Install
|
@@ -45,7 +44,7 @@ end
|
|
45
44
|
|
46
45
|
## More Information
|
47
46
|
|
48
|
-
Full documentation and more information on advanced configuration, sending more information, scrubbing sensitive data, and more can be found on [the wiki](https://github.com/getsentry/raven-ruby/wiki).
|
47
|
+
Full documentation and more information on advanced configuration, sending more information, scrubbing sensitive data, and more can be found on [the wiki](https://github.com/getsentry/raven-ruby/wiki).
|
49
48
|
|
50
49
|
* [Documentation](https://github.com/getsentry/raven-ruby/wiki)
|
51
50
|
* [Bug Tracker](http://github.com/getsentry/raven-ruby/issues>)
|
data/lib/raven/base.rb
CHANGED
@@ -7,6 +7,7 @@ require 'raven/event'
|
|
7
7
|
require 'raven/logger'
|
8
8
|
require 'raven/interfaces/message'
|
9
9
|
require 'raven/interfaces/exception'
|
10
|
+
require 'raven/interfaces/single_exception'
|
10
11
|
require 'raven/interfaces/stack_trace'
|
11
12
|
require 'raven/interfaces/http'
|
12
13
|
require 'raven/processor'
|
@@ -49,9 +50,15 @@ module Raven
|
|
49
50
|
end
|
50
51
|
|
51
52
|
# Tell the log that the client is good to go
|
52
|
-
def
|
53
|
-
|
53
|
+
def report_status
|
54
|
+
return if client.configuration.silence_ready
|
55
|
+
if client.configuration.send_in_current_environment?
|
56
|
+
logger.info "Raven #{VERSION} ready to catch errors"
|
57
|
+
else
|
58
|
+
logger.info "Raven #{VERSION} configured not to send errors."
|
59
|
+
end
|
54
60
|
end
|
61
|
+
alias_method :report_ready, :report_status
|
55
62
|
|
56
63
|
# Call this method to modify defaults in your initializers.
|
57
64
|
#
|
@@ -59,11 +66,11 @@ module Raven
|
|
59
66
|
# Raven.configure do |config|
|
60
67
|
# config.server = 'http://...'
|
61
68
|
# end
|
62
|
-
def configure
|
69
|
+
def configure
|
63
70
|
yield(configuration) if block_given?
|
64
71
|
|
65
72
|
self.client = Client.new(configuration)
|
66
|
-
|
73
|
+
report_status
|
67
74
|
self.client
|
68
75
|
end
|
69
76
|
|
@@ -83,65 +90,39 @@ module Raven
|
|
83
90
|
# Raven.capture do
|
84
91
|
# MyApp.run
|
85
92
|
# end
|
86
|
-
def capture(options = {}
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
end
|
96
|
-
else
|
97
|
-
# Install at_exit hook
|
98
|
-
at_exit do
|
99
|
-
if $ERROR_INFO
|
100
|
-
logger.debug "Caught a post-mortem exception: #{$ERROR_INFO.inspect}"
|
101
|
-
capture_exception($ERROR_INFO, options)
|
102
|
-
end
|
103
|
-
end
|
93
|
+
def capture(options = {})
|
94
|
+
install_at_exit_hook unless block_given?
|
95
|
+
begin
|
96
|
+
yield
|
97
|
+
rescue Error
|
98
|
+
raise # Don't capture Raven errors
|
99
|
+
rescue Exception => e
|
100
|
+
capture_exception(e, options)
|
101
|
+
raise
|
104
102
|
end
|
105
103
|
end
|
106
104
|
|
107
|
-
def
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
105
|
+
def capture_type(obj, options = {})
|
106
|
+
return false unless should_capture?(obj)
|
107
|
+
message_or_exc = obj.is_a?(String) ? "message" : "exception"
|
108
|
+
if (evt = Event.send("from_" + message_or_exc, obj, options))
|
109
|
+
yield evt if block_given?
|
110
|
+
if configuration.async?
|
111
|
+
configuration.async.call(evt)
|
112
|
+
else
|
113
|
+
send(evt)
|
116
114
|
end
|
117
115
|
end
|
118
116
|
end
|
117
|
+
alias_method :capture_message, :capture_type
|
118
|
+
alias_method :capture_exception, :capture_type
|
119
119
|
|
120
|
-
def
|
121
|
-
|
122
|
-
|
123
|
-
yield evt if block_given?
|
124
|
-
if configuration.async?
|
125
|
-
configuration.async.call(evt)
|
126
|
-
else
|
127
|
-
send(evt)
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
def send_or_skip(exc)
|
134
|
-
should_send = if configuration.should_send
|
135
|
-
configuration.should_send.call(*[exc])
|
120
|
+
def should_capture?(message_or_exc)
|
121
|
+
if configuration.should_capture
|
122
|
+
configuration.should_capture.call(*[message_or_exc])
|
136
123
|
else
|
137
124
|
true
|
138
125
|
end
|
139
|
-
|
140
|
-
if configuration.send_in_current_environment? && should_send
|
141
|
-
yield if block_given?
|
142
|
-
else
|
143
|
-
configuration.log_excluded_environment_message
|
144
|
-
end
|
145
126
|
end
|
146
127
|
|
147
128
|
# Provides extra context to the exception prior to it being handled by
|
@@ -231,5 +212,14 @@ module Raven
|
|
231
212
|
alias :captureMessage :capture_message
|
232
213
|
alias :annotateException :annotate_exception
|
233
214
|
alias :annotate :annotate_exception
|
215
|
+
|
216
|
+
private
|
217
|
+
|
218
|
+
def install_at_exit_hook
|
219
|
+
at_exit do
|
220
|
+
logger.debug "Caught a post-mortem exception: #{$ERROR_INFO.inspect}"
|
221
|
+
capture_exception($ERROR_INFO, options)
|
222
|
+
end
|
223
|
+
end
|
234
224
|
end
|
235
225
|
end
|
data/lib/raven/client.rb
CHANGED
@@ -7,9 +7,8 @@ require 'raven/transports/http'
|
|
7
7
|
require 'raven/transports/udp'
|
8
8
|
|
9
9
|
module Raven
|
10
|
-
|
10
|
+
# Encodes events and sends them to the Sentry server.
|
11
11
|
class Client
|
12
|
-
|
13
12
|
PROTOCOL_VERSION = '5'
|
14
13
|
USER_AGENT = "raven-ruby/#{Raven::VERSION}"
|
15
14
|
CONTENT_TYPE = 'application/json'
|
@@ -23,22 +22,20 @@ module Raven
|
|
23
22
|
end
|
24
23
|
|
25
24
|
def send(event)
|
26
|
-
unless
|
27
|
-
configuration.log_excluded_environment_message
|
28
|
-
return
|
29
|
-
end
|
25
|
+
return false unless configuration_allows_sending
|
30
26
|
|
31
|
-
#
|
32
|
-
event
|
27
|
+
# Convert to hash
|
28
|
+
event = event.to_hash
|
33
29
|
|
34
30
|
if !@state.should_try?
|
35
31
|
Raven.logger.error("Not sending event due to previous failure(s): #{get_log_message(event)}")
|
36
32
|
return
|
37
33
|
end
|
38
34
|
|
39
|
-
Raven.logger.debug "Sending event #{event
|
35
|
+
Raven.logger.debug "Sending event #{event['id']} to Sentry"
|
40
36
|
|
41
37
|
content_type, encoded_data = encode(event)
|
38
|
+
|
42
39
|
begin
|
43
40
|
transport.send(generate_auth_header, encoded_data,
|
44
41
|
:content_type => content_type)
|
@@ -54,39 +51,40 @@ module Raven
|
|
54
51
|
|
55
52
|
private
|
56
53
|
|
57
|
-
def
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
54
|
+
def configuration_allows_sending
|
55
|
+
if configuration.send_in_current_environment?
|
56
|
+
true
|
57
|
+
else
|
58
|
+
configuration.log_excluded_environment_message
|
59
|
+
false
|
63
60
|
end
|
61
|
+
end
|
64
62
|
|
63
|
+
def encode(event)
|
64
|
+
hash = @processors.reduce(event.to_hash) { |memo, p| p.process(memo) }
|
65
65
|
encoded = OkJson.encode(hash)
|
66
66
|
|
67
|
-
case
|
67
|
+
case configuration.encoding
|
68
68
|
when 'gzip'
|
69
|
-
|
70
|
-
b64_encoded = strict_encode64(gzipped)
|
71
|
-
return 'application/octet-stream', b64_encoded
|
69
|
+
['application/octet-stream', strict_encode64(Zlib::Deflate.deflate(encoded))]
|
72
70
|
else
|
73
|
-
|
71
|
+
['application/json', encoded]
|
74
72
|
end
|
75
73
|
end
|
76
74
|
|
77
75
|
def get_log_message(event)
|
78
|
-
(event && event
|
76
|
+
(event && event['message']) || '<no message value>'
|
79
77
|
end
|
80
78
|
|
81
79
|
def transport
|
82
80
|
@transport ||=
|
83
|
-
case
|
81
|
+
case configuration.scheme
|
84
82
|
when 'udp'
|
85
|
-
Transports::UDP.new
|
83
|
+
Transports::UDP.new(configuration)
|
86
84
|
when 'http', 'https'
|
87
|
-
Transports::HTTP.new
|
85
|
+
Transports::HTTP.new(configuration)
|
88
86
|
else
|
89
|
-
raise Error
|
87
|
+
raise Error, "Unknown transport scheme '#{self.configuration.scheme}'"
|
90
88
|
end
|
91
89
|
end
|
92
90
|
|
@@ -96,14 +94,12 @@ module Raven
|
|
96
94
|
'sentry_version' => PROTOCOL_VERSION,
|
97
95
|
'sentry_client' => USER_AGENT,
|
98
96
|
'sentry_timestamp' => now,
|
99
|
-
'sentry_key' =>
|
100
|
-
'sentry_secret' =>
|
97
|
+
'sentry_key' => configuration.public_key,
|
98
|
+
'sentry_secret' => configuration.secret_key
|
101
99
|
}
|
102
100
|
'Sentry ' + fields.map { |key, value| "#{key}=#{value}" }.join(', ')
|
103
101
|
end
|
104
102
|
|
105
|
-
private
|
106
|
-
|
107
103
|
def strict_encode64(string)
|
108
104
|
if Base64.respond_to? :strict_encode64
|
109
105
|
Base64.strict_encode64 string
|
data/lib/raven/configuration.rb
CHANGED
@@ -31,6 +31,9 @@ module Raven
|
|
31
31
|
# Logger to use internally
|
32
32
|
attr_accessor :logger
|
33
33
|
|
34
|
+
# Silence ready message
|
35
|
+
attr_accessor :silence_ready
|
36
|
+
|
34
37
|
# Number of lines of code context to capture, or nil for none
|
35
38
|
attr_accessor :context_lines
|
36
39
|
|
@@ -68,6 +71,8 @@ module Raven
|
|
68
71
|
|
69
72
|
attr_accessor :server_name
|
70
73
|
|
74
|
+
attr_accessor :release
|
75
|
+
|
71
76
|
# DEPRECATED: This option is now ignored as we use our own adapter.
|
72
77
|
attr_accessor :json_adapter
|
73
78
|
|
@@ -84,8 +89,8 @@ module Raven
|
|
84
89
|
# ActionDispatch::ShowExceptions or ActionDispatch::DebugExceptions
|
85
90
|
attr_accessor :catch_debugged_exceptions
|
86
91
|
|
87
|
-
# Provide a configurable callback to
|
88
|
-
attr_accessor :
|
92
|
+
# Provide a configurable callback to determine event capture
|
93
|
+
attr_accessor :should_capture
|
89
94
|
|
90
95
|
# additional fields to sanitize
|
91
96
|
attr_accessor :sanitize_fields
|
data/lib/raven/event.rb
CHANGED
@@ -23,52 +23,46 @@ module Raven
|
|
23
23
|
PLATFORM = "ruby"
|
24
24
|
|
25
25
|
attr_reader :id
|
26
|
-
attr_accessor :project, :message, :timestamp, :time_spent, :level
|
27
|
-
|
28
|
-
|
29
|
-
def initialize(
|
30
|
-
@configuration =
|
31
|
-
@interfaces
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
@
|
36
|
-
@
|
37
|
-
@
|
38
|
-
@
|
39
|
-
|
40
|
-
@
|
41
|
-
@
|
42
|
-
@
|
43
|
-
@
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
26
|
+
attr_accessor :project, :message, :timestamp, :time_spent, :level, :logger,
|
27
|
+
:culprit, :server_name, :release, :modules, :extra, :tags, :context, :configuration
|
28
|
+
|
29
|
+
def initialize(init = {})
|
30
|
+
@configuration = Raven.configuration
|
31
|
+
@interfaces = {}
|
32
|
+
@context = Raven.context
|
33
|
+
@id = generate_event_id
|
34
|
+
@message = nil
|
35
|
+
@timestamp = Time.now.utc
|
36
|
+
@time_spent = nil
|
37
|
+
@level = :error
|
38
|
+
@logger = 'root'
|
39
|
+
@culprit = nil
|
40
|
+
@server_name = @configuration.server_name || get_hostname
|
41
|
+
@release = @configuration.release
|
42
|
+
@modules = get_modules if @configuration.send_modules
|
43
|
+
@user = {}
|
44
|
+
@extra = {}
|
45
|
+
@tags = {}
|
46
|
+
|
47
|
+
yield self if block_given?
|
48
|
+
|
49
|
+
if !self[:http] && @context.rack_env
|
50
|
+
interface :http do |int|
|
51
|
+
int.from_rack(@context.rack_env)
|
52
|
+
end
|
53
|
+
end
|
51
54
|
|
52
|
-
@
|
53
|
-
@extra.merge!(context.extra)
|
55
|
+
init.each_pair { |key, val| instance_variable_set('@' + key.to_s, val) }
|
54
56
|
|
55
|
-
@
|
57
|
+
@user.merge!(@context.user)
|
58
|
+
@extra.merge!(@context.extra)
|
56
59
|
@tags.merge!(@configuration.tags)
|
57
|
-
@tags.merge!(
|
58
|
-
@tags.merge!(context.tags)
|
59
|
-
|
60
|
-
block.call(self) if block
|
61
|
-
|
62
|
-
if !self[:http] && context.rack_env
|
63
|
-
self.interface :http do |int|
|
64
|
-
int.from_rack(context.rack_env)
|
65
|
-
end
|
66
|
-
end
|
60
|
+
@tags.merge!(@context.tags)
|
67
61
|
|
68
62
|
# Some type coercion
|
69
|
-
@timestamp
|
63
|
+
@timestamp = @timestamp.strftime('%Y-%m-%dT%H:%M:%S') if @timestamp.is_a?(Time)
|
70
64
|
@time_spent = (@time_spent*1000).to_i if @time_spent.is_a?(Float)
|
71
|
-
@level
|
65
|
+
@level = LOG_LEVELS[@level.to_s.downcase] if @level.is_a?(String) || @level.is_a?(Symbol)
|
72
66
|
end
|
73
67
|
|
74
68
|
def get_hostname
|
@@ -99,23 +93,24 @@ module Raven
|
|
99
93
|
|
100
94
|
def to_hash
|
101
95
|
data = {
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
96
|
+
:event_id => @id,
|
97
|
+
:message => @message,
|
98
|
+
:timestamp => @timestamp,
|
99
|
+
:time_spent => @time_spent,
|
100
|
+
:level => @level,
|
101
|
+
:project => @project,
|
102
|
+
:logger => @logger,
|
103
|
+
:platform => PLATFORM,
|
110
104
|
}
|
111
|
-
data[
|
112
|
-
data[
|
113
|
-
data[
|
114
|
-
data[
|
115
|
-
data[
|
116
|
-
data[
|
105
|
+
data[:culprit] = @culprit if @culprit
|
106
|
+
data[:server_name] = @server_name if @server_name
|
107
|
+
data[:release] = @release if @release
|
108
|
+
data[:modules] = @modules if @modules
|
109
|
+
data[:extra] = @extra if @extra
|
110
|
+
data[:tags] = @tags if @tags
|
111
|
+
data[:user] = @user if @user
|
117
112
|
@interfaces.each_pair do |name, int_data|
|
118
|
-
data[name] = int_data.to_hash
|
113
|
+
data[name.to_sym] = int_data.to_hash
|
119
114
|
end
|
120
115
|
data
|
121
116
|
end
|
@@ -135,54 +130,78 @@ module Raven
|
|
135
130
|
return nil
|
136
131
|
end
|
137
132
|
|
138
|
-
context_lines = configuration[:context_lines]
|
139
|
-
|
140
133
|
new(options) do |evt|
|
134
|
+
evt.configuration = configuration
|
141
135
|
evt.message = "#{exc.class}: #{exc.message}"
|
142
136
|
evt.level = options[:level] || :error
|
143
137
|
|
144
|
-
evt
|
145
|
-
int.type = exc.class.to_s
|
146
|
-
int.value = exc.to_s
|
147
|
-
int.module = exc.class.to_s.split('::')[0...-1].join('::')
|
148
|
-
|
149
|
-
# TODO(dcramer): this needs cleaned up, but I couldn't figure out how to
|
150
|
-
# work Hashie as a non-Rubyist
|
151
|
-
if exc.backtrace
|
152
|
-
int.stacktrace = StacktraceInterface.new do |stacktrace|
|
153
|
-
backtrace = Backtrace.parse(exc.backtrace)
|
154
|
-
stacktrace.frames = backtrace.lines.reverse.map do |line|
|
155
|
-
stacktrace.frame do |frame|
|
156
|
-
frame.abs_path = line.file
|
157
|
-
frame.function = line.method
|
158
|
-
frame.lineno = line.number
|
159
|
-
frame.in_app = line.in_app
|
160
|
-
if context_lines && frame.abs_path
|
161
|
-
frame.pre_context, frame.context_line, frame.post_context = \
|
162
|
-
evt.get_file_context(frame.abs_path, frame.lineno, context_lines)
|
163
|
-
end
|
164
|
-
end
|
165
|
-
end.select { |f| f.filename }
|
166
|
-
|
167
|
-
evt.culprit = evt.get_culprit(stacktrace.frames)
|
168
|
-
end
|
169
|
-
end
|
170
|
-
end
|
138
|
+
add_exception_interface(evt, exc)
|
171
139
|
|
172
140
|
block.call(evt) if block
|
173
141
|
end
|
174
142
|
end
|
175
143
|
|
176
144
|
def self.from_message(message, options = {})
|
145
|
+
configuration = options[:configuration] || Raven.configuration
|
177
146
|
new(options) do |evt|
|
147
|
+
evt.configuration = configuration
|
178
148
|
evt.message = message
|
179
149
|
evt.level = options[:level] || :error
|
180
150
|
evt.interface :message do |int|
|
181
151
|
int.message = message
|
182
152
|
end
|
153
|
+
if options[:backtrace]
|
154
|
+
evt.interface(:stacktrace) do |int|
|
155
|
+
stacktrace_interface_from(int, evt, options[:backtrace])
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def self.add_exception_interface(evt, exc)
|
162
|
+
evt.interface(:exception) do |exc_int|
|
163
|
+
exceptions = [exc]
|
164
|
+
while exc.respond_to?(:cause) && exc.cause
|
165
|
+
exceptions << exc.cause
|
166
|
+
exc = exc.cause
|
167
|
+
end
|
168
|
+
exceptions.reverse!
|
169
|
+
|
170
|
+
exc_int.values = exceptions.map do |exc|
|
171
|
+
SingleExceptionInterface.new do |int|
|
172
|
+
int.type = exc.class.to_s
|
173
|
+
int.value = exc.to_s
|
174
|
+
int.module = exc.class.to_s.split('::')[0...-1].join('::')
|
175
|
+
|
176
|
+
int.stacktrace = if exc.backtrace
|
177
|
+
StacktraceInterface.new do |stacktrace|
|
178
|
+
stacktrace_interface_from(stacktrace, evt, exc.backtrace)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
183
|
end
|
184
184
|
end
|
185
185
|
|
186
|
+
def self.stacktrace_interface_from(int, evt, backtrace)
|
187
|
+
backtrace = Backtrace.parse(backtrace)
|
188
|
+
int.frames = backtrace.lines.reverse.map do |line|
|
189
|
+
StacktraceInterface::Frame.new.tap do |frame|
|
190
|
+
frame.abs_path = line.file
|
191
|
+
frame.function = line.method
|
192
|
+
frame.lineno = line.number
|
193
|
+
frame.in_app = line.in_app
|
194
|
+
|
195
|
+
if evt.configuration[:context_lines] && frame.abs_path
|
196
|
+
frame.pre_context, frame.context_line, frame.post_context = \
|
197
|
+
evt.get_file_context(frame.abs_path, frame.lineno, evt.configuration[:context_lines])
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end.select { |f| f.filename }
|
201
|
+
|
202
|
+
evt.culprit = evt.get_culprit(int.frames)
|
203
|
+
end
|
204
|
+
|
186
205
|
# Because linecache can go to hell
|
187
206
|
def self._source_lines(_path, _from, _to)
|
188
207
|
end
|
@@ -22,26 +22,19 @@ module Raven
|
|
22
22
|
# Use a standard Raven.configure call to configure your server credentials.
|
23
23
|
class Rack
|
24
24
|
|
25
|
-
def self.
|
25
|
+
def self.capture_type(exception, env, options = {})
|
26
26
|
if env['requested_at']
|
27
27
|
options[:time_spent] = Time.now - env['requested_at']
|
28
28
|
end
|
29
|
-
Raven.
|
29
|
+
Raven.capture_type(exception, options) do |evt|
|
30
30
|
evt.interface :http do |int|
|
31
31
|
int.from_rack(env)
|
32
32
|
end
|
33
33
|
end
|
34
34
|
end
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
options[:time_spent] = Time.now - env['requested_at']
|
39
|
-
end
|
40
|
-
Raven.capture_message(message, options) do |evt|
|
41
|
-
evt.interface :http do |int|
|
42
|
-
int.from_rack(env)
|
43
|
-
end
|
44
|
-
end
|
35
|
+
class << self
|
36
|
+
alias_method :capture_message, :capture_type
|
37
|
+
alias_method :capture_exception, :capture_type
|
45
38
|
end
|
46
39
|
|
47
40
|
def initialize(app)
|
data/lib/raven/interfaces.rb
CHANGED
@@ -1,16 +1,11 @@
|
|
1
|
-
require 'raven/better_attr_accessor'
|
2
|
-
|
3
1
|
module Raven
|
4
2
|
|
5
3
|
INTERFACES = {}
|
6
4
|
|
7
5
|
class Interface
|
8
|
-
include BetterAttrAccessor
|
9
|
-
alias_method :to_hash, :attributes
|
10
|
-
|
11
6
|
def initialize(attributes = nil)
|
12
7
|
attributes.each do |attr, value|
|
13
|
-
|
8
|
+
public_send "#{attr}=", value
|
14
9
|
end if attributes
|
15
10
|
|
16
11
|
yield self if block_given?
|
@@ -19,6 +14,10 @@ module Raven
|
|
19
14
|
def self.name(value = nil)
|
20
15
|
@interface_name ||= value
|
21
16
|
end
|
17
|
+
|
18
|
+
def to_hash
|
19
|
+
Hash[instance_variables.map { |name| [name[1..-1].to_sym, instance_variable_get(name)] } ]
|
20
|
+
end
|
22
21
|
end
|
23
22
|
|
24
23
|
def self.register_interface(mapping)
|
@@ -4,15 +4,12 @@ module Raven
|
|
4
4
|
class ExceptionInterface < Interface
|
5
5
|
|
6
6
|
name 'exception'
|
7
|
-
attr_accessor :
|
8
|
-
attr_accessor :value
|
9
|
-
attr_accessor :module
|
10
|
-
attr_accessor :stacktrace
|
7
|
+
attr_accessor :values
|
11
8
|
|
12
9
|
def to_hash(*args)
|
13
10
|
data = super(*args)
|
14
|
-
if data[
|
15
|
-
data[
|
11
|
+
if data[:values]
|
12
|
+
data[:values] = data[:values].map(&:to_hash)
|
16
13
|
end
|
17
14
|
data
|
18
15
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'raven/interfaces'
|
2
|
+
|
3
|
+
module Raven
|
4
|
+
class SingleExceptionInterface < Interface
|
5
|
+
|
6
|
+
attr_accessor :type
|
7
|
+
attr_accessor :value
|
8
|
+
attr_accessor :module
|
9
|
+
attr_accessor :stacktrace
|
10
|
+
|
11
|
+
def to_hash(*args)
|
12
|
+
data = super(*args)
|
13
|
+
if data[:stacktrace]
|
14
|
+
data[:stacktrace] = data[:stacktrace].to_hash
|
15
|
+
end
|
16
|
+
data
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -4,7 +4,7 @@ module Raven
|
|
4
4
|
class StacktraceInterface < Interface
|
5
5
|
|
6
6
|
name 'stacktrace'
|
7
|
-
attr_accessor :frames
|
7
|
+
attr_accessor :frames
|
8
8
|
|
9
9
|
def initialize(*arguments)
|
10
10
|
self.frames = []
|
@@ -13,39 +13,49 @@ module Raven
|
|
13
13
|
|
14
14
|
def to_hash(*args)
|
15
15
|
data = super(*args)
|
16
|
-
data[
|
16
|
+
data[:frames] = data[:frames].map { |frame| frame.to_hash }
|
17
17
|
data
|
18
18
|
end
|
19
19
|
|
20
|
-
def frame(attributes = nil, &block)
|
21
|
-
Frame.new(attributes, &block)
|
22
|
-
end
|
23
|
-
|
24
20
|
# Not actually an interface, but I want to use the same style
|
25
21
|
class Frame < Interface
|
26
22
|
attr_accessor :abs_path
|
27
23
|
attr_accessor :function
|
28
|
-
attr_accessor :vars
|
29
|
-
attr_accessor :pre_context
|
30
|
-
attr_accessor :post_context
|
24
|
+
attr_accessor :vars
|
25
|
+
attr_accessor :pre_context
|
26
|
+
attr_accessor :post_context
|
31
27
|
attr_accessor :context_line
|
32
28
|
attr_accessor :lineno
|
33
29
|
attr_accessor :in_app
|
34
30
|
|
31
|
+
def initialize(*arguments)
|
32
|
+
self.vars, self.pre_context, self.post_context = [], [], []
|
33
|
+
super(*arguments)
|
34
|
+
end
|
35
|
+
|
35
36
|
def filename
|
36
37
|
return nil if self.abs_path.nil?
|
37
38
|
|
38
|
-
prefix =
|
39
|
+
prefix = if project_root && self.abs_path.start_with?(project_root)
|
40
|
+
project_root
|
41
|
+
else
|
42
|
+
$LOAD_PATH.select { |s| self.abs_path.start_with?(s.to_s) }.sort_by { |s| s.to_s.length }.last
|
43
|
+
end
|
44
|
+
|
39
45
|
prefix ? self.abs_path[prefix.to_s.chomp(File::SEPARATOR).length+1..-1] : self.abs_path
|
40
46
|
end
|
41
47
|
|
48
|
+
def project_root
|
49
|
+
@project_root ||= Raven.configuration.project_root && Raven.configuration.project_root.to_s
|
50
|
+
end
|
51
|
+
|
42
52
|
def to_hash(*args)
|
43
53
|
data = super(*args)
|
44
|
-
data[
|
45
|
-
data.delete(
|
46
|
-
data.delete(
|
47
|
-
data.delete(
|
48
|
-
data.delete(
|
54
|
+
data[:filename] = self.filename
|
55
|
+
data.delete(:vars) unless self.vars && !self.vars.empty?
|
56
|
+
data.delete(:pre_context) unless self.pre_context && !self.pre_context.empty?
|
57
|
+
data.delete(:post_context) unless self.post_context && !self.post_context.empty?
|
58
|
+
data.delete(:context_line) unless self.context_line && !self.context_line.empty?
|
49
59
|
data
|
50
60
|
end
|
51
61
|
end
|
data/lib/raven/linecache.rb
CHANGED
data/lib/raven/processor.rb
CHANGED
@@ -1,27 +1,11 @@
|
|
1
|
-
require 'json'
|
2
|
-
|
3
1
|
module Raven
|
4
2
|
class Processor
|
5
|
-
attr_accessor :sanitize_fields
|
6
|
-
|
7
3
|
def initialize(client)
|
8
4
|
@client = client
|
9
|
-
@sanitize_fields = client.configuration.sanitize_fields
|
10
5
|
end
|
11
6
|
|
12
7
|
def process(data)
|
13
|
-
|
14
|
-
end
|
15
|
-
|
16
|
-
private
|
17
|
-
|
18
|
-
def parse_json_or_nil(string)
|
19
|
-
begin
|
20
|
-
OkJson.decode(string)
|
21
|
-
rescue Raven::OkJson::Error
|
22
|
-
nil
|
23
|
-
end
|
8
|
+
raise NotImplementedError
|
24
9
|
end
|
25
|
-
|
26
10
|
end
|
27
11
|
end
|
@@ -2,7 +2,11 @@ module Raven
|
|
2
2
|
class Processor::RemoveStacktrace < Processor
|
3
3
|
|
4
4
|
def process(value)
|
5
|
-
|
5
|
+
if value[:exception]
|
6
|
+
value[:exception][:values].map do |single_exception|
|
7
|
+
single_exception.delete(:stacktrace) if single_exception[:stacktrace]
|
8
|
+
end
|
9
|
+
end
|
6
10
|
|
7
11
|
value
|
8
12
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'json'
|
1
2
|
module Raven
|
2
3
|
class Processor::SanitizeData < Processor
|
3
4
|
STRING_MASK = '********'
|
@@ -5,6 +6,13 @@ module Raven
|
|
5
6
|
DEFAULT_FIELDS = %w(authorization password passwd secret ssn social(.*)?sec)
|
6
7
|
CREDIT_CARD_RE = /^(?:\d[ -]*?){13,16}$/
|
7
8
|
|
9
|
+
attr_accessor :sanitize_fields
|
10
|
+
|
11
|
+
def initialize(client)
|
12
|
+
super
|
13
|
+
self.sanitize_fields = client.configuration.sanitize_fields
|
14
|
+
end
|
15
|
+
|
8
16
|
def process(value)
|
9
17
|
value.inject(value) { |memo,(k,v)| memo[k] = sanitize(k,v); memo }
|
10
18
|
end
|
@@ -16,13 +24,17 @@ module Raven
|
|
16
24
|
v.map{|a| sanitize(k, a)}
|
17
25
|
elsif k == 'query_string'
|
18
26
|
sanitize_query_string(v)
|
19
|
-
elsif v.is_a?(
|
20
|
-
#if this string is actually a json obj, convert and sanitize
|
21
|
-
json.is_a?(Hash) ? process(json).to_json : v
|
22
|
-
elsif v.is_a?(Integer) && (CREDIT_CARD_RE.match(v.to_s) || fields_re.match(k.to_s))
|
27
|
+
elsif v.is_a?(Integer) && matches_regexes?(k,v)
|
23
28
|
INT_MASK
|
24
|
-
elsif v.is_a?(String)
|
25
|
-
|
29
|
+
elsif v.is_a?(String)
|
30
|
+
if fields_re.match(v.to_s) && (json = parse_json_or_nil(v))
|
31
|
+
#if this string is actually a json obj, convert and sanitize
|
32
|
+
json.is_a?(Hash) ? process(json).to_json : v
|
33
|
+
elsif matches_regexes?(k,v)
|
34
|
+
STRING_MASK
|
35
|
+
else
|
36
|
+
v
|
37
|
+
end
|
26
38
|
else
|
27
39
|
v
|
28
40
|
end
|
@@ -36,8 +48,20 @@ module Raven
|
|
36
48
|
URI.encode_www_form(processed_query_hash)
|
37
49
|
end
|
38
50
|
|
51
|
+
def matches_regexes?(k, v)
|
52
|
+
CREDIT_CARD_RE.match(v.to_s) || fields_re.match(k.to_s)
|
53
|
+
end
|
54
|
+
|
39
55
|
def fields_re
|
40
|
-
@fields_re ||= /(#{(DEFAULT_FIELDS
|
56
|
+
@fields_re ||= /(#{(DEFAULT_FIELDS | sanitize_fields).join("|")})/i
|
57
|
+
end
|
58
|
+
|
59
|
+
def parse_json_or_nil(string)
|
60
|
+
begin
|
61
|
+
OkJson.decode(string)
|
62
|
+
rescue Raven::OkJson::Error, NoMethodError
|
63
|
+
nil
|
64
|
+
end
|
41
65
|
end
|
42
66
|
end
|
43
67
|
end
|
data/lib/raven/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sentry-raven
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.13.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sentry Team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-04-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -66,20 +66,6 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '1.16'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: coveralls
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - ">="
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '0'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - ">="
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '0'
|
83
69
|
- !ruby/object:Gem::Dependency
|
84
70
|
name: rest-client
|
85
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -124,7 +110,6 @@ files:
|
|
124
110
|
- lib/raven/backports/uri.rb
|
125
111
|
- lib/raven/backtrace.rb
|
126
112
|
- lib/raven/base.rb
|
127
|
-
- lib/raven/better_attr_accessor.rb
|
128
113
|
- lib/raven/cli.rb
|
129
114
|
- lib/raven/client.rb
|
130
115
|
- lib/raven/configuration.rb
|
@@ -143,6 +128,7 @@ files:
|
|
143
128
|
- lib/raven/interfaces/exception.rb
|
144
129
|
- lib/raven/interfaces/http.rb
|
145
130
|
- lib/raven/interfaces/message.rb
|
131
|
+
- lib/raven/interfaces/single_exception.rb
|
146
132
|
- lib/raven/interfaces/stack_trace.rb
|
147
133
|
- lib/raven/linecache.rb
|
148
134
|
- lib/raven/logger.rb
|
@@ -1,44 +0,0 @@
|
|
1
|
-
require 'set'
|
2
|
-
|
3
|
-
module Raven
|
4
|
-
module BetterAttrAccessor
|
5
|
-
|
6
|
-
def attributes
|
7
|
-
Hash[
|
8
|
-
self.class.attributes.map do |attr|
|
9
|
-
[attr, send(attr)]
|
10
|
-
end
|
11
|
-
]
|
12
|
-
end
|
13
|
-
|
14
|
-
def self.included(base)
|
15
|
-
base.extend ClassMethods
|
16
|
-
end
|
17
|
-
|
18
|
-
module ClassMethods
|
19
|
-
def attributes
|
20
|
-
@attributes ||= Set.new
|
21
|
-
|
22
|
-
if superclass.include? BetterAttrAccessor
|
23
|
-
@attributes + superclass.attributes
|
24
|
-
else
|
25
|
-
@attributes
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
def attr_accessor(attr, options = {})
|
30
|
-
@attributes ||= Set.new
|
31
|
-
@attributes << attr.to_s
|
32
|
-
|
33
|
-
define_method attr do
|
34
|
-
if instance_variable_defined? "@#{attr}"
|
35
|
-
instance_variable_get "@#{attr}"
|
36
|
-
elsif options.key? :default
|
37
|
-
instance_variable_set "@#{attr}", options[:default].dup
|
38
|
-
end
|
39
|
-
end
|
40
|
-
attr_writer attr
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|