bugsnag 2.8.1 → 2.8.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cdbdd74cc3bf6c45f80a0828c67de91915375114
4
- data.tar.gz: fe23fc1d6931f33c1f120042168fd3f59d41bc24
3
+ metadata.gz: 43df7800cf5b29766a8eb2ee1574eea6549f9e0a
4
+ data.tar.gz: 6c9478cd0c3dcf185b30e6266fbbe7bffc1ab26d
5
5
  SHA512:
6
- metadata.gz: b54f5a14ae6d88f0ad19084d6d6e84f0ebaf6463ab503d603394ac69f9eb152a36a8b71bbd75de2ff773a38c29f1e2b845adf600952b776a2668218c801f3e35
7
- data.tar.gz: 309b32904d8372069fd02a446689c0fe1212a9f6e1f8db0ae4e8b9a9728783e8ffcd2bf55e60cded72acaffe59965209a18c7e752603353deef37a9928b7e171
6
+ metadata.gz: e961861ba8a71814253994d8c011166fa2b95c3c086ab795aa6ee4a0086f6affb09655426256684ccd0010033f3df1f32ef38353e49cfd693ef4b86c66e04849
7
+ data.tar.gz: ca3916340b2c8d937481204bf36f1f6b523d0ebaf30ab48e1440107ba36d83dbbe9c35670bb1341bd95dce1f656cd2451fd7a05ff4f7eaa434d9ce074ddddd7a
@@ -1,6 +1,10 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
+ 2.8.2
5
+ -----
6
+ - Fix various threading issues during library initialization
7
+
4
8
  2.8.1
5
9
  -----
6
10
  - Exclude cookies and authorization headers by default
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.8.1
1
+ 2.8.2
@@ -1,4 +1,5 @@
1
1
  require "rubygems"
2
+ require "thread"
2
3
 
3
4
  require "bugsnag/version"
4
5
  require "bugsnag/configuration"
@@ -25,6 +26,7 @@ require "bugsnag/middleware/callbacks"
25
26
 
26
27
  module Bugsnag
27
28
  LOG_PREFIX = "** [Bugsnag] "
29
+ LOCK = Mutex.new
28
30
 
29
31
  class << self
30
32
  # Configure the Bugsnag notifier application-wide settings.
@@ -92,7 +94,7 @@ module Bugsnag
92
94
 
93
95
  # Configuration getters
94
96
  def configuration
95
- @configuration ||= Bugsnag::Configuration.new
97
+ @configuration || LOCK.synchronize { @configuration ||= Bugsnag::Configuration.new }
96
98
  end
97
99
 
98
100
  # Set "per-request" data, temporal data for use in bugsnag middleware
@@ -6,6 +6,7 @@ module Bugsnag
6
6
  MAX_OUTSTANDING_REQUESTS = 100
7
7
  STOP = Object.new
8
8
 
9
+
9
10
  class << self
10
11
  def deliver(url, body, configuration)
11
12
  if queue.length > MAX_OUTSTANDING_REQUESTS
@@ -15,35 +16,32 @@ module Bugsnag
15
16
 
16
17
  # Add delivery to the worker thread
17
18
  queue.push proc { super(url, body, configuration) }
18
-
19
- # Make sure the worker thread is started
20
- ensure_worker_thread_started
21
19
  end
22
20
 
23
21
  private
24
- def queue
25
- @queue ||= Queue.new
26
- end
27
22
 
28
- def ensure_worker_thread_started
29
- unless @worker_thread
30
- @worker_thread = Thread.new do
31
- while x = queue.pop
32
- break if x == STOP
33
- x.call
34
- end
35
- end
23
+ attr_reader :queue
36
24
 
37
- at_exit do
38
- Bugsnag.warn("Waiting for #{queue.length} outstanding request(s)") unless queue.empty?
39
- queue.push STOP
40
- @worker_thread.join
25
+ def start!
26
+ @queue = Queue.new
27
+
28
+ worker_thread = Thread.new do
29
+ while x = queue.pop
30
+ break if x == STOP
31
+ x.call
41
32
  end
42
33
  end
43
34
 
44
- @worker_thread
35
+ at_exit do
36
+ Bugsnag.warn("Waiting for #{queue.length} outstanding request(s)") unless queue.empty?
37
+ queue.push STOP
38
+ worker_thread.join
39
+ end
45
40
  end
46
41
  end
42
+
43
+ # do this once at require time to avoid race conditions
44
+ start!
47
45
  end
48
46
  end
49
47
  end
@@ -41,7 +41,7 @@ module Bugsnag
41
41
  if str =~ /#<.*>/
42
42
  '[OBJECT]'
43
43
  else
44
- str
44
+ cleanup_string(str)
45
45
  end
46
46
  end
47
47
  end
@@ -3,46 +3,58 @@ module Bugsnag
3
3
  def initialize
4
4
  @middlewares = []
5
5
  @disabled_middleware = []
6
+ @mutex = Mutex.new
6
7
  end
7
8
 
8
9
  def use(new_middleware)
9
- return if @disabled_middleware.include?(new_middleware)
10
+ @mutex.synchronize do
11
+ return if @disabled_middleware.include?(new_middleware)
12
+ return if @middlewares.include?(new_middleware)
10
13
 
11
- @middlewares << new_middleware
14
+ @middlewares << new_middleware
15
+ end
12
16
  end
13
17
 
14
18
  def insert_after(after, new_middleware)
15
- return if @disabled_middleware.include?(new_middleware)
16
-
17
- if after.is_a? Array
18
- index = @middlewares.rindex {|el| after.include?(el)}
19
- else
20
- index = @middlewares.rindex(after)
21
- end
22
-
23
- if index.nil?
24
- @middlewares << new_middleware
25
- else
26
- @middlewares.insert index + 1, new_middleware
19
+ @mutex.synchronize do
20
+ return if @disabled_middleware.include?(new_middleware)
21
+ return if @middlewares.include?(new_middleware)
22
+
23
+ if after.is_a? Array
24
+ index = @middlewares.rindex {|el| after.include?(el)}
25
+ else
26
+ index = @middlewares.rindex(after)
27
+ end
28
+
29
+ if index.nil?
30
+ @middlewares << new_middleware
31
+ else
32
+ @middlewares.insert index + 1, new_middleware
33
+ end
27
34
  end
28
35
  end
29
36
 
30
37
  def insert_before(before, new_middleware)
31
- return if @disabled_middleware.include?(new_middleware)
38
+ @mutex.synchronize do
39
+ return if @disabled_middleware.include?(new_middleware)
40
+ return if @middlewares.include?(new_middleware)
32
41
 
33
- if before.is_a? Array
34
- index = @middlewares.index {|el| before.include?(el)}
35
- else
36
- index = @middlewares.index(before)
37
- end
42
+ if before.is_a? Array
43
+ index = @middlewares.index {|el| before.include?(el)}
44
+ else
45
+ index = @middlewares.index(before)
46
+ end
38
47
 
39
- @middlewares.insert index || @middlewares.length, new_middleware
48
+ @middlewares.insert index || @middlewares.length, new_middleware
49
+ end
40
50
  end
41
51
 
42
52
  def disable(*middlewares)
43
- @disabled_middleware += middlewares
53
+ @mutex.synchronize do
54
+ @disabled_middleware += middlewares
44
55
 
45
- @middlewares.delete_if {|m| @disabled_middleware.include?(m)}
56
+ @middlewares.delete_if {|m| @disabled_middleware.include?(m)}
57
+ end
46
58
  end
47
59
 
48
60
  # This allows people to proxy methods to the array if they want to do more complex stuff
@@ -56,7 +68,7 @@ module Bugsnag
56
68
  lambda_has_run = false
57
69
  notify_lambda = lambda do |notif|
58
70
  lambda_has_run = true
59
- yield
71
+ yield if block_given?
60
72
  end
61
73
 
62
74
  begin
@@ -191,7 +191,7 @@ module Bugsnag
191
191
  # Warn if no release_stage is set
192
192
  Bugsnag.warn "You should set your app's release_stage (see https://bugsnag.com/docs/notifiers/ruby#release_stage)." unless @configuration.release_stage
193
193
 
194
- @configuration.internal_middleware.run(self) { }
194
+ @configuration.internal_middleware.run(self)
195
195
 
196
196
  exceptions.each do |exception|
197
197
  if exception.class.include?(Bugsnag::MetaData)
@@ -224,46 +224,49 @@ module Bugsnag
224
224
  endpoint = (@configuration.use_ssl ? "https://" : "http://") + @configuration.endpoint
225
225
  Bugsnag.log("Notifying #{endpoint} of #{@exceptions.last.class} from api_key #{api_key}")
226
226
 
227
- # Build the payload's exception event
228
- payload_event = {
229
- :app => {
230
- :version => @configuration.app_version,
231
- :releaseStage => @configuration.release_stage,
232
- :type => @configuration.app_type
233
- },
234
- :context => self.context,
235
- :user => @user,
236
- :payloadVersion => payload_version,
237
- :exceptions => exception_list,
238
- :severity => self.severity,
239
- :groupingHash => self.grouping_hash,
240
- }
241
-
242
- payload_event[:device] = {:hostname => @configuration.hostname} if @configuration.hostname
243
-
244
- # cleanup character encodings
245
- payload_event = Bugsnag::Helpers.cleanup_obj_encoding(payload_event)
246
-
247
- # filter out sensitive values in (and cleanup encodings) metaData
248
- payload_event[:metaData] = Bugsnag::Helpers.cleanup_obj(@meta_data, @configuration.params_filters)
249
- payload_event.reject! {|k,v| v.nil? }
250
-
251
- # Build the payload hash
252
- payload = {
253
- :apiKey => api_key,
254
- :notifier => {
255
- :name => NOTIFIER_NAME,
256
- :version => NOTIFIER_VERSION,
257
- :url => NOTIFIER_URL
258
- },
259
- :events => [payload_event]
260
- }
261
-
262
227
  # Deliver the payload
263
- self.class.deliver_exception_payload(endpoint, payload, @configuration, @delivery_method)
228
+ self.class.deliver_exception_payload(endpoint, build_exception_payload, @configuration, @delivery_method)
264
229
  end
265
230
  end
266
231
 
232
+ # Build an exception payload
233
+ def build_exception_payload
234
+ # Build the payload's exception event
235
+ payload_event = {
236
+ :app => {
237
+ :version => @configuration.app_version,
238
+ :releaseStage => @configuration.release_stage,
239
+ :type => @configuration.app_type
240
+ },
241
+ :context => self.context,
242
+ :user => @user,
243
+ :payloadVersion => payload_version,
244
+ :exceptions => exception_list,
245
+ :severity => self.severity,
246
+ :groupingHash => self.grouping_hash,
247
+ }
248
+
249
+ payload_event[:device] = {:hostname => @configuration.hostname} if @configuration.hostname
250
+
251
+ # cleanup character encodings
252
+ payload_event = Bugsnag::Helpers.cleanup_obj_encoding(payload_event)
253
+
254
+ # filter out sensitive values in (and cleanup encodings) metaData
255
+ payload_event[:metaData] = Bugsnag::Helpers.cleanup_obj(@meta_data, @configuration.params_filters)
256
+ payload_event.reject! {|k,v| v.nil? }
257
+
258
+ # return the payload hash
259
+ {
260
+ :apiKey => api_key,
261
+ :notifier => {
262
+ :name => NOTIFIER_NAME,
263
+ :version => NOTIFIER_VERSION,
264
+ :url => NOTIFIER_URL
265
+ },
266
+ :events => [payload_event]
267
+ }
268
+ end
269
+
267
270
  def ignore?
268
271
  @should_ignore || ignore_exception_class? || ignore_user_agent?
269
272
  end
@@ -411,6 +414,9 @@ module Bugsnag
411
414
 
412
415
  from_line = [line_number - num_lines, 1].max
413
416
 
417
+ # don't try and open '(irb)' or '-e'
418
+ return unless File.exist?(file)
419
+
414
420
  # Populate code hash with line numbers and code lines
415
421
  File.open(file) do |f|
416
422
  current_line_number = 0
@@ -44,6 +44,17 @@ describe Bugsnag::Helpers do
44
44
  end
45
45
  end
46
46
 
47
+ it "cleans up strings returned from #to_s properly" do
48
+ if RUBY_VERSION > "1.9"
49
+ str = "Andr\xc7\xff"
50
+ if str.respond_to? :force_encoding
51
+ str = str.force_encoding('BINARY')
52
+ end
53
+ obj = RuntimeError.new(str)
54
+ expect(Bugsnag::Helpers.cleanup_obj(obj)).to eq("Andr��")
55
+ end
56
+ end
57
+
47
58
  it "filters by string inclusion" do
48
59
  expect(Bugsnag::Helpers.cleanup_obj({ :foo => 'bar' }, ['f'])).to eq({ :foo => '[FILTERED]' })
49
60
  expect(Bugsnag::Helpers.cleanup_obj({ :foo => 'bar' }, ['b'])).to eq({ :foo => 'bar' })
@@ -55,6 +55,19 @@ describe 'Bugsnag' do
55
55
  expect(request['appVersion']).to eq('1.1.1')
56
56
  end
57
57
 
58
+ it 'should work with threadpool delivery' do
59
+ Bugsnag.configure do |config|
60
+ config.endpoint = "localhost:#{server.config[:Port]}"
61
+ config.use_ssl = false
62
+ config.delivery_method = :thread_queue
63
+ end
64
+ WebMock.allow_net_connect!
65
+
66
+ Bugsnag.notify 'yo'
67
+
68
+ expect(request['events'][0]['exceptions'][0]['message']).to eq('yo')
69
+ end
70
+
58
71
  describe 'with a proxy' do
59
72
  proxy = nil
60
73
  pqueue = Queue.new
@@ -42,4 +42,15 @@ describe Bugsnag::Rack do
42
42
  expect(Bugsnag::Notification).not_to have_sent_notification
43
43
  end
44
44
  end
45
+
46
+ it "don't mess with middlewares list on each req" do
47
+ stub_const('Rack', nil)
48
+ app = lambda { |env| ['200', {}, ['']] }
49
+
50
+ Bugsnag::Rack.new(app)
51
+
52
+ expect { 2.times { Bugsnag::Rack.new(app) } }.not_to change {
53
+ Bugsnag.configuration.middleware.instance_variable_get(:@middlewares)
54
+ }
55
+ end
45
56
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bugsnag
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.8.1
4
+ version: 2.8.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Smith
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-24 00:00:00.000000000 Z
11
+ date: 2015-03-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: multi_json