sentry-raven 2.6.3 → 2.7.1
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/.rspec +0 -1
- data/.rubocop.yml +1 -1
- data/.travis.yml +6 -5
- data/README.md +0 -3
- data/changelog.md +22 -0
- data/docs/breadcrumbs.rst +11 -0
- data/docs/config.rst +17 -5
- data/docs/context.rst +23 -0
- data/docs/index.rst +1 -0
- data/docs/integrations/puma.rst +1 -1
- data/docs/processors.rst +124 -0
- data/lib/raven/backtrace.rb +2 -1
- data/lib/raven/base.rb +6 -0
- data/lib/raven/cli.rb +1 -1
- data/lib/raven/client.rb +0 -3
- data/lib/raven/configuration.rb +60 -4
- data/lib/raven/context.rb +2 -1
- data/lib/raven/event.rb +136 -211
- data/lib/raven/integrations/rack.rb +1 -0
- data/lib/raven/integrations/rails.rb +2 -0
- data/lib/raven/integrations/rails/controller_transaction.rb +13 -0
- data/lib/raven/integrations/rake.rb +6 -1
- data/lib/raven/integrations/sidekiq.rb +11 -7
- data/lib/raven/interfaces/exception.rb +0 -2
- data/lib/raven/interfaces/http.rb +0 -2
- data/lib/raven/interfaces/single_exception.rb +0 -2
- data/lib/raven/interfaces/stack_trace.rb +3 -14
- data/lib/raven/processor/sanitizedata.rb +2 -2
- data/lib/raven/processor/utf8conversion.rb +1 -0
- data/lib/raven/transports.rb +0 -2
- data/lib/raven/transports/http.rb +0 -1
- data/lib/raven/utils/deep_merge.rb +6 -14
- data/lib/raven/version.rb +1 -1
- metadata +5 -4
- data/lib/raven/error.rb +0 -4
data/lib/raven/context.rb
CHANGED
@@ -10,7 +10,7 @@ module Raven
|
|
10
10
|
Thread.current[:sentry_context] = nil
|
11
11
|
end
|
12
12
|
|
13
|
-
attr_accessor :extra, :server_os, :rack_env, :runtime, :tags, :user
|
13
|
+
attr_accessor :transaction, :extra, :server_os, :rack_env, :runtime, :tags, :user
|
14
14
|
|
15
15
|
def initialize
|
16
16
|
self.server_os = self.class.os_context
|
@@ -19,6 +19,7 @@ module Raven
|
|
19
19
|
self.rack_env = nil
|
20
20
|
self.tags = {}
|
21
21
|
self.user = {}
|
22
|
+
self.transaction = []
|
22
23
|
end
|
23
24
|
|
24
25
|
class << self
|
data/lib/raven/event.rb
CHANGED
@@ -1,227 +1,117 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require 'rubygems'
|
3
2
|
require 'socket'
|
4
3
|
require 'securerandom'
|
5
|
-
require 'digest/md5'
|
6
|
-
|
7
|
-
require 'raven/error'
|
8
|
-
require 'raven/linecache'
|
9
4
|
|
10
5
|
module Raven
|
11
6
|
class Event
|
12
|
-
LOG_LEVELS = {
|
13
|
-
"debug" => 10,
|
14
|
-
"info" => 20,
|
15
|
-
"warn" => 30,
|
16
|
-
"warning" => 30,
|
17
|
-
"error" => 40,
|
18
|
-
"fatal" => 50
|
19
|
-
}.freeze
|
20
|
-
|
21
|
-
BACKTRACE_RE = /^(.+?):(\d+)(?::in `(.+?)')?$/
|
22
7
|
# See Sentry server default limits at
|
23
8
|
# https://github.com/getsentry/sentry/blob/master/src/sentry/conf/server.py
|
24
9
|
MAX_MESSAGE_SIZE_IN_BYTES = 1024 * 8
|
25
10
|
|
26
|
-
PLATFORM = "ruby".freeze
|
27
11
|
SDK = { "name" => "raven-ruby", "version" => Raven::VERSION }.freeze
|
28
12
|
|
29
13
|
attr_accessor :id, :timestamp, :time_spent, :level, :logger,
|
30
|
-
:
|
14
|
+
:transaction, :server_name, :release, :modules, :extra, :tags,
|
31
15
|
:context, :configuration, :checksum, :fingerprint, :environment,
|
32
|
-
:server_os, :runtime, :breadcrumbs, :user, :backtrace, :
|
16
|
+
:server_os, :runtime, :breadcrumbs, :user, :backtrace, :platform,
|
17
|
+
:sdk
|
18
|
+
alias event_id id
|
33
19
|
|
34
20
|
def initialize(init = {})
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
@
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
@extra = {} # TODO: contexts
|
51
|
-
@server_os = {} # TODO: contexts
|
52
|
-
@runtime = {} # TODO: contexts
|
53
|
-
@tags = {} # TODO: contexts
|
54
|
-
@checksum = nil
|
55
|
-
@fingerprint = nil
|
56
|
-
@environment = @configuration.current_environment
|
21
|
+
self.configuration = Raven.configuration
|
22
|
+
self.breadcrumbs = Raven.breadcrumbs
|
23
|
+
self.context = Raven.context
|
24
|
+
self.id = SecureRandom.uuid.delete("-")
|
25
|
+
self.timestamp = Time.now.utc
|
26
|
+
self.level = :error
|
27
|
+
self.logger = :ruby
|
28
|
+
self.platform = :ruby
|
29
|
+
self.sdk = SDK
|
30
|
+
@interfaces = {}
|
31
|
+
self.user = {} # TODO: contexts
|
32
|
+
self.extra = {} # TODO: contexts
|
33
|
+
self.server_os = {} # TODO: contexts
|
34
|
+
self.runtime = {} # TODO: contexts
|
35
|
+
self.tags = {} # TODO: contexts
|
57
36
|
|
58
37
|
yield self if block_given?
|
59
38
|
|
60
|
-
|
39
|
+
init.each_pair { |key, val| public_send("#{key}=", val) }
|
40
|
+
|
41
|
+
self.transaction ||= context.transaction.last
|
42
|
+
self.server_name ||= configuration.server_name
|
43
|
+
self.release ||= configuration.release
|
44
|
+
self.modules = list_gem_specs if configuration.send_modules
|
45
|
+
self.environment ||= configuration.current_environment
|
46
|
+
|
47
|
+
if !self[:http] && context.rack_env
|
61
48
|
interface :http do |int|
|
62
|
-
int.from_rack(
|
49
|
+
int.from_rack(context.rack_env)
|
63
50
|
end
|
64
|
-
end
|
65
51
|
|
66
|
-
|
67
|
-
@context.user[:ip_address] = calculate_real_ip_from_rack
|
52
|
+
context.user[:ip_address] = calculate_real_ip_from_rack
|
68
53
|
end
|
69
54
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
@extra = @context.extra.merge(@extra) # TODO: contexts
|
74
|
-
@tags = @configuration.tags.merge(@context.tags).merge(@tags) # TODO: contexts
|
75
|
-
|
76
|
-
# Some type coercion
|
77
|
-
@timestamp = @timestamp.strftime('%Y-%m-%dT%H:%M:%S') if @timestamp.is_a?(Time)
|
78
|
-
@time_spent = (@time_spent * 1000).to_i if @time_spent.is_a?(Float)
|
79
|
-
@level = LOG_LEVELS[@level.to_s.downcase] if @level.is_a?(String) || @level.is_a?(Symbol)
|
55
|
+
self.user = context.user.merge(user) # TODO: contexts
|
56
|
+
self.extra = context.extra.merge(extra) # TODO: contexts
|
57
|
+
self.tags = configuration.tags.merge(context.tags).merge(tags) # TODO: contexts
|
80
58
|
end
|
81
59
|
|
82
|
-
def
|
83
|
-
|
84
|
-
|
60
|
+
def self.from_exception(exc, options = {}, &block)
|
61
|
+
exception_context = if exc.instance_variable_defined?(:@__raven_context)
|
62
|
+
exc.instance_variable_get(:@__raven_context)
|
63
|
+
elsif exc.respond_to?(:raven_context)
|
64
|
+
exc.raven_context
|
65
|
+
else
|
66
|
+
{}
|
67
|
+
end
|
68
|
+
options = Raven::Utils::DeepMergeHash.deep_merge(exception_context, options)
|
85
69
|
|
86
|
-
|
87
|
-
|
88
|
-
interface(:message) do |int|
|
89
|
-
int.message = message
|
90
|
-
int.params = params
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
class << self
|
95
|
-
def from_exception(exc, options = {}, &block)
|
96
|
-
exception_context = get_exception_context(exc) || {}
|
97
|
-
options = Raven::Utils::DeepMergeHash.deep_merge(exception_context, options)
|
98
|
-
|
99
|
-
configuration = options[:configuration] || Raven.configuration
|
100
|
-
if exc.is_a?(Raven::Error)
|
101
|
-
# Try to prevent error reporting loops
|
102
|
-
configuration.logger.debug "Refusing to capture Raven error: #{exc.inspect}"
|
103
|
-
return nil
|
104
|
-
end
|
105
|
-
if configuration[:excluded_exceptions].any? { |x| get_exception_class(x) === exc }
|
106
|
-
configuration.logger.debug "User excluded error: #{exc.inspect}"
|
107
|
-
return nil
|
108
|
-
end
|
70
|
+
configuration = options[:configuration] || Raven.configuration
|
71
|
+
return unless configuration.exception_class_allowed?(exc)
|
109
72
|
|
110
|
-
|
111
|
-
|
112
|
-
evt.message = "#{exc.class}: #{exc.message}".byteslice(0...MAX_MESSAGE_SIZE_IN_BYTES) # Messages limited to 10kb
|
113
|
-
evt.level = options[:level] || :error
|
73
|
+
new(options) do |evt|
|
74
|
+
evt.message = "#{exc.class}: #{exc.message}"
|
114
75
|
|
115
|
-
|
76
|
+
evt.add_exception_interface(exc)
|
116
77
|
|
117
|
-
|
118
|
-
end
|
78
|
+
yield evt if block
|
119
79
|
end
|
80
|
+
end
|
120
81
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
evt.level = options[:level] || :error
|
128
|
-
evt.message = message, options[:message_params] || []
|
129
|
-
if options[:backtrace]
|
130
|
-
evt.interface(:stacktrace) do |int|
|
131
|
-
stacktrace_interface_from(int, evt, options[:backtrace])
|
132
|
-
end
|
82
|
+
def self.from_message(message, options = {})
|
83
|
+
new(options) do |evt|
|
84
|
+
evt.message = message, options[:message_params] || []
|
85
|
+
if options[:backtrace]
|
86
|
+
evt.interface(:stacktrace) do |int|
|
87
|
+
int.frames = evt.stacktrace_interface_from(options[:backtrace])
|
133
88
|
end
|
134
89
|
end
|
135
90
|
end
|
91
|
+
end
|
136
92
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
x.is_a?(Module) ? x : qualified_const_get(x)
|
141
|
-
end
|
142
|
-
|
143
|
-
# In Ruby <2.0 const_get can't lookup "SomeModule::SomeClass" in one go
|
144
|
-
def qualified_const_get(x)
|
145
|
-
x = x.to_s
|
146
|
-
parts = x.split("::")
|
147
|
-
parts.reject!(&:empty?)
|
148
|
-
|
149
|
-
if parts.size < 2
|
150
|
-
Object.const_get(x)
|
151
|
-
else
|
152
|
-
parts.inject(Object) { |a, e| a.const_get(e) }
|
153
|
-
end
|
154
|
-
rescue NameError # There's no way to safely ask if a constant exist for an unknown string
|
155
|
-
nil
|
156
|
-
end
|
157
|
-
|
158
|
-
def get_exception_context(exc)
|
159
|
-
if exc.instance_variable_defined?(:@__raven_context)
|
160
|
-
exc.instance_variable_get(:@__raven_context)
|
161
|
-
elsif exc.respond_to?(:raven_context)
|
162
|
-
exc.raven_context
|
163
|
-
end
|
164
|
-
end
|
93
|
+
def message
|
94
|
+
@interfaces[:logentry] && @interfaces[:logentry].unformatted_message
|
95
|
+
end
|
165
96
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
while exc.respond_to?(:cause) && exc.cause
|
173
|
-
exc = exc.cause
|
174
|
-
break if context.include?(exc.object_id)
|
175
|
-
exceptions << exc
|
176
|
-
context.add(exc.object_id)
|
177
|
-
end
|
178
|
-
exceptions.reverse!
|
179
|
-
|
180
|
-
exc_int.values = exceptions.map do |e|
|
181
|
-
SingleExceptionInterface.new do |int|
|
182
|
-
int.type = e.class.to_s
|
183
|
-
int.value = e.to_s
|
184
|
-
int.module = e.class.to_s.split('::')[0...-1].join('::')
|
185
|
-
|
186
|
-
int.stacktrace =
|
187
|
-
if e.backtrace && !backtraces.include?(e.backtrace.object_id)
|
188
|
-
backtraces << e.backtrace.object_id
|
189
|
-
StacktraceInterface.new do |stacktrace|
|
190
|
-
stacktrace_interface_from(stacktrace, evt, e.backtrace)
|
191
|
-
end
|
192
|
-
end
|
193
|
-
end
|
194
|
-
end
|
195
|
-
end
|
97
|
+
def message=(args)
|
98
|
+
message, params = *args
|
99
|
+
interface(:message) do |int|
|
100
|
+
int.message = message.byteslice(0...MAX_MESSAGE_SIZE_IN_BYTES) # Messages limited to 10kb
|
101
|
+
int.params = params
|
196
102
|
end
|
103
|
+
end
|
197
104
|
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
int.frames = []
|
202
|
-
backtrace.lines.reverse_each do |line|
|
203
|
-
frame = StacktraceInterface::Frame.new
|
204
|
-
frame.abs_path = line.file if line.file
|
205
|
-
frame.function = line.method if line.method
|
206
|
-
frame.lineno = line.number
|
207
|
-
frame.in_app = line.in_app
|
208
|
-
frame.module = line.module_name if line.module_name
|
209
|
-
|
210
|
-
if evt.configuration[:context_lines] && frame.abs_path
|
211
|
-
frame.pre_context, frame.context_line, frame.post_context = \
|
212
|
-
evt.get_file_context(frame.abs_path, frame.lineno, evt.configuration[:context_lines])
|
213
|
-
end
|
214
|
-
|
215
|
-
int.frames << frame if frame.filename
|
216
|
-
end
|
105
|
+
def timestamp=(time)
|
106
|
+
@timestamp = time.is_a?(Time) ? time.strftime('%Y-%m-%dT%H:%M:%S') : time
|
107
|
+
end
|
217
108
|
|
218
|
-
|
219
|
-
|
109
|
+
def time_spent=(time)
|
110
|
+
@time_spent = time.is_a?(Float) ? (time * 1000).to_i : time
|
220
111
|
end
|
221
112
|
|
222
|
-
def
|
223
|
-
|
224
|
-
Hash[Gem::Specification.map { |spec| [spec.name, spec.version.to_s] }] if Gem::Specification.respond_to?(:map)
|
113
|
+
def level=(new_level) # needed to meet the Sentry spec
|
114
|
+
@level = new_level == "warn" || new_level == :warn ? :warning : new_level
|
225
115
|
end
|
226
116
|
|
227
117
|
def interface(name, value = nil, &block)
|
@@ -240,47 +130,63 @@ module Raven
|
|
240
130
|
end
|
241
131
|
|
242
132
|
def to_hash
|
243
|
-
data =
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
:sdk => SDK
|
250
|
-
}
|
251
|
-
|
252
|
-
data[:logger] = @logger if @logger
|
253
|
-
data[:culprit] = @culprit if @culprit
|
254
|
-
data[:server_name] = @server_name if @server_name
|
255
|
-
data[:release] = @release if @release
|
256
|
-
data[:environment] = @environment if @environment
|
257
|
-
data[:fingerprint] = @fingerprint if @fingerprint
|
258
|
-
data[:modules] = @modules if @modules
|
259
|
-
data[:extra] = @extra if @extra
|
260
|
-
data[:tags] = @tags if @tags
|
261
|
-
data[:user] = @user if @user
|
133
|
+
data = [:checksum, :environment, :event_id, :extra, :fingerprint, :level,
|
134
|
+
:logger, :message, :modules, :platform, :release, :sdk, :server_name,
|
135
|
+
:tags, :time_spent, :timestamp, :transaction, :user].each_with_object({}) do |att, memo|
|
136
|
+
memo[att] = public_send(att) if public_send(att)
|
137
|
+
end
|
138
|
+
|
262
139
|
data[:breadcrumbs] = @breadcrumbs.to_hash unless @breadcrumbs.empty?
|
263
|
-
data[:checksum] = @checksum if @checksum
|
264
140
|
|
265
141
|
@interfaces.each_pair do |name, int_data|
|
266
142
|
data[name.to_sym] = int_data.to_hash
|
267
143
|
end
|
268
|
-
data[:message] = message
|
269
144
|
data
|
270
145
|
end
|
271
146
|
|
272
|
-
def
|
273
|
-
|
147
|
+
def to_json_compatible
|
148
|
+
cleaned_hash = async_json_processors.reduce(to_hash) { |a, e| e.process(a) }
|
149
|
+
JSON.parse(JSON.generate(cleaned_hash))
|
274
150
|
end
|
275
151
|
|
276
|
-
def
|
277
|
-
|
278
|
-
|
152
|
+
def add_exception_interface(exc)
|
153
|
+
interface(:exception) do |exc_int|
|
154
|
+
exceptions = exception_chain_to_array(exc)
|
155
|
+
backtraces = Set.new
|
156
|
+
exc_int.values = exceptions.map do |e|
|
157
|
+
SingleExceptionInterface.new do |int|
|
158
|
+
int.type = e.class.to_s
|
159
|
+
int.value = e.to_s
|
160
|
+
int.module = e.class.to_s.split('::')[0...-1].join('::')
|
161
|
+
|
162
|
+
int.stacktrace =
|
163
|
+
if e.backtrace && !backtraces.include?(e.backtrace.object_id)
|
164
|
+
backtraces << e.backtrace.object_id
|
165
|
+
StacktraceInterface.new do |stacktrace|
|
166
|
+
stacktrace.frames = stacktrace_interface_from(e.backtrace)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
279
172
|
end
|
280
173
|
|
281
|
-
def
|
282
|
-
|
283
|
-
|
174
|
+
def stacktrace_interface_from(backtrace)
|
175
|
+
Backtrace.parse(backtrace).lines.reverse.each_with_object([]) do |line, memo|
|
176
|
+
frame = StacktraceInterface::Frame.new
|
177
|
+
frame.abs_path = line.file if line.file
|
178
|
+
frame.function = line.method if line.method
|
179
|
+
frame.lineno = line.number
|
180
|
+
frame.in_app = line.in_app
|
181
|
+
frame.module = line.module_name if line.module_name
|
182
|
+
|
183
|
+
if configuration[:context_lines] && frame.abs_path
|
184
|
+
frame.pre_context, frame.context_line, frame.post_context = \
|
185
|
+
configuration.linecache.get_file_context(frame.abs_path, frame.lineno, configuration[:context_lines])
|
186
|
+
end
|
187
|
+
|
188
|
+
memo << frame if frame.filename
|
189
|
+
end
|
284
190
|
end
|
285
191
|
|
286
192
|
# For cross-language compat
|
@@ -310,5 +216,24 @@ module Raven
|
|
310
216
|
Raven::Processor::UTF8Conversion
|
311
217
|
].map { |v| v.new(self) }
|
312
218
|
end
|
219
|
+
|
220
|
+
def exception_chain_to_array(exc)
|
221
|
+
if exc.respond_to?(:cause) && exc.cause
|
222
|
+
exceptions = [exc]
|
223
|
+
while exc.cause
|
224
|
+
exc = exc.cause
|
225
|
+
break if exceptions.any? { |e| e.object_id == exc.object_id }
|
226
|
+
exceptions << exc
|
227
|
+
end
|
228
|
+
exceptions.reverse!
|
229
|
+
else
|
230
|
+
[exc]
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
def list_gem_specs
|
235
|
+
# Older versions of Rubygems don't support iterating over all specs
|
236
|
+
Hash[Gem::Specification.map { |spec| [spec.name, spec.version.to_s] }] if Gem::Specification.respond_to?(:map)
|
237
|
+
end
|
313
238
|
end
|
314
239
|
end
|
@@ -4,6 +4,7 @@ module Raven
|
|
4
4
|
class Rails < ::Rails::Railtie
|
5
5
|
require 'raven/integrations/rails/overrides/streaming_reporter'
|
6
6
|
require 'raven/integrations/rails/controller_methods'
|
7
|
+
require 'raven/integrations/rails/controller_transaction'
|
7
8
|
|
8
9
|
initializer "raven.use_rack_middleware" do |app|
|
9
10
|
app.config.middleware.insert 0, Raven::Rack
|
@@ -12,6 +13,7 @@ module Raven
|
|
12
13
|
initializer 'raven.action_controller' do
|
13
14
|
ActiveSupport.on_load :action_controller do
|
14
15
|
include Raven::Rails::ControllerMethods
|
16
|
+
include Raven::Rails::ControllerTransaction
|
15
17
|
if ::Rails::VERSION::STRING >= "4.0.0"
|
16
18
|
Raven.safely_prepend(
|
17
19
|
"StreamingReporter",
|