sentry-raven 1.1.0 → 1.2.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/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'
|