bugsnag 4.2.1 → 6.27.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 +5 -5
- data/.yardopts +12 -0
- data/CHANGELOG.md +814 -0
- data/README.md +21 -25
- data/VERSION +1 -1
- data/bugsnag.gemspec +19 -8
- data/lib/bugsnag/breadcrumb_type.rb +14 -0
- data/lib/bugsnag/breadcrumbs/breadcrumb.rb +109 -0
- data/lib/bugsnag/breadcrumbs/breadcrumbs.rb +13 -0
- data/lib/bugsnag/breadcrumbs/on_breadcrumb_callback_list.rb +48 -0
- data/lib/bugsnag/breadcrumbs/validator.rb +29 -0
- data/lib/bugsnag/cleaner.rb +170 -59
- data/lib/bugsnag/code_extractor.rb +137 -0
- data/lib/bugsnag/configuration.rb +670 -45
- data/lib/bugsnag/delivery/synchronous.rb +31 -14
- data/lib/bugsnag/delivery/thread_queue.rb +23 -6
- data/lib/bugsnag/delivery.rb +13 -0
- 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 +5 -0
- data/lib/bugsnag/feature_flag.rb +74 -0
- data/lib/bugsnag/helpers.rb +121 -25
- data/lib/bugsnag/integrations/delayed_job.rb +51 -0
- data/lib/bugsnag/integrations/mailman.rb +43 -0
- data/lib/bugsnag/integrations/mongo.rb +133 -0
- data/lib/bugsnag/integrations/que.rb +53 -0
- data/lib/bugsnag/integrations/rack.rb +83 -0
- data/lib/bugsnag/integrations/rails/active_job.rb +100 -0
- data/lib/bugsnag/{rails → integrations/rails}/active_record_rescue.rb +10 -1
- data/lib/bugsnag/{rails → integrations/rails}/controller_methods.rb +1 -9
- data/lib/bugsnag/integrations/rails/rails_breadcrumbs.rb +115 -0
- data/lib/bugsnag/integrations/railtie.rb +153 -0
- data/lib/bugsnag/integrations/rake.rb +74 -0
- data/lib/bugsnag/integrations/resque.rb +94 -0
- data/lib/bugsnag/integrations/shoryuken.rb +50 -0
- data/lib/bugsnag/integrations/sidekiq.rb +68 -0
- data/lib/bugsnag/meta_data.rb +1 -0
- data/lib/bugsnag/middleware/active_job.rb +18 -0
- data/lib/bugsnag/middleware/breadcrumbs.rb +21 -0
- data/lib/bugsnag/middleware/callbacks.rb +6 -8
- data/lib/bugsnag/middleware/classify_error.rb +50 -0
- data/lib/bugsnag/middleware/clearance_user.rb +33 -0
- data/lib/bugsnag/middleware/delayed_job.rb +93 -0
- data/lib/bugsnag/middleware/discard_error_class.rb +30 -0
- data/lib/bugsnag/middleware/exception_meta_data.rb +42 -0
- data/lib/bugsnag/middleware/ignore_error_class.rb +26 -0
- data/lib/bugsnag/middleware/mailman.rb +6 -4
- data/lib/bugsnag/middleware/rack_request.rb +126 -30
- data/lib/bugsnag/middleware/rails3_request.rb +15 -17
- data/lib/bugsnag/middleware/rake.rb +7 -5
- data/lib/bugsnag/middleware/session_data.rb +25 -0
- data/lib/bugsnag/middleware/sidekiq.rb +9 -4
- data/lib/bugsnag/middleware/suggestion_data.rb +34 -0
- data/lib/bugsnag/middleware/warden_user.rb +11 -6
- data/lib/bugsnag/middleware_stack.rb +62 -9
- data/lib/bugsnag/on_error_callbacks.rb +33 -0
- data/lib/bugsnag/report.rb +516 -0
- data/lib/bugsnag/session_tracker.rb +182 -0
- data/lib/bugsnag/stacktrace.rb +82 -0
- data/lib/bugsnag/tasks/bugsnag.rake +2 -70
- data/lib/bugsnag/utility/circular_buffer.rb +62 -0
- data/lib/bugsnag/utility/duplicator.rb +124 -0
- data/lib/bugsnag/utility/feature_data_store.rb +41 -0
- data/lib/bugsnag/utility/feature_flag_delegate.rb +89 -0
- data/lib/bugsnag/utility/metadata_delegate.rb +102 -0
- data/lib/bugsnag.rb +528 -80
- metadata +61 -123
- data/.document +0 -5
- data/.gitignore +0 -52
- data/.rspec +0 -3
- data/.travis.yml +0 -14
- data/CONTRIBUTING.md +0 -47
- data/Gemfile +0 -2
- data/Rakefile +0 -29
- data/lib/bugsnag/capistrano.rb +0 -7
- data/lib/bugsnag/capistrano2.rb +0 -32
- data/lib/bugsnag/delay/resque.rb +0 -21
- data/lib/bugsnag/delayed_job.rb +0 -57
- data/lib/bugsnag/deploy.rb +0 -34
- data/lib/bugsnag/mailman.rb +0 -28
- data/lib/bugsnag/middleware/rails2_request.rb +0 -52
- data/lib/bugsnag/notification.rb +0 -459
- data/lib/bugsnag/rack.rb +0 -53
- data/lib/bugsnag/rails/action_controller_rescue.rb +0 -62
- data/lib/bugsnag/rails.rb +0 -66
- data/lib/bugsnag/railtie.rb +0 -80
- data/lib/bugsnag/rake.rb +0 -25
- data/lib/bugsnag/resque.rb +0 -40
- data/lib/bugsnag/sidekiq.rb +0 -42
- data/lib/bugsnag/tasks/bugsnag.cap +0 -48
- data/rails/init.rb +0 -7
- data/spec/cleaner_spec.rb +0 -138
- data/spec/code_spec.rb +0 -86
- data/spec/fixtures/crashes/end_of_file.rb +0 -9
- data/spec/fixtures/crashes/short_file.rb +0 -1
- data/spec/fixtures/crashes/start_of_file.rb +0 -9
- data/spec/fixtures/middleware/internal_info_setter.rb +0 -11
- data/spec/fixtures/middleware/public_info_setter.rb +0 -11
- data/spec/fixtures/tasks/Rakefile +0 -15
- data/spec/helper_spec.rb +0 -163
- data/spec/integration_spec.rb +0 -132
- data/spec/middleware_spec.rb +0 -181
- data/spec/notification_spec.rb +0 -877
- data/spec/rack_spec.rb +0 -56
- data/spec/spec_helper.rb +0 -53
data/lib/bugsnag/notification.rb
DELETED
@@ -1,459 +0,0 @@
|
|
1
|
-
require "json"
|
2
|
-
|
3
|
-
if RUBY_VERSION =~ /^1\.8/
|
4
|
-
begin
|
5
|
-
require "iconv"
|
6
|
-
rescue LoadError
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
require "pathname"
|
11
|
-
|
12
|
-
module Bugsnag
|
13
|
-
class Notification
|
14
|
-
NOTIFIER_NAME = "Ruby Bugsnag Notifier"
|
15
|
-
NOTIFIER_VERSION = Bugsnag::VERSION
|
16
|
-
NOTIFIER_URL = "http://www.bugsnag.com"
|
17
|
-
|
18
|
-
API_KEY_REGEX = /[0-9a-f]{32}/i
|
19
|
-
|
20
|
-
# e.g. "org/jruby/RubyKernel.java:1264:in `catch'"
|
21
|
-
BACKTRACE_LINE_REGEX = /^((?:[a-zA-Z]:)?[^:]+):(\d+)(?::in `([^']+)')?$/
|
22
|
-
|
23
|
-
# e.g. "org.jruby.Ruby.runScript(Ruby.java:807)"
|
24
|
-
JAVA_BACKTRACE_REGEX = /^(.*)\((.*)(?::([0-9]+))?\)$/
|
25
|
-
|
26
|
-
MAX_EXCEPTIONS_TO_UNWRAP = 5
|
27
|
-
|
28
|
-
SUPPORTED_SEVERITIES = ["error", "warning", "info"]
|
29
|
-
|
30
|
-
CURRENT_PAYLOAD_VERSION = "2"
|
31
|
-
|
32
|
-
attr_accessor :context
|
33
|
-
attr_reader :user
|
34
|
-
attr_accessor :configuration
|
35
|
-
attr_accessor :meta_data
|
36
|
-
|
37
|
-
class << self
|
38
|
-
def deliver_exception_payload(url, payload, configuration=Bugsnag.configuration, delivery_method=nil)
|
39
|
-
payload_string = ::JSON.dump(Bugsnag::Helpers.trim_if_needed(payload))
|
40
|
-
delivery_method = delivery_method || configuration.delivery_method
|
41
|
-
Bugsnag::Delivery[delivery_method].deliver(url, payload_string, configuration)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def initialize(exception, configuration, overrides = nil, request_data = nil)
|
46
|
-
@configuration = configuration
|
47
|
-
@overrides = Bugsnag::Helpers.flatten_meta_data(overrides) || {}
|
48
|
-
@request_data = request_data
|
49
|
-
@meta_data = {}
|
50
|
-
@user = {}
|
51
|
-
@should_ignore = false
|
52
|
-
@severity = nil
|
53
|
-
@grouping_hash = nil
|
54
|
-
@delivery_method = nil
|
55
|
-
|
56
|
-
self.severity = @overrides[:severity]
|
57
|
-
@overrides.delete :severity
|
58
|
-
|
59
|
-
if @overrides.key? :grouping_hash
|
60
|
-
self.grouping_hash = @overrides[:grouping_hash]
|
61
|
-
@overrides.delete :grouping_hash
|
62
|
-
end
|
63
|
-
|
64
|
-
if @overrides.key? :api_key
|
65
|
-
self.api_key = @overrides[:api_key]
|
66
|
-
@overrides.delete :api_key
|
67
|
-
end
|
68
|
-
|
69
|
-
if @overrides.key? :delivery_method
|
70
|
-
@delivery_method = @overrides[:delivery_method]
|
71
|
-
@overrides.delete :delivery_method
|
72
|
-
end
|
73
|
-
|
74
|
-
# Unwrap exceptions
|
75
|
-
@exceptions = []
|
76
|
-
|
77
|
-
ex = exception
|
78
|
-
while ex != nil && !@exceptions.include?(ex) && @exceptions.length < MAX_EXCEPTIONS_TO_UNWRAP
|
79
|
-
|
80
|
-
unless ex.is_a? Exception
|
81
|
-
if ex.respond_to?(:to_exception)
|
82
|
-
ex = ex.to_exception
|
83
|
-
elsif ex.respond_to?(:exception)
|
84
|
-
ex = ex.exception
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
unless ex.is_a?(Exception) || (defined?(Java::JavaLang::Throwable) && ex.is_a?(Java::JavaLang::Throwable))
|
89
|
-
Bugsnag.warn("Converting non-Exception to RuntimeError: #{ex.inspect}")
|
90
|
-
ex = RuntimeError.new(ex.to_s)
|
91
|
-
ex.set_backtrace caller
|
92
|
-
end
|
93
|
-
|
94
|
-
@exceptions << ex
|
95
|
-
|
96
|
-
if ex.respond_to?(:cause) && ex.cause
|
97
|
-
ex = ex.cause
|
98
|
-
elsif ex.respond_to?(:continued_exception) && ex.continued_exception
|
99
|
-
ex = ex.continued_exception
|
100
|
-
elsif ex.respond_to?(:original_exception) && ex.original_exception
|
101
|
-
ex = ex.original_exception
|
102
|
-
else
|
103
|
-
ex = nil
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
# Add a single value as custom data, to this notification
|
109
|
-
def add_custom_data(name, value)
|
110
|
-
@meta_data[:custom] ||= {}
|
111
|
-
@meta_data[:custom][name.to_sym] = value
|
112
|
-
end
|
113
|
-
|
114
|
-
# Add a new tab to this notification
|
115
|
-
def add_tab(name, value)
|
116
|
-
return if name.nil?
|
117
|
-
|
118
|
-
if value.is_a? Hash
|
119
|
-
@meta_data[name.to_sym] ||= {}
|
120
|
-
@meta_data[name.to_sym].merge! value
|
121
|
-
else
|
122
|
-
self.add_custom_data(name, value)
|
123
|
-
Bugsnag.warn "Adding a tab requires a hash, adding to custom tab instead (name=#{name})"
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
# Remove a tab from this notification
|
128
|
-
def remove_tab(name)
|
129
|
-
return if name.nil?
|
130
|
-
|
131
|
-
@meta_data.delete(name.to_sym)
|
132
|
-
end
|
133
|
-
|
134
|
-
def user_id=(user_id)
|
135
|
-
@user[:id] = user_id
|
136
|
-
end
|
137
|
-
|
138
|
-
def user_id
|
139
|
-
@user[:id]
|
140
|
-
end
|
141
|
-
|
142
|
-
def user=(user = {})
|
143
|
-
return unless user.is_a? Hash
|
144
|
-
@user.merge!(user).delete_if{|k,v| v == nil}
|
145
|
-
end
|
146
|
-
|
147
|
-
def severity=(severity)
|
148
|
-
@severity = severity if SUPPORTED_SEVERITIES.include?(severity)
|
149
|
-
end
|
150
|
-
|
151
|
-
def severity
|
152
|
-
@severity || "warning"
|
153
|
-
end
|
154
|
-
|
155
|
-
def payload_version
|
156
|
-
CURRENT_PAYLOAD_VERSION
|
157
|
-
end
|
158
|
-
|
159
|
-
def grouping_hash=(grouping_hash)
|
160
|
-
@grouping_hash = grouping_hash
|
161
|
-
end
|
162
|
-
|
163
|
-
def grouping_hash
|
164
|
-
@grouping_hash || nil
|
165
|
-
end
|
166
|
-
|
167
|
-
def api_key=(api_key)
|
168
|
-
@api_key = api_key
|
169
|
-
end
|
170
|
-
|
171
|
-
def api_key
|
172
|
-
@api_key ||= @configuration.api_key
|
173
|
-
end
|
174
|
-
|
175
|
-
# Deliver this notification to bugsnag.com Also runs through the middleware as required.
|
176
|
-
def deliver
|
177
|
-
return unless @configuration.should_notify?
|
178
|
-
|
179
|
-
# Check we have at least an api_key
|
180
|
-
if api_key.nil?
|
181
|
-
Bugsnag.warn "No API key configured, couldn't notify"
|
182
|
-
return
|
183
|
-
elsif api_key !~ API_KEY_REGEX
|
184
|
-
Bugsnag.warn "Your API key (#{api_key}) is not valid, couldn't notify"
|
185
|
-
return
|
186
|
-
end
|
187
|
-
|
188
|
-
# Warn if no release_stage is set
|
189
|
-
Bugsnag.warn "You should set your app's release_stage (see https://bugsnag.com/docs/notifiers/ruby#release_stage)." unless @configuration.release_stage
|
190
|
-
|
191
|
-
@configuration.internal_middleware.run(self)
|
192
|
-
|
193
|
-
exceptions.each do |exception|
|
194
|
-
if exception.class.include?(Bugsnag::MetaData)
|
195
|
-
if exception.bugsnag_user_id.is_a?(String)
|
196
|
-
self.user_id = exception.bugsnag_user_id
|
197
|
-
end
|
198
|
-
if exception.bugsnag_context.is_a?(String)
|
199
|
-
self.context = exception.bugsnag_context
|
200
|
-
end
|
201
|
-
end
|
202
|
-
end
|
203
|
-
|
204
|
-
[:user_id, :context, :user, :grouping_hash].each do |symbol|
|
205
|
-
if @overrides[symbol]
|
206
|
-
self.send("#{symbol}=", @overrides[symbol])
|
207
|
-
@overrides.delete symbol
|
208
|
-
end
|
209
|
-
end
|
210
|
-
|
211
|
-
# make meta_data available to public middleware
|
212
|
-
@meta_data = generate_meta_data(@exceptions, @overrides)
|
213
|
-
|
214
|
-
# Run the middleware here (including Bugsnag::Middleware::Callbacks)
|
215
|
-
# at the end of the middleware stack, execute the actual notification delivery
|
216
|
-
@configuration.middleware.run(self) do
|
217
|
-
# This supports self.ignore! for before_notify_callbacks.
|
218
|
-
return if @should_ignore
|
219
|
-
|
220
|
-
# Build the endpoint url
|
221
|
-
endpoint = (@configuration.use_ssl ? "https://" : "http://") + @configuration.endpoint
|
222
|
-
Bugsnag.log("Notifying #{endpoint} of #{@exceptions.last.class}")
|
223
|
-
|
224
|
-
# Deliver the payload
|
225
|
-
self.class.deliver_exception_payload(endpoint, build_exception_payload, @configuration, @delivery_method)
|
226
|
-
end
|
227
|
-
end
|
228
|
-
|
229
|
-
# Build an exception payload
|
230
|
-
def build_exception_payload
|
231
|
-
# Build the payload's exception event
|
232
|
-
payload_event = {
|
233
|
-
:app => {
|
234
|
-
:version => @configuration.app_version,
|
235
|
-
:releaseStage => @configuration.release_stage,
|
236
|
-
:type => @configuration.app_type
|
237
|
-
},
|
238
|
-
:context => self.context,
|
239
|
-
:user => @user,
|
240
|
-
:payloadVersion => payload_version,
|
241
|
-
:exceptions => exception_list,
|
242
|
-
:severity => self.severity,
|
243
|
-
:groupingHash => self.grouping_hash,
|
244
|
-
}
|
245
|
-
|
246
|
-
payload_event[:device] = {:hostname => @configuration.hostname} if @configuration.hostname
|
247
|
-
|
248
|
-
# cleanup character encodings
|
249
|
-
payload_event = Bugsnag::Cleaner.clean_object_encoding(payload_event)
|
250
|
-
|
251
|
-
# filter out sensitive values in (and cleanup encodings) metaData
|
252
|
-
payload_event[:metaData] = Bugsnag::Cleaner.new(@configuration.params_filters).clean_object(@meta_data)
|
253
|
-
payload_event.reject! {|k,v| v.nil? }
|
254
|
-
|
255
|
-
# return the payload hash
|
256
|
-
{
|
257
|
-
:apiKey => api_key,
|
258
|
-
:notifier => {
|
259
|
-
:name => NOTIFIER_NAME,
|
260
|
-
:version => NOTIFIER_VERSION,
|
261
|
-
:url => NOTIFIER_URL
|
262
|
-
},
|
263
|
-
:events => [payload_event]
|
264
|
-
}
|
265
|
-
end
|
266
|
-
|
267
|
-
def ignore?
|
268
|
-
@should_ignore || ignore_exception_class? || ignore_user_agent?
|
269
|
-
end
|
270
|
-
|
271
|
-
def request_data
|
272
|
-
@request_data || Bugsnag.configuration.request_data
|
273
|
-
end
|
274
|
-
|
275
|
-
def exceptions
|
276
|
-
@exceptions
|
277
|
-
end
|
278
|
-
|
279
|
-
def ignore!
|
280
|
-
@should_ignore = true
|
281
|
-
end
|
282
|
-
|
283
|
-
private
|
284
|
-
|
285
|
-
def ignore_exception_class?
|
286
|
-
@exceptions.any? do |ex|
|
287
|
-
ancestor_chain = ex.class.ancestors.select { |ancestor| ancestor.is_a?(Class) }.map { |ancestor| error_class(ancestor) }.to_set
|
288
|
-
|
289
|
-
@configuration.ignore_classes.any? do |to_ignore|
|
290
|
-
to_ignore.is_a?(Proc) ? to_ignore.call(ex) : ancestor_chain.include?(to_ignore)
|
291
|
-
end
|
292
|
-
end
|
293
|
-
end
|
294
|
-
|
295
|
-
def ignore_user_agent?
|
296
|
-
if @configuration.request_data && @configuration.request_data[:rack_env] && (agent = @configuration.request_data[:rack_env]["HTTP_USER_AGENT"])
|
297
|
-
@configuration.ignore_user_agents.any? do |to_ignore|
|
298
|
-
agent =~ to_ignore
|
299
|
-
end
|
300
|
-
end
|
301
|
-
end
|
302
|
-
|
303
|
-
# Generate the meta data from both the request configuration, the overrides and the exceptions for this notification
|
304
|
-
def generate_meta_data(exceptions, overrides)
|
305
|
-
# Copy the request meta data so we dont edit it by mistake
|
306
|
-
meta_data = @meta_data.dup
|
307
|
-
|
308
|
-
exceptions.each do |exception|
|
309
|
-
if exception.respond_to?(:bugsnag_meta_data) && exception.bugsnag_meta_data
|
310
|
-
exception.bugsnag_meta_data.each do |key, value|
|
311
|
-
add_to_meta_data key, value, meta_data
|
312
|
-
end
|
313
|
-
end
|
314
|
-
end
|
315
|
-
|
316
|
-
overrides.each do |key, value|
|
317
|
-
add_to_meta_data key, value, meta_data
|
318
|
-
end
|
319
|
-
|
320
|
-
meta_data
|
321
|
-
end
|
322
|
-
|
323
|
-
def add_to_meta_data(key, value, meta_data)
|
324
|
-
# If its a hash, its a tab so we can just add it providing its not reserved
|
325
|
-
if value.is_a? Hash
|
326
|
-
key = key.to_sym
|
327
|
-
|
328
|
-
if meta_data[key]
|
329
|
-
# If its a clash, merge with the existing data
|
330
|
-
meta_data[key].merge! value
|
331
|
-
else
|
332
|
-
# Add it as is if its not special
|
333
|
-
meta_data[key] = value
|
334
|
-
end
|
335
|
-
else
|
336
|
-
meta_data[:custom] ||= {}
|
337
|
-
meta_data[:custom][key] = value
|
338
|
-
end
|
339
|
-
end
|
340
|
-
|
341
|
-
def exception_list
|
342
|
-
@exceptions.map do |exception|
|
343
|
-
{
|
344
|
-
:errorClass => error_class(exception),
|
345
|
-
:message => exception.message,
|
346
|
-
:stacktrace => stacktrace(exception)
|
347
|
-
}
|
348
|
-
end
|
349
|
-
end
|
350
|
-
|
351
|
-
def error_class(exception)
|
352
|
-
# The "Class" check is for some strange exceptions like Timeout::Error
|
353
|
-
# which throw the error class instead of an instance
|
354
|
-
(exception.is_a? Class) ? exception.name : exception.class.name
|
355
|
-
end
|
356
|
-
|
357
|
-
def stacktrace(exception)
|
358
|
-
(exception.backtrace || caller).map do |trace|
|
359
|
-
|
360
|
-
if trace.match(BACKTRACE_LINE_REGEX)
|
361
|
-
file, line_str, method = [$1, $2, $3]
|
362
|
-
elsif trace.match(JAVA_BACKTRACE_REGEX)
|
363
|
-
method, file, line_str = [$1, $2, $3]
|
364
|
-
end
|
365
|
-
|
366
|
-
# Parse the stacktrace line
|
367
|
-
|
368
|
-
# Skip stacktrace lines inside lib/bugsnag
|
369
|
-
next(nil) if file.nil? || file =~ %r{lib/bugsnag(/|\.rb)}
|
370
|
-
|
371
|
-
# Expand relative paths
|
372
|
-
p = Pathname.new(file)
|
373
|
-
if p.relative?
|
374
|
-
file = p.realpath.to_s rescue file
|
375
|
-
end
|
376
|
-
|
377
|
-
# Generate the stacktrace line hash
|
378
|
-
trace_hash = {}
|
379
|
-
trace_hash[:inProject] = true if in_project?(file)
|
380
|
-
trace_hash[:lineNumber] = line_str.to_i
|
381
|
-
|
382
|
-
if @configuration.send_code
|
383
|
-
trace_hash[:code] = code(file, trace_hash[:lineNumber])
|
384
|
-
end
|
385
|
-
|
386
|
-
# Clean up the file path in the stacktrace
|
387
|
-
if defined?(Bugsnag.configuration.project_root) && Bugsnag.configuration.project_root.to_s != ''
|
388
|
-
file.sub!(/#{Bugsnag.configuration.project_root}\//, "")
|
389
|
-
end
|
390
|
-
|
391
|
-
# Strip common gem path prefixes
|
392
|
-
if defined?(Gem)
|
393
|
-
file = Gem.path.inject(file) {|line, path| line.sub(/#{path}\//, "") }
|
394
|
-
end
|
395
|
-
|
396
|
-
trace_hash[:file] = file
|
397
|
-
|
398
|
-
# Add a method if we have it
|
399
|
-
trace_hash[:method] = method if method && (method =~ /^__bind/).nil?
|
400
|
-
|
401
|
-
if trace_hash[:file] && !trace_hash[:file].empty?
|
402
|
-
trace_hash
|
403
|
-
else
|
404
|
-
nil
|
405
|
-
end
|
406
|
-
end.compact
|
407
|
-
end
|
408
|
-
|
409
|
-
def in_project?(line)
|
410
|
-
return false if @configuration.vendor_paths && @configuration.vendor_paths.any? do |vendor_path|
|
411
|
-
if vendor_path.is_a?(String)
|
412
|
-
line.include?(vendor_path)
|
413
|
-
else
|
414
|
-
line =~ vendor_path
|
415
|
-
end
|
416
|
-
end
|
417
|
-
@configuration.project_root && line.start_with?(@configuration.project_root.to_s)
|
418
|
-
end
|
419
|
-
|
420
|
-
def code(file, line_number, num_lines = 7)
|
421
|
-
code_hash = {}
|
422
|
-
|
423
|
-
from_line = [line_number - num_lines, 1].max
|
424
|
-
|
425
|
-
# don't try and open '(irb)' or '-e'
|
426
|
-
return unless File.exist?(file)
|
427
|
-
|
428
|
-
# Populate code hash with line numbers and code lines
|
429
|
-
File.open(file) do |f|
|
430
|
-
current_line_number = 0
|
431
|
-
f.each_line do |line|
|
432
|
-
current_line_number += 1
|
433
|
-
|
434
|
-
next if current_line_number < from_line
|
435
|
-
|
436
|
-
code_hash[current_line_number] = line[0...200].rstrip
|
437
|
-
|
438
|
-
break if code_hash.length >= ( num_lines * 1.5 ).ceil
|
439
|
-
end
|
440
|
-
end
|
441
|
-
|
442
|
-
while code_hash.length > num_lines
|
443
|
-
last_line = code_hash.keys.max
|
444
|
-
first_line = code_hash.keys.min
|
445
|
-
|
446
|
-
if (last_line - line_number) > (line_number - first_line)
|
447
|
-
code_hash.delete(last_line)
|
448
|
-
else
|
449
|
-
code_hash.delete(first_line)
|
450
|
-
end
|
451
|
-
end
|
452
|
-
|
453
|
-
code_hash
|
454
|
-
rescue
|
455
|
-
Bugsnag.warn("Error fetching code: #{$!.inspect}")
|
456
|
-
nil
|
457
|
-
end
|
458
|
-
end
|
459
|
-
end
|
data/lib/bugsnag/rack.rb
DELETED
@@ -1,53 +0,0 @@
|
|
1
|
-
module Bugsnag
|
2
|
-
class Rack
|
3
|
-
def initialize(app)
|
4
|
-
@app = app
|
5
|
-
|
6
|
-
# Configure bugsnag rack defaults
|
7
|
-
Bugsnag.configure do |config|
|
8
|
-
# Try to set the release_stage automatically if it hasn't already been set
|
9
|
-
config.release_stage ||= ENV["RACK_ENV"] if ENV["RACK_ENV"]
|
10
|
-
|
11
|
-
# Try to set the project_root if it hasn't already been set, or show a warning if we can't
|
12
|
-
unless config.project_root && !config.project_root.to_s.empty?
|
13
|
-
if defined?(settings)
|
14
|
-
config.project_root = settings.root
|
15
|
-
else
|
16
|
-
Bugsnag.warn("You should set your app's project_root (see https://bugsnag.com/docs/notifiers/ruby#project_root).")
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
# Hook up rack-based notification middlewares
|
21
|
-
config.middleware.insert_before([Bugsnag::Middleware::Rails3Request,Bugsnag::Middleware::Callbacks], Bugsnag::Middleware::RackRequest) if defined?(::Rack)
|
22
|
-
config.middleware.insert_before(Bugsnag::Middleware::Callbacks, Bugsnag::Middleware::WardenUser) if defined?(Warden)
|
23
|
-
|
24
|
-
Bugsnag.configuration.app_type ||= "rack"
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def call(env)
|
29
|
-
# Set the request data for bugsnag middleware to use
|
30
|
-
Bugsnag.set_request_data(:rack_env, env)
|
31
|
-
|
32
|
-
begin
|
33
|
-
response = @app.call(env)
|
34
|
-
rescue Exception => raised
|
35
|
-
# Notify bugsnag of rack exceptions
|
36
|
-
Bugsnag.auto_notify(raised)
|
37
|
-
|
38
|
-
# Re-raise the exception
|
39
|
-
raise
|
40
|
-
end
|
41
|
-
|
42
|
-
# Notify bugsnag of rack exceptions
|
43
|
-
if env["rack.exception"]
|
44
|
-
Bugsnag.auto_notify(env["rack.exception"])
|
45
|
-
end
|
46
|
-
|
47
|
-
response
|
48
|
-
ensure
|
49
|
-
# Clear per-request data after processing the each request
|
50
|
-
Bugsnag.clear_request_data
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
@@ -1,62 +0,0 @@
|
|
1
|
-
# Rails 2.x only
|
2
|
-
module Bugsnag::Rails
|
3
|
-
module ActionControllerRescue
|
4
|
-
def self.included(base)
|
5
|
-
base.extend(ClassMethods)
|
6
|
-
|
7
|
-
# Hook into rails exception rescue stack
|
8
|
-
base.send(:alias_method, :rescue_action_in_public_without_bugsnag, :rescue_action_in_public)
|
9
|
-
base.send(:alias_method, :rescue_action_in_public, :rescue_action_in_public_with_bugsnag)
|
10
|
-
|
11
|
-
base.send(:alias_method, :rescue_action_locally_without_bugsnag, :rescue_action_locally)
|
12
|
-
base.send(:alias_method, :rescue_action_locally, :rescue_action_locally_with_bugsnag)
|
13
|
-
|
14
|
-
# Run filters on requests to capture request data
|
15
|
-
base.send(:prepend_before_filter, :set_bugsnag_request_data)
|
16
|
-
end
|
17
|
-
|
18
|
-
private
|
19
|
-
def set_bugsnag_request_data
|
20
|
-
Bugsnag.clear_request_data
|
21
|
-
Bugsnag.set_request_data(:rails2_request, request)
|
22
|
-
end
|
23
|
-
|
24
|
-
def rescue_action_in_public_with_bugsnag(exception)
|
25
|
-
Bugsnag.auto_notify(exception)
|
26
|
-
|
27
|
-
rescue_action_in_public_without_bugsnag(exception)
|
28
|
-
end
|
29
|
-
|
30
|
-
def rescue_action_locally_with_bugsnag(exception)
|
31
|
-
Bugsnag.auto_notify(exception)
|
32
|
-
|
33
|
-
rescue_action_locally_without_bugsnag(exception)
|
34
|
-
end
|
35
|
-
|
36
|
-
module ClassMethods
|
37
|
-
|
38
|
-
def self.extended(base)
|
39
|
-
base.singleton_class.class_eval do
|
40
|
-
alias_method_chain :filter_parameter_logging, :bugsnag
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
# Rails 2 does parameter filtering via a controller configuration method
|
45
|
-
# that dynamically defines a method on the controller, so the configured
|
46
|
-
# parameters aren't easily accessible. Intercept these parameters as
|
47
|
-
# they're configured so that the Bugsnag configuration can take them
|
48
|
-
# into account.
|
49
|
-
#
|
50
|
-
def filter_parameter_logging_with_bugsnag(*filter_words, &block)
|
51
|
-
if filter_words.length > 0
|
52
|
-
Bugsnag.configure do |config|
|
53
|
-
# Use the same regular expression that Rails parameter filtering uses.
|
54
|
-
config.params_filters << Regexp.new(filter_words.collect{ |s| s.to_s }.join('|'), true)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
filter_parameter_logging_without_bugsnag(*filter_words, &block)
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
end
|
62
|
-
end
|
data/lib/bugsnag/rails.rb
DELETED
@@ -1,66 +0,0 @@
|
|
1
|
-
# Rails 2.x hooks
|
2
|
-
# For Rails 3+ hooks, see railtie.rb
|
3
|
-
|
4
|
-
require "bugsnag"
|
5
|
-
require "bugsnag/rails/controller_methods"
|
6
|
-
require "bugsnag/rails/action_controller_rescue"
|
7
|
-
require "bugsnag/rails/active_record_rescue"
|
8
|
-
require "bugsnag/middleware/rails2_request"
|
9
|
-
require "bugsnag/middleware/callbacks"
|
10
|
-
|
11
|
-
module Bugsnag
|
12
|
-
module Rails
|
13
|
-
def self.initialize
|
14
|
-
if defined?(ActionController::Base)
|
15
|
-
ActionController::Base.send(:include, Bugsnag::Rails::ActionControllerRescue)
|
16
|
-
ActionController::Base.send(:include, Bugsnag::Rails::ControllerMethods)
|
17
|
-
end
|
18
|
-
if defined?(ActiveRecord::Base) && Gem::Version.new(ActiveRecord::VERSION::STRING) < Gem::Version.new("4.3")
|
19
|
-
unless ActiveRecord::Base.respond_to?(:raise_in_transactional_callbacks) && ActiveRecord::Base.raise_in_transactional_callbacks
|
20
|
-
ActiveRecord::Base.send(:include, Bugsnag::Rails::ActiveRecordRescue)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
Bugsnag.configure do |config|
|
25
|
-
config.logger ||= rails_logger
|
26
|
-
config.release_stage = rails_env if rails_env
|
27
|
-
config.project_root = rails_root if rails_root
|
28
|
-
|
29
|
-
config.middleware.insert_before(Bugsnag::Middleware::Callbacks,Bugsnag::Middleware::Rails2Request)
|
30
|
-
end
|
31
|
-
|
32
|
-
# Auto-load configuration settings from config/bugsnag.yml if it exists
|
33
|
-
config_file = File.join(rails_root, "config", "bugsnag.yml")
|
34
|
-
config = YAML.load_file(config_file) if File.exists?(config_file)
|
35
|
-
Bugsnag.configure(config[rails_env] ? config[rails_env] : config) if config
|
36
|
-
|
37
|
-
Bugsnag.configuration.app_type = "rails"
|
38
|
-
end
|
39
|
-
|
40
|
-
def self.rails_logger
|
41
|
-
if defined?(::Rails.logger)
|
42
|
-
rails_logger = ::Rails.logger
|
43
|
-
elsif defined?(RAILS_DEFAULT_LOGGER)
|
44
|
-
rails_logger = RAILS_DEFAULT_LOGGER
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def self.rails_env
|
49
|
-
if defined?(::Rails.env)
|
50
|
-
::Rails.env
|
51
|
-
elsif defined?(RAILS_ENV)
|
52
|
-
RAILS_ENV
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
def self.rails_root
|
57
|
-
if defined?(::Rails.root)
|
58
|
-
::Rails.root
|
59
|
-
elsif defined?(RAILS_ROOT)
|
60
|
-
RAILS_ROOT
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
Bugsnag::Rails.initialize
|