bugsnag 6.22.1 → 6.24.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +93 -0
- data/VERSION +1 -1
- data/lib/bugsnag/breadcrumb_type.rb +14 -0
- data/lib/bugsnag/breadcrumbs/breadcrumb.rb +34 -1
- data/lib/bugsnag/breadcrumbs/breadcrumbs.rb +1 -0
- data/lib/bugsnag/breadcrumbs/on_breadcrumb_callback_list.rb +50 -0
- data/lib/bugsnag/cleaner.rb +31 -18
- data/lib/bugsnag/configuration.rb +240 -22
- data/lib/bugsnag/delivery/synchronous.rb +2 -2
- data/lib/bugsnag/delivery/thread_queue.rb +2 -2
- data/lib/bugsnag/endpoint_configuration.rb +11 -0
- data/lib/bugsnag/endpoint_validator.rb +80 -0
- data/lib/bugsnag/error.rb +25 -0
- data/lib/bugsnag/event.rb +7 -0
- data/lib/bugsnag/integrations/railtie.rb +27 -2
- data/lib/bugsnag/integrations/resque.rb +10 -6
- data/lib/bugsnag/middleware/active_job.rb +1 -1
- data/lib/bugsnag/middleware/delayed_job.rb +1 -1
- data/lib/bugsnag/middleware/exception_meta_data.rb +2 -0
- data/lib/bugsnag/middleware/rack_request.rb +84 -19
- data/lib/bugsnag/middleware/rails3_request.rb +2 -2
- data/lib/bugsnag/middleware/rake.rb +1 -1
- data/lib/bugsnag/middleware/session_data.rb +3 -1
- data/lib/bugsnag/middleware/sidekiq.rb +1 -1
- data/lib/bugsnag/report.rb +166 -6
- data/lib/bugsnag/session_tracker.rb +52 -12
- data/lib/bugsnag/stacktrace.rb +10 -1
- data/lib/bugsnag/tasks/bugsnag.rake +1 -1
- data/lib/bugsnag/utility/duplicator.rb +124 -0
- data/lib/bugsnag/utility/metadata_delegate.rb +102 -0
- data/lib/bugsnag.rb +126 -4
- metadata +14 -6
@@ -1,8 +1,11 @@
|
|
1
|
+
require "json"
|
2
|
+
|
1
3
|
module Bugsnag::Middleware
|
2
4
|
##
|
3
5
|
# Extracts and attaches rack data to an error report
|
4
6
|
class RackRequest
|
5
7
|
SPOOF = "[SPOOF]".freeze
|
8
|
+
COOKIE_HEADER = "Cookie".freeze
|
6
9
|
|
7
10
|
def initialize(bugsnag)
|
8
11
|
@bugsnag = bugsnag
|
@@ -18,8 +21,8 @@ module Bugsnag::Middleware
|
|
18
21
|
client_ip = request.ip.to_s rescue SPOOF
|
19
22
|
session = env["rack.session"]
|
20
23
|
|
21
|
-
# Set the context
|
22
|
-
report.
|
24
|
+
# Set the automatic context
|
25
|
+
report.automatic_context = "#{request.request_method} #{request.path}"
|
23
26
|
|
24
27
|
# Set a sensible default for user_id
|
25
28
|
report.user["id"] = request.ip
|
@@ -42,22 +45,6 @@ module Bugsnag::Middleware
|
|
42
45
|
Bugsnag.configuration.warn "RackRequest - Rescued error while cleaning request.referer: #{stde}"
|
43
46
|
end
|
44
47
|
|
45
|
-
headers = {}
|
46
|
-
|
47
|
-
env.each_pair do |key, value|
|
48
|
-
if key.to_s.start_with?("HTTP_")
|
49
|
-
header_key = key[5..-1]
|
50
|
-
elsif ["CONTENT_TYPE", "CONTENT_LENGTH"].include?(key)
|
51
|
-
header_key = key
|
52
|
-
else
|
53
|
-
next
|
54
|
-
end
|
55
|
-
|
56
|
-
headers[header_key.split("_").map {|s| s.capitalize}.join("-")] = value
|
57
|
-
end
|
58
|
-
|
59
|
-
headers["Referer"] = referer if headers["Referer"]
|
60
|
-
|
61
48
|
# Add a request tab
|
62
49
|
report.add_tab(:request, {
|
63
50
|
:url => url,
|
@@ -65,9 +52,17 @@ module Bugsnag::Middleware
|
|
65
52
|
:params => params.to_hash,
|
66
53
|
:referer => referer,
|
67
54
|
:clientIp => client_ip,
|
68
|
-
:headers =>
|
55
|
+
:headers => format_headers(env, referer)
|
69
56
|
})
|
70
57
|
|
58
|
+
# add the HTTP version if present
|
59
|
+
if env["SERVER_PROTOCOL"]
|
60
|
+
report.add_metadata(:request, :httpVersion, env["SERVER_PROTOCOL"])
|
61
|
+
end
|
62
|
+
|
63
|
+
add_request_body(report, request, env)
|
64
|
+
add_cookies(report, request)
|
65
|
+
|
71
66
|
# Add an environment tab
|
72
67
|
if report.configuration.send_environment
|
73
68
|
report.add_tab(:environment, env)
|
@@ -87,5 +82,75 @@ module Bugsnag::Middleware
|
|
87
82
|
|
88
83
|
@bugsnag.call(report)
|
89
84
|
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def format_headers(env, referer)
|
89
|
+
headers = {}
|
90
|
+
|
91
|
+
env.each_pair do |key, value|
|
92
|
+
if key.to_s.start_with?("HTTP_")
|
93
|
+
header_key = key[5..-1]
|
94
|
+
elsif ["CONTENT_TYPE", "CONTENT_LENGTH"].include?(key)
|
95
|
+
header_key = key
|
96
|
+
else
|
97
|
+
next
|
98
|
+
end
|
99
|
+
|
100
|
+
headers[header_key.split("_").map {|s| s.capitalize}.join("-")] = value
|
101
|
+
end
|
102
|
+
|
103
|
+
headers["Referer"] = referer if headers["Referer"]
|
104
|
+
|
105
|
+
headers
|
106
|
+
end
|
107
|
+
|
108
|
+
def add_request_body(report, request, env)
|
109
|
+
body = parsed_request_body(request, env)
|
110
|
+
|
111
|
+
# this request may not have a body
|
112
|
+
return unless body.is_a?(Hash) && !body.empty?
|
113
|
+
|
114
|
+
report.add_metadata(:request, :body, body)
|
115
|
+
end
|
116
|
+
|
117
|
+
def parsed_request_body(request, env)
|
118
|
+
return request.POST rescue nil if request.form_data?
|
119
|
+
|
120
|
+
content_type = env["CONTENT_TYPE"]
|
121
|
+
|
122
|
+
return nil if content_type.nil?
|
123
|
+
|
124
|
+
if content_type.include?('/json') || content_type.include?('+json')
|
125
|
+
begin
|
126
|
+
body = request.body
|
127
|
+
|
128
|
+
return JSON.parse(body.read)
|
129
|
+
rescue StandardError
|
130
|
+
return nil
|
131
|
+
ensure
|
132
|
+
# the body must be rewound so other things can read it after we do
|
133
|
+
body.rewind
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
nil
|
138
|
+
end
|
139
|
+
|
140
|
+
def add_cookies(report, request)
|
141
|
+
return unless record_cookies?
|
142
|
+
|
143
|
+
cookies = request.cookies rescue nil
|
144
|
+
|
145
|
+
return unless cookies.is_a?(Hash) && !cookies.empty?
|
146
|
+
|
147
|
+
report.add_metadata(:request, :cookies, cookies)
|
148
|
+
end
|
149
|
+
|
150
|
+
def record_cookies?
|
151
|
+
# only record cookies in the request if none of the filters match "Cookie"
|
152
|
+
# the "Cookie" header will be filtered as normal
|
153
|
+
!Bugsnag.cleaner.filters_match?(COOKIE_HEADER)
|
154
|
+
end
|
90
155
|
end
|
91
156
|
end
|
@@ -15,8 +15,8 @@ module Bugsnag::Middleware
|
|
15
15
|
client_ip = env["action_dispatch.remote_ip"].to_s rescue SPOOF
|
16
16
|
|
17
17
|
if params
|
18
|
-
# Set the context
|
19
|
-
report.
|
18
|
+
# Set the automatic context
|
19
|
+
report.automatic_context = "#{params[:controller]}##{params[:action]}"
|
20
20
|
|
21
21
|
# Augment the request tab
|
22
22
|
report.add_tab(:request, {
|
@@ -8,12 +8,14 @@ module Bugsnag::Middleware
|
|
8
8
|
|
9
9
|
def call(report)
|
10
10
|
session = Bugsnag::SessionTracker.get_current_session
|
11
|
-
|
11
|
+
|
12
|
+
if session && !session[:paused?]
|
12
13
|
if report.unhandled
|
13
14
|
session[:events][:unhandled] += 1
|
14
15
|
else
|
15
16
|
session[:events][:handled] += 1
|
16
17
|
end
|
18
|
+
|
17
19
|
report.session = session
|
18
20
|
end
|
19
21
|
|
@@ -10,7 +10,7 @@ module Bugsnag::Middleware
|
|
10
10
|
sidekiq = report.request_data[:sidekiq]
|
11
11
|
if sidekiq
|
12
12
|
report.add_tab(:sidekiq, sidekiq)
|
13
|
-
report.
|
13
|
+
report.automatic_context ||= "#{sidekiq[:msg]['wrapped'] || sidekiq[:msg]['class']}@#{sidekiq[:msg]['queue']}"
|
14
14
|
end
|
15
15
|
@bugsnag.call(report)
|
16
16
|
end
|
data/lib/bugsnag/report.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
require "json"
|
2
2
|
require "pathname"
|
3
|
+
require "bugsnag/error"
|
3
4
|
require "bugsnag/stacktrace"
|
4
5
|
|
5
6
|
module Bugsnag
|
7
|
+
# rubocop:todo Metrics/ClassLength
|
6
8
|
class Report
|
7
9
|
NOTIFIER_NAME = "Ruby Bugsnag Notifier"
|
8
10
|
NOTIFIER_VERSION = Bugsnag::VERSION
|
@@ -45,16 +47,13 @@ module Bugsnag
|
|
45
47
|
# @return [Configuration]
|
46
48
|
attr_accessor :configuration
|
47
49
|
|
48
|
-
# Additional context for this report
|
49
|
-
# @return [String, nil]
|
50
|
-
attr_accessor :context
|
51
|
-
|
52
50
|
# The delivery method that will be used for this report
|
53
51
|
# @see Configuration#delivery_method
|
54
52
|
# @return [Symbol]
|
55
53
|
attr_accessor :delivery_method
|
56
54
|
|
57
55
|
# The list of exceptions in this report
|
56
|
+
# @deprecated Use {#errors} instead
|
58
57
|
# @return [Array<Hash>]
|
59
58
|
attr_accessor :exceptions
|
60
59
|
|
@@ -72,10 +71,12 @@ module Bugsnag
|
|
72
71
|
attr_accessor :grouping_hash
|
73
72
|
|
74
73
|
# Arbitrary metadata attached to this report
|
74
|
+
# @deprecated Use {#metadata} instead
|
75
75
|
# @return [Hash]
|
76
76
|
attr_accessor :meta_data
|
77
77
|
|
78
78
|
# The raw Exception instances for this report
|
79
|
+
# @deprecated Use {#original_error} instead
|
79
80
|
# @see #exceptions
|
80
81
|
# @return [Array<Exception>]
|
81
82
|
attr_accessor :raw_exceptions
|
@@ -102,31 +103,67 @@ module Bugsnag
|
|
102
103
|
# @return [Hash]
|
103
104
|
attr_accessor :user
|
104
105
|
|
106
|
+
# A list of errors in this report
|
107
|
+
# @return [Array<Error>]
|
108
|
+
attr_reader :errors
|
109
|
+
|
110
|
+
# The Exception instance this report was created for
|
111
|
+
# @return [Exception]
|
112
|
+
attr_reader :original_error
|
113
|
+
|
105
114
|
##
|
106
115
|
# Initializes a new report from an exception.
|
107
116
|
def initialize(exception, passed_configuration, auto_notify=false)
|
117
|
+
# store the creation time for use as device.time
|
118
|
+
@created_at = Time.now.utc.iso8601(3)
|
119
|
+
|
108
120
|
@should_ignore = false
|
109
121
|
@unhandled = auto_notify
|
122
|
+
@initial_unhandled = @unhandled
|
110
123
|
|
111
124
|
self.configuration = passed_configuration
|
112
125
|
|
126
|
+
@original_error = exception
|
113
127
|
self.raw_exceptions = generate_raw_exceptions(exception)
|
114
128
|
self.exceptions = generate_exception_list
|
129
|
+
@errors = generate_error_list
|
115
130
|
|
116
131
|
self.api_key = configuration.api_key
|
117
132
|
self.app_type = configuration.app_type
|
118
133
|
self.app_version = configuration.app_version
|
119
134
|
self.breadcrumbs = []
|
135
|
+
self.context = configuration.context if configuration.context_set?
|
120
136
|
self.delivery_method = configuration.delivery_method
|
121
137
|
self.hostname = configuration.hostname
|
122
138
|
self.runtime_versions = configuration.runtime_versions.dup
|
123
|
-
self.meta_data =
|
139
|
+
self.meta_data = Utility::Duplicator.duplicate(configuration.metadata)
|
124
140
|
self.release_stage = configuration.release_stage
|
125
141
|
self.severity = auto_notify ? "error" : "warning"
|
126
142
|
self.severity_reason = auto_notify ? {:type => UNHANDLED_EXCEPTION} : {:type => HANDLED_EXCEPTION}
|
127
143
|
self.user = {}
|
144
|
+
|
145
|
+
@metadata_delegate = Utility::MetadataDelegate.new
|
146
|
+
end
|
147
|
+
|
148
|
+
##
|
149
|
+
# Additional context for this report
|
150
|
+
# @!attribute context
|
151
|
+
# @return [String, nil]
|
152
|
+
def context
|
153
|
+
return @context if defined?(@context)
|
154
|
+
|
155
|
+
@automatic_context
|
128
156
|
end
|
129
157
|
|
158
|
+
attr_writer :context
|
159
|
+
|
160
|
+
##
|
161
|
+
# Context set automatically by Bugsnag uses this attribute, which prevents
|
162
|
+
# it from overwriting the user-supplied context
|
163
|
+
# @api private
|
164
|
+
# @return [String, nil]
|
165
|
+
attr_accessor :automatic_context
|
166
|
+
|
130
167
|
##
|
131
168
|
# Add a new metadata tab to this notification.
|
132
169
|
#
|
@@ -135,6 +172,8 @@ module Bugsnag
|
|
135
172
|
# exists, this will be merged with the existing values. If a Hash is not
|
136
173
|
# given, the value will be placed into the 'custom' tab
|
137
174
|
# @return [void]
|
175
|
+
#
|
176
|
+
# @deprecated Use {#add_metadata} instead
|
138
177
|
def add_tab(name, value)
|
139
178
|
return if name.nil?
|
140
179
|
|
@@ -153,6 +192,8 @@ module Bugsnag
|
|
153
192
|
#
|
154
193
|
# @param name [String]
|
155
194
|
# @return [void]
|
195
|
+
#
|
196
|
+
# @deprecated Use {#clear_metadata} instead
|
156
197
|
def remove_tab(name)
|
157
198
|
return if name.nil?
|
158
199
|
|
@@ -175,7 +216,8 @@ module Bugsnag
|
|
175
216
|
context: context,
|
176
217
|
device: {
|
177
218
|
hostname: hostname,
|
178
|
-
runtimeVersions: runtime_versions
|
219
|
+
runtimeVersions: runtime_versions,
|
220
|
+
time: @created_at
|
179
221
|
},
|
180
222
|
exceptions: exceptions,
|
181
223
|
groupingHash: grouping_hash,
|
@@ -257,8 +299,119 @@ module Bugsnag
|
|
257
299
|
end
|
258
300
|
end
|
259
301
|
|
302
|
+
# A Hash containing arbitrary metadata
|
303
|
+
# @!attribute metadata
|
304
|
+
# @return [Hash]
|
305
|
+
def metadata
|
306
|
+
@meta_data
|
307
|
+
end
|
308
|
+
|
309
|
+
# @param metadata [Hash]
|
310
|
+
# @return [void]
|
311
|
+
def metadata=(metadata)
|
312
|
+
@meta_data = metadata
|
313
|
+
end
|
314
|
+
|
315
|
+
##
|
316
|
+
# Data from the current HTTP request. May be nil if no data has been recorded
|
317
|
+
#
|
318
|
+
# @return [Hash, nil]
|
319
|
+
def request
|
320
|
+
@meta_data[:request]
|
321
|
+
end
|
322
|
+
|
323
|
+
##
|
324
|
+
# Add values to metadata
|
325
|
+
#
|
326
|
+
# @overload add_metadata(section, data)
|
327
|
+
# Merges data into the given section of metadata
|
328
|
+
# @param section [String, Symbol]
|
329
|
+
# @param data [Hash]
|
330
|
+
#
|
331
|
+
# @overload add_metadata(section, key, value)
|
332
|
+
# Sets key to value in the given section of metadata. If the value is nil
|
333
|
+
# the key will be deleted
|
334
|
+
# @param section [String, Symbol]
|
335
|
+
# @param key [String, Symbol]
|
336
|
+
# @param value
|
337
|
+
#
|
338
|
+
# @return [void]
|
339
|
+
def add_metadata(section, key_or_data, *args)
|
340
|
+
@metadata_delegate.add_metadata(@meta_data, section, key_or_data, *args)
|
341
|
+
end
|
342
|
+
|
343
|
+
##
|
344
|
+
# Clear values from metadata
|
345
|
+
#
|
346
|
+
# @overload clear_metadata(section)
|
347
|
+
# Clears the given section of metadata
|
348
|
+
# @param section [String, Symbol]
|
349
|
+
#
|
350
|
+
# @overload clear_metadata(section, key)
|
351
|
+
# Clears the key in the given section of metadata
|
352
|
+
# @param section [String, Symbol]
|
353
|
+
# @param key [String, Symbol]
|
354
|
+
#
|
355
|
+
# @return [void]
|
356
|
+
def clear_metadata(section, *args)
|
357
|
+
@metadata_delegate.clear_metadata(@meta_data, section, *args)
|
358
|
+
end
|
359
|
+
|
360
|
+
##
|
361
|
+
# Set information about the current user
|
362
|
+
#
|
363
|
+
# Additional user fields can be added as metadata in a "user" section
|
364
|
+
#
|
365
|
+
# Setting a field to 'nil' will remove it from the user data
|
366
|
+
#
|
367
|
+
# @param id [String, nil]
|
368
|
+
# @param email [String, nil]
|
369
|
+
# @param name [String, nil]
|
370
|
+
# @return [void]
|
371
|
+
def set_user(id = nil, email = nil, name = nil)
|
372
|
+
new_user = { id: id, email: email, name: name }
|
373
|
+
new_user.reject! { |key, value| value.nil? }
|
374
|
+
|
375
|
+
@user = new_user
|
376
|
+
end
|
377
|
+
|
378
|
+
def unhandled=(new_unhandled)
|
379
|
+
# fix the handled/unhandled counts in the current session
|
380
|
+
update_handled_counts(new_unhandled, @unhandled)
|
381
|
+
|
382
|
+
@unhandled = new_unhandled
|
383
|
+
end
|
384
|
+
|
385
|
+
##
|
386
|
+
# Returns true if the unhandled flag has been changed from its initial value
|
387
|
+
#
|
388
|
+
# @api private
|
389
|
+
# @return [Boolean]
|
390
|
+
def unhandled_overridden?
|
391
|
+
@unhandled != @initial_unhandled
|
392
|
+
end
|
393
|
+
|
260
394
|
private
|
261
395
|
|
396
|
+
def update_handled_counts(is_unhandled, was_unhandled)
|
397
|
+
# do nothing if there is no session to update
|
398
|
+
return if @session.nil?
|
399
|
+
|
400
|
+
# increment the counts for the current unhandled value
|
401
|
+
if is_unhandled
|
402
|
+
@session[:events][:unhandled] += 1
|
403
|
+
else
|
404
|
+
@session[:events][:handled] += 1
|
405
|
+
end
|
406
|
+
|
407
|
+
# decrement the counts for the previous unhandled value
|
408
|
+
if was_unhandled
|
409
|
+
@session[:events][:unhandled] -= 1
|
410
|
+
else
|
411
|
+
@session[:events][:handled] -= 1
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
262
415
|
def generate_exception_list
|
263
416
|
raw_exceptions.map do |exception|
|
264
417
|
{
|
@@ -269,6 +422,12 @@ module Bugsnag
|
|
269
422
|
end
|
270
423
|
end
|
271
424
|
|
425
|
+
def generate_error_list
|
426
|
+
exceptions.map do |exception|
|
427
|
+
Error.new(exception[:errorClass], exception[:message], exception[:stacktrace])
|
428
|
+
end
|
429
|
+
end
|
430
|
+
|
272
431
|
def error_class(exception)
|
273
432
|
# The "Class" check is for some strange exceptions like Timeout::Error
|
274
433
|
# which throw the error class instead of an instance
|
@@ -311,4 +470,5 @@ module Bugsnag
|
|
311
470
|
exceptions
|
312
471
|
end
|
313
472
|
end
|
473
|
+
# rubocop:enable Metrics/ClassLength
|
314
474
|
end
|
@@ -34,16 +34,20 @@ module Bugsnag
|
|
34
34
|
# Starts a new session, storing it on the current thread.
|
35
35
|
#
|
36
36
|
# This allows Bugsnag to track error rates for a release.
|
37
|
+
#
|
38
|
+
# @return [void]
|
37
39
|
def start_session
|
38
|
-
return unless Bugsnag.configuration.enable_sessions
|
40
|
+
return unless Bugsnag.configuration.enable_sessions && Bugsnag.configuration.should_notify_release_stage?
|
41
|
+
|
39
42
|
start_delivery_thread
|
40
43
|
start_time = Time.now().utc().strftime('%Y-%m-%dT%H:%M:00')
|
41
44
|
new_session = {
|
42
|
-
:
|
43
|
-
:
|
44
|
-
|
45
|
-
|
46
|
-
:
|
45
|
+
id: SecureRandom.uuid,
|
46
|
+
startedAt: start_time,
|
47
|
+
paused?: false,
|
48
|
+
events: {
|
49
|
+
handled: 0,
|
50
|
+
unhandled: 0
|
47
51
|
}
|
48
52
|
}
|
49
53
|
SessionTracker.set_current_session(new_session)
|
@@ -52,6 +56,47 @@ module Bugsnag
|
|
52
56
|
|
53
57
|
alias_method :create_session, :start_session
|
54
58
|
|
59
|
+
##
|
60
|
+
# Stop any events being attributed to the current session until it is
|
61
|
+
# resumed or a new session is started
|
62
|
+
#
|
63
|
+
# @see resume_session
|
64
|
+
#
|
65
|
+
# @return [void]
|
66
|
+
def pause_session
|
67
|
+
current_session = SessionTracker.get_current_session
|
68
|
+
|
69
|
+
return unless current_session
|
70
|
+
|
71
|
+
current_session[:paused?] = true
|
72
|
+
end
|
73
|
+
|
74
|
+
##
|
75
|
+
# Resume the current session if it was previously paused. If there is no
|
76
|
+
# current session, a new session will be started
|
77
|
+
#
|
78
|
+
# @see pause_session
|
79
|
+
#
|
80
|
+
# @return [Boolean] true if a paused session was resumed
|
81
|
+
def resume_session
|
82
|
+
current_session = SessionTracker.get_current_session
|
83
|
+
|
84
|
+
if current_session
|
85
|
+
# if the session is paused then resume it, otherwise we don't need to
|
86
|
+
# do anything
|
87
|
+
if current_session[:paused?]
|
88
|
+
current_session[:paused?] = false
|
89
|
+
|
90
|
+
return true
|
91
|
+
end
|
92
|
+
else
|
93
|
+
# if there's no current session, start a new one
|
94
|
+
start_session
|
95
|
+
end
|
96
|
+
|
97
|
+
false
|
98
|
+
end
|
99
|
+
|
55
100
|
##
|
56
101
|
# Delivers the current session_counts lists to the session endpoint.
|
57
102
|
def send_sessions
|
@@ -83,7 +128,7 @@ module Bugsnag
|
|
83
128
|
end
|
84
129
|
end
|
85
130
|
end
|
86
|
-
@delivery_thread = Concurrent::TimerTask.execute(execution_interval:
|
131
|
+
@delivery_thread = Concurrent::TimerTask.execute(execution_interval: 10) do
|
87
132
|
if @session_counts.size > 0
|
88
133
|
send_sessions
|
89
134
|
end
|
@@ -106,11 +151,6 @@ module Bugsnag
|
|
106
151
|
return
|
107
152
|
end
|
108
153
|
|
109
|
-
if !Bugsnag.configuration.should_notify_release_stage?
|
110
|
-
Bugsnag.configuration.debug("Not delivering sessions due to notify_release_stages :#{Bugsnag.configuration.notify_release_stages.inspect}")
|
111
|
-
return
|
112
|
-
end
|
113
|
-
|
114
154
|
body = {
|
115
155
|
:notifier => {
|
116
156
|
:name => Bugsnag::Report::NOTIFIER_NAME,
|
data/lib/bugsnag/stacktrace.rb
CHANGED
@@ -43,7 +43,7 @@ module Bugsnag
|
|
43
43
|
if defined?(configuration.project_root) && configuration.project_root.to_s != ''
|
44
44
|
trace_hash[:inProject] = true if file.start_with?(configuration.project_root.to_s)
|
45
45
|
file.sub!(/#{configuration.project_root}\//, "")
|
46
|
-
trace_hash.delete(:inProject) if
|
46
|
+
trace_hash.delete(:inProject) if vendor_path?(configuration, file)
|
47
47
|
end
|
48
48
|
|
49
49
|
# Strip common gem path prefixes
|
@@ -67,5 +67,14 @@ module Bugsnag
|
|
67
67
|
|
68
68
|
processed_backtrace
|
69
69
|
end
|
70
|
+
|
71
|
+
# @api private
|
72
|
+
def self.vendor_path?(configuration, file_path)
|
73
|
+
return true if configuration.vendor_path && file_path.match(configuration.vendor_path)
|
74
|
+
|
75
|
+
configuration.vendor_paths.any? do |vendor_path|
|
76
|
+
file_path.start_with?("#{vendor_path.sub(/\/$/, '')}/")
|
77
|
+
end
|
78
|
+
end
|
70
79
|
end
|
71
80
|
end
|