bugsnag 2.8.1 → 2.8.2

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 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