sentry-raven 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/raven/base.rb +23 -193
- data/lib/raven/breadcrumbs.rb +74 -0
- data/lib/raven/breadcrumbs/activesupport.rb +19 -0
- data/lib/raven/breadcrumbs/logger.rb +93 -0
- data/lib/raven/client.rb +3 -3
- data/lib/raven/configuration.rb +9 -1
- data/lib/raven/event.rb +2 -0
- data/lib/raven/instance.rb +223 -0
- data/lib/raven/integrations/rack.rb +1 -0
- data/lib/raven/integrations/rails.rb +23 -7
- data/lib/raven/logger.rb +11 -1
- data/lib/raven/processor/sanitizedata.rb +3 -2
- data/lib/raven/transports/http.rb +2 -3
- data/lib/raven/version.rb +2 -1
- metadata +16 -36
- data/lib/raven/okjson.rb +0 -614
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bd0a24e20bb50a520df079f36059cb0adb5d7673
|
4
|
+
data.tar.gz: c89f6a2a4146c6ac291e527e7ec362f12a2e82eb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ddb34f4ff56c51af45e4c369f61f9a2a01e24107bc97eca694abbb1a501902cac5254fc912e1eb9e794b8d6c21beff0a49570bb1b114d748676b39cfb7862735
|
7
|
+
data.tar.gz: b35f1609019436dd7f42ef6ed976f53bde10a15eab61b5c6a1bc362b99fa571e459913cafb02da7e1281ff366c70ba1a6a06ff8abf326fd455d1824f4a7cfe00
|
data/lib/raven/base.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'raven/version'
|
2
2
|
require 'raven/backtrace'
|
3
|
+
require 'raven/breadcrumbs'
|
3
4
|
require 'raven/processor'
|
4
5
|
require 'raven/processor/sanitizedata'
|
5
6
|
require 'raven/processor/removecircularreferences'
|
@@ -17,187 +18,33 @@ require 'raven/interfaces/single_exception'
|
|
17
18
|
require 'raven/interfaces/stack_trace'
|
18
19
|
require 'raven/interfaces/http'
|
19
20
|
require 'raven/utils/deep_merge'
|
21
|
+
require 'raven/instance'
|
22
|
+
|
23
|
+
require 'forwardable'
|
20
24
|
|
21
25
|
module Raven
|
22
26
|
AVAILABLE_INTEGRATIONS = %w[delayed_job railties sidekiq rack rake].freeze
|
23
27
|
|
24
28
|
class << self
|
25
|
-
|
26
|
-
# Must respond to #send. See Raven::Client.
|
27
|
-
attr_writer :client
|
28
|
-
|
29
|
-
# A Raven configuration object. Must act like a hash and return sensible
|
30
|
-
# values for all Raven configuration options. See Raven::Configuration.
|
31
|
-
attr_writer :configuration
|
32
|
-
|
33
|
-
def context
|
34
|
-
Context.current
|
35
|
-
end
|
36
|
-
|
37
|
-
def logger
|
38
|
-
@logger ||= Logger.new
|
39
|
-
end
|
40
|
-
|
41
|
-
# The configuration object.
|
42
|
-
# @see Raven.configure
|
43
|
-
def configuration
|
44
|
-
@configuration ||= Configuration.new
|
45
|
-
end
|
46
|
-
|
47
|
-
# The client object is responsible for delivering formatted data to the Sentry server.
|
48
|
-
def client
|
49
|
-
@client ||= Client.new(configuration)
|
50
|
-
end
|
51
|
-
|
52
|
-
# Tell the log that the client is good to go
|
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
|
60
|
-
end
|
61
|
-
alias_method :report_ready, :report_status
|
62
|
-
|
63
|
-
# Call this method to modify defaults in your initializers.
|
64
|
-
#
|
65
|
-
# @example
|
66
|
-
# Raven.configure do |config|
|
67
|
-
# config.server = 'http://...'
|
68
|
-
# end
|
69
|
-
def configure
|
70
|
-
yield(configuration) if block_given?
|
71
|
-
|
72
|
-
self.client = Client.new(configuration)
|
73
|
-
report_status
|
74
|
-
self.client
|
75
|
-
end
|
76
|
-
|
77
|
-
# Send an event to the configured Sentry server
|
78
|
-
#
|
79
|
-
# @example
|
80
|
-
# evt = Raven::Event.new(:message => "An error")
|
81
|
-
# Raven.send_event(evt)
|
82
|
-
def send_event(event)
|
83
|
-
client.send_event(event)
|
84
|
-
end
|
85
|
-
|
86
|
-
# Capture and process any exceptions from the given block, or globally if
|
87
|
-
# no block is given
|
88
|
-
#
|
89
|
-
# @example
|
90
|
-
# Raven.capture do
|
91
|
-
# MyApp.run
|
92
|
-
# end
|
93
|
-
def capture(options = {})
|
94
|
-
if 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
|
102
|
-
end
|
103
|
-
else
|
104
|
-
install_at_exit_hook(options)
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
def capture_type(obj, options = {})
|
109
|
-
return false unless should_capture?(obj)
|
110
|
-
message_or_exc = obj.is_a?(String) ? "message" : "exception"
|
111
|
-
if (evt = Event.send("from_" + message_or_exc, obj, options))
|
112
|
-
yield evt if block_given?
|
113
|
-
if configuration.async?
|
114
|
-
configuration.async.call(evt)
|
115
|
-
else
|
116
|
-
send_event(evt)
|
117
|
-
end
|
118
|
-
Thread.current[:sentry_last_event_id] = evt.id
|
119
|
-
evt
|
120
|
-
end
|
121
|
-
end
|
122
|
-
alias_method :capture_message, :capture_type
|
123
|
-
alias_method :capture_exception, :capture_type
|
124
|
-
|
125
|
-
def last_event_id
|
126
|
-
Thread.current[:sentry_last_event_id]
|
127
|
-
end
|
128
|
-
|
129
|
-
def should_capture?(message_or_exc)
|
130
|
-
if configuration.should_capture
|
131
|
-
configuration.should_capture.call(*[message_or_exc])
|
132
|
-
else
|
133
|
-
true
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
# Provides extra context to the exception prior to it being handled by
|
138
|
-
# Raven. An exception can have multiple annotations, which are merged
|
139
|
-
# together.
|
140
|
-
#
|
141
|
-
# The options (annotation) is treated the same as the ``options``
|
142
|
-
# parameter to ``capture_exception`` or ``Event.from_exception``, and
|
143
|
-
# can contain the same ``:user``, ``:tags``, etc. options as these
|
144
|
-
# methods.
|
145
|
-
#
|
146
|
-
# These will be merged with the ``options`` parameter to
|
147
|
-
# ``Event.from_exception`` at the top of execution.
|
148
|
-
#
|
149
|
-
# @example
|
150
|
-
# begin
|
151
|
-
# raise "Hello"
|
152
|
-
# rescue => exc
|
153
|
-
# Raven.annotate_exception(exc, :user => { 'id' => 1,
|
154
|
-
# 'email' => 'foo@example.com' })
|
155
|
-
# end
|
156
|
-
def annotate_exception(exc, options = {})
|
157
|
-
notes = (exc.instance_variable_defined?(:@__raven_context) && exc.instance_variable_get(:@__raven_context)) || {}
|
158
|
-
notes.merge!(options)
|
159
|
-
exc.instance_variable_set(:@__raven_context, notes)
|
160
|
-
exc
|
161
|
-
end
|
162
|
-
|
163
|
-
# Bind user context. Merges with existing context (if any).
|
164
|
-
#
|
165
|
-
# It is recommending that you send at least the ``id`` and ``email``
|
166
|
-
# values. All other values are arbitrary.
|
167
|
-
#
|
168
|
-
# @example
|
169
|
-
# Raven.user_context('id' => 1, 'email' => 'foo@example.com')
|
170
|
-
def user_context(options = nil)
|
171
|
-
self.context.user = options || {}
|
172
|
-
end
|
29
|
+
extend Forwardable
|
173
30
|
|
174
|
-
|
175
|
-
|
176
|
-
# Tags are key / value pairs which generally represent things like application version,
|
177
|
-
# environment, role, and server names.
|
178
|
-
#
|
179
|
-
# @example
|
180
|
-
# Raven.tags_context('my_custom_tag' => 'tag_value')
|
181
|
-
def tags_context(options = nil)
|
182
|
-
self.context.tags.merge!(options || {})
|
31
|
+
def instance
|
32
|
+
@instance ||= Raven::Instance.new
|
183
33
|
end
|
184
34
|
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
# @example
|
190
|
-
# Raven.extra_context('my_custom_data' => 'value')
|
191
|
-
def extra_context(options = nil)
|
192
|
-
self.context.extra.merge!(options || {})
|
193
|
-
end
|
35
|
+
def_delegators :instance, :client=, :configuration=, :context, :logger, :configuration,
|
36
|
+
:client, :report_status, :configure, :send_event, :capture, :capture_type,
|
37
|
+
:last_event_id, :should_capture?, :annotate_exception, :user_context,
|
38
|
+
:tags_context, :extra_context, :rack_context, :breadcrumbs
|
194
39
|
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
40
|
+
def_delegator :instance, :report_status, :report_ready
|
41
|
+
def_delegator :instance, :capture_type, :capture_message
|
42
|
+
def_delegator :instance, :capture_type, :capture_exception
|
43
|
+
# For cross-language compatibility
|
44
|
+
def_delegator :instance, :capture_type, :captureException
|
45
|
+
def_delegator :instance, :capture_type, :captureMessage
|
46
|
+
def_delegator :instance, :annotate_exception, :annotateException
|
47
|
+
def_delegator :instance, :annotate_exception, :annotate
|
201
48
|
|
202
49
|
# Injects various integrations. Default behavior: inject all available integrations
|
203
50
|
def inject
|
@@ -232,29 +79,12 @@ module Raven
|
|
232
79
|
self.logger.warn "Unable to load raven/integrations/#{integration}: #{error}"
|
233
80
|
end
|
234
81
|
|
235
|
-
def
|
236
|
-
return if opts[:to].nil?
|
82
|
+
def safely_prepend(module_name, opts = {})
|
83
|
+
return if opts[:to].nil? || opts[:from].nil?
|
237
84
|
if opts[:to].respond_to?(:prepend, true)
|
238
|
-
opts[:to].send(:prepend,
|
85
|
+
opts[:to].send(:prepend, opts[:from].const_get(module_name))
|
239
86
|
else
|
240
|
-
opts[:to].send(:include,
|
241
|
-
end
|
242
|
-
end
|
243
|
-
|
244
|
-
# For cross-language compat
|
245
|
-
alias :captureException :capture_exception
|
246
|
-
alias :captureMessage :capture_message
|
247
|
-
alias :annotateException :annotate_exception
|
248
|
-
alias :annotate :annotate_exception
|
249
|
-
|
250
|
-
private
|
251
|
-
|
252
|
-
def install_at_exit_hook(options)
|
253
|
-
at_exit do
|
254
|
-
if $!
|
255
|
-
logger.debug "Caught a post-mortem exception: #{$!.inspect}"
|
256
|
-
capture_exception($!, options)
|
257
|
-
end
|
87
|
+
opts[:to].send(:include, opts[:from].const_get("Old" + module_name))
|
258
88
|
end
|
259
89
|
end
|
260
90
|
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Raven
|
2
|
+
class Breadcrumb
|
3
|
+
attr_accessor :category, :data, :message, :level, :timestamp, :type
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@category = nil
|
7
|
+
@data = {}
|
8
|
+
@level = nil
|
9
|
+
@message = nil
|
10
|
+
@timestamp = Time.now.to_i
|
11
|
+
@type = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_hash
|
15
|
+
{
|
16
|
+
:category => @category,
|
17
|
+
:data => @data,
|
18
|
+
:level => @level,
|
19
|
+
:message => @message,
|
20
|
+
:timestamp => @timestamp,
|
21
|
+
:type => @type
|
22
|
+
}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
module Raven
|
28
|
+
class BreadcrumbBuffer
|
29
|
+
include Enumerable
|
30
|
+
|
31
|
+
def self.current
|
32
|
+
Thread.current[:sentry_breadcrumbs] ||= new
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.clear!
|
36
|
+
Thread.current[:sentry_breadcrumbs] = nil
|
37
|
+
end
|
38
|
+
|
39
|
+
def initialize(size = 100)
|
40
|
+
@buffer = Array.new(size)
|
41
|
+
end
|
42
|
+
|
43
|
+
def record(crumb = nil)
|
44
|
+
if block_given?
|
45
|
+
crumb = Breadcrumb.new if crumb.nil?
|
46
|
+
yield(crumb)
|
47
|
+
end
|
48
|
+
@buffer.slice!(0)
|
49
|
+
@buffer << crumb
|
50
|
+
end
|
51
|
+
|
52
|
+
def members
|
53
|
+
@buffer.compact
|
54
|
+
end
|
55
|
+
|
56
|
+
def peek
|
57
|
+
members.last
|
58
|
+
end
|
59
|
+
|
60
|
+
def each(&block)
|
61
|
+
members.each(&block)
|
62
|
+
end
|
63
|
+
|
64
|
+
def empty?
|
65
|
+
!members.any?
|
66
|
+
end
|
67
|
+
|
68
|
+
def to_hash
|
69
|
+
{
|
70
|
+
:values => members.map(&:to_hash)
|
71
|
+
}
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Raven
|
2
|
+
module ActiveSupportBreadcrumbs
|
3
|
+
class << self
|
4
|
+
def add(name, started, _finished, _unique_id, data)
|
5
|
+
Raven.breadcrumbs.record do |crumb|
|
6
|
+
crumb.data = data
|
7
|
+
crumb.category = name
|
8
|
+
crumb.timestamp = started.to_i
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def inject
|
13
|
+
ActiveSupport::Notifications.subscribe(/.*/) do |name, started, finished, unique_id, data|
|
14
|
+
add(name, started, finished, unique_id, data)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module Raven
|
4
|
+
module BreadcrumbLogger
|
5
|
+
LEVELS = {
|
6
|
+
::Logger::DEBUG => 'debug',
|
7
|
+
::Logger::INFO => 'info',
|
8
|
+
::Logger::WARN => 'warn',
|
9
|
+
::Logger::ERROR => 'error',
|
10
|
+
::Logger::FATAL => 'fatal'
|
11
|
+
}.freeze
|
12
|
+
|
13
|
+
EXC_FORMAT = /^([a-zA-Z0-9]+)\:\s(.*)$/
|
14
|
+
|
15
|
+
def self.parse_exception(message)
|
16
|
+
lines = message.split(/\n\s*/)
|
17
|
+
# TODO: wat
|
18
|
+
return nil unless lines.length > 2
|
19
|
+
|
20
|
+
match = lines[0].match(EXC_FORMAT)
|
21
|
+
return nil unless match
|
22
|
+
|
23
|
+
_, type, value = match.to_a
|
24
|
+
[type, value]
|
25
|
+
end
|
26
|
+
|
27
|
+
def add(*args)
|
28
|
+
add_breadcrumb(*args)
|
29
|
+
super
|
30
|
+
end
|
31
|
+
|
32
|
+
def add_breadcrumb(severity, message = nil, progname = nil)
|
33
|
+
message = progname if message.nil? # see Ruby's Logger docs for why
|
34
|
+
return if ignored_logger?(progname)
|
35
|
+
return if message.nil? || message == ""
|
36
|
+
|
37
|
+
# some loggers will add leading/trailing space as they (incorrectly, mind you)
|
38
|
+
# think of logging as a shortcut to std{out,err}
|
39
|
+
message = message.strip
|
40
|
+
|
41
|
+
last_crumb = Raven.breadcrumbs.peek
|
42
|
+
# try to avoid dupes from logger broadcasts
|
43
|
+
if last_crumb.nil? || last_crumb.message != message
|
44
|
+
error = Raven::BreadcrumbLogger.parse_exception(message)
|
45
|
+
# TODO(dcramer): we need to filter out the "currently captured error"
|
46
|
+
if error
|
47
|
+
Raven.breadcrumbs.record do |crumb|
|
48
|
+
crumb.level = Raven::BreadcrumbLogger::LEVELS.fetch(severity, nil)
|
49
|
+
crumb.category = progname || 'error'
|
50
|
+
crumb.type = 'error'
|
51
|
+
crumb.data = {
|
52
|
+
:type => error[0],
|
53
|
+
:value => error[1]
|
54
|
+
}
|
55
|
+
end
|
56
|
+
else
|
57
|
+
Raven.breadcrumbs.record do |crumb|
|
58
|
+
crumb.level = Raven::BreadcrumbLogger::LEVELS.fetch(severity, nil)
|
59
|
+
crumb.category = progname || 'logger'
|
60
|
+
crumb.message = message
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def ignored_logger?(progname)
|
69
|
+
progname == "sentry" ||
|
70
|
+
Raven.configuration.exclude_loggers.include?(progname)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
module OldBreadcrumbLogger
|
74
|
+
def self.included(base)
|
75
|
+
base.class_eval do
|
76
|
+
include Raven::BreadcrumbLogger
|
77
|
+
alias_method :add_without_raven, :add
|
78
|
+
alias_method :add, :add_with_raven
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def add_with_raven(*args)
|
83
|
+
add_breadcrumb(*args)
|
84
|
+
add_without_raven(*args)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
Raven.safely_prepend(
|
90
|
+
"BreadcrumbLogger",
|
91
|
+
:from => Raven,
|
92
|
+
:to => ::Logger
|
93
|
+
)
|
data/lib/raven/client.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require 'zlib'
|
3
2
|
require 'base64'
|
3
|
+
require 'json'
|
4
|
+
require 'zlib'
|
4
5
|
|
5
6
|
require 'raven/version'
|
6
|
-
require 'raven/okjson'
|
7
7
|
require 'raven/transports/http'
|
8
8
|
|
9
9
|
module Raven
|
@@ -73,7 +73,7 @@ module Raven
|
|
73
73
|
|
74
74
|
def encode(event)
|
75
75
|
hash = @processors.reduce(event.to_hash) { |memo, p| p.process(memo) }
|
76
|
-
encoded =
|
76
|
+
encoded = JSON.generate(hash)
|
77
77
|
|
78
78
|
case configuration.encoding
|
79
79
|
when 'gzip'
|