bugsnag 2.7.1 → 2.8.0

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: 9d58304a346068abb5398be6aca9ab17cb57bca6
4
- data.tar.gz: c74ff028120853a2ee7f1d74993ad1a76be33d00
3
+ metadata.gz: b932122137e824fb015eec162c338d8936587af2
4
+ data.tar.gz: e9f4337e6858a184a8ab78e70f902971d4dcc318
5
5
  SHA512:
6
- metadata.gz: df1bb6f9345dd8809721bfd3f214340c30247e8988d20e45889142639c3bee75629dd787bb6bb26b9a10dfd90a127d5dd5e544f91e7c27b036d0879749320e29
7
- data.tar.gz: 3ba9a85d663736f53205872adf576f1a5dda7436e23cddb5f5c4da01d32ea342cd699f3fedc7b6029c5100d7892c9f87617f87252592964ba4d4896eff15402f
6
+ metadata.gz: 5438db3a7db9953df848433a36fd1da52e9e951cee37d8df226a87cd6b661c7bc843a2028c1280d2a2865d238e2a5b74e02af091c2cf725785eee1bba71f88c3
7
+ data.tar.gz: 95bb639e1d57e5f3b5b7aa61ba30c23047419b433f0a47b22af807865169cba7892a9887706314b364af87a1cc6c9ef4146dd5b6beb19bb9dc3c6dcda7a06c0d
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  Changelog
2
2
  =========
3
+ 2.8.0
4
+ -----
5
+ - Make meta_data available to before_notify hooks
6
+ - Fix bug with rails param filters
7
+ - Fix encoding error in exception message
3
8
 
4
9
  2.7.1
5
10
  -----
data/README.md CHANGED
@@ -83,7 +83,11 @@ exceptions, to help debug problems.
83
83
 
84
84
  ### Rails Apps
85
85
 
86
- In any rails controller you can define a `before_bugsnag_notify` callback, which allows you to add this additional data by calling `add_tab` on the exception notification object. Please see the [Notification Object](#notification-object) for details on the notification parameter.
86
+ By default Bugsnag includes some information automatically. For example, we
87
+ send all the HTTP headers for requests. Additionally if you're using Warden or
88
+ Devise, the id, name and email of the current user are sent.
89
+
90
+ To send additional information, in any rails controller you can define a `before_bugsnag_notify` callback, which allows you to add this additional data by calling `add_tab` on the exception notification object. Please see the [Notification Object](#notification-object) for details on the notification parameter.
87
91
 
88
92
  ```ruby
89
93
  class MyController < ApplicationController
@@ -639,10 +643,17 @@ introduced in.
639
643
  ### Using Heroku
640
644
 
641
645
  You can easily add Bugsnag deploy tracking to your Heroku application by
642
- running the following command:
646
+ running the following command from your application's directory:
647
+
648
+ ```shell
649
+ $ bundle exec rake bugsnag:heroku:add_deploy_hook
650
+ ```
651
+
652
+ If you have multiple Heroku apps, you can specify which app to add the hook
653
+ for as with the `HEROKU_APP` environment variable:
643
654
 
644
655
  ```shell
645
- $ rake bugsnag:heroku:add_deploy_hook
656
+ $ bundle exec rake bugsnag:heroku:add_deploy_hook HEROKU_APP=my-app
646
657
  ```
647
658
 
648
659
  ### Using Capistrano
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.7.1
1
+ 2.8.0
data/lib/bugsnag.rb CHANGED
@@ -14,12 +14,14 @@ require "bugsnag/delivery/thread_queue"
14
14
  require "bugsnag/rack"
15
15
  require "bugsnag/railtie" if defined?(Rails::Railtie)
16
16
 
17
- [:resque, :sidekiq, :mailman, :delayed_job].each do |integration|
18
- begin
19
- require "bugsnag/#{integration}"
20
- rescue LoadError
21
- end
22
- end
17
+ require "bugsnag/middleware/rack_request"
18
+ require "bugsnag/middleware/warden_user"
19
+ require "bugsnag/middleware/callbacks"
20
+ require "bugsnag/middleware/rails3_request"
21
+ require "bugsnag/middleware/sidekiq"
22
+ require "bugsnag/middleware/mailman"
23
+ require "bugsnag/middleware/rake"
24
+ require "bugsnag/middleware/callbacks"
23
25
 
24
26
  module Bugsnag
25
27
  LOG_PREFIX = "** [Bugsnag] "
@@ -47,7 +49,9 @@ module Bugsnag
47
49
 
48
50
  # Explicitly notify of an exception
49
51
  def notify(exception, overrides=nil, request_data=nil)
50
- Notification.new(exception, configuration, overrides, request_data).deliver
52
+ notification = Notification.new(exception, configuration, overrides, request_data)
53
+ notification.deliver
54
+ notification
51
55
  end
52
56
 
53
57
  # Notify of an exception unless it should be ignored
@@ -114,3 +118,10 @@ module Bugsnag
114
118
  end
115
119
  end
116
120
  end
121
+
122
+ [:resque, :sidekiq, :mailman, :delayed_job].each do |integration|
123
+ begin
124
+ require "bugsnag/#{integration}"
125
+ rescue LoadError
126
+ end
127
+ end
@@ -20,6 +20,7 @@ module Bugsnag
20
20
  attr_accessor :endpoint
21
21
  attr_accessor :logger
22
22
  attr_accessor :middleware
23
+ attr_accessor :internal_middleware
23
24
  attr_accessor :delay_with_resque
24
25
  attr_accessor :debug
25
26
  attr_accessor :proxy_host
@@ -75,6 +76,8 @@ module Bugsnag
75
76
  self.logger.level = Logger::WARN
76
77
 
77
78
  # Configure the bugsnag middleware stack
79
+ self.internal_middleware = Bugsnag::MiddlewareStack.new
80
+
78
81
  self.middleware = Bugsnag::MiddlewareStack.new
79
82
  self.middleware.use Bugsnag::Middleware::Callbacks
80
83
  end
@@ -1,3 +1,5 @@
1
+ require 'uri'
2
+
1
3
  module Bugsnag
2
4
  module Helpers
3
5
  MAX_STRING_LENGTH = 4096
@@ -29,20 +31,10 @@ module Bugsnag
29
31
  clean_hash
30
32
  when Array, Set
31
33
  obj.map { |el| cleanup_obj(el, filters, seen) }.compact
32
- when Numeric
34
+ when Numeric, TrueClass, FalseClass
33
35
  obj
34
36
  when String
35
- if defined?(obj.encoding) && defined?(Encoding::UTF_8)
36
- if obj.encoding == Encoding::UTF_8
37
- obj.valid_encoding? ? obj : obj.encode('utf-16', {:invalid => :replace, :undef => :replace}).encode('utf-8')
38
- else
39
- obj.encode('utf-8', {:invalid => :replace, :undef => :replace})
40
- end
41
- elsif defined?(Iconv)
42
- Iconv.conv('UTF-8//IGNORE', 'UTF-8', obj) || obj
43
- else
44
- obj
45
- end
37
+ cleanup_string(obj)
46
38
  else
47
39
  str = obj.to_s
48
40
  # avoid leaking potentially sensitive data from objects' #inspect output
@@ -54,6 +46,24 @@ module Bugsnag
54
46
  end
55
47
  end
56
48
 
49
+ def self.cleanup_string(str)
50
+ if defined?(str.encoding) && defined?(Encoding::UTF_8)
51
+ if str.encoding == Encoding::UTF_8
52
+ str.valid_encoding? ? str : str.encode('utf-16', {:invalid => :replace, :undef => :replace}).encode('utf-8')
53
+ else
54
+ str.encode('utf-8', {:invalid => :replace, :undef => :replace})
55
+ end
56
+ elsif defined?(Iconv)
57
+ Iconv.conv('UTF-8//IGNORE', 'UTF-8', str) || str
58
+ else
59
+ str
60
+ end
61
+ end
62
+
63
+ def self.cleanup_obj_encoding(obj)
64
+ cleanup_obj(obj, nil)
65
+ end
66
+
57
67
  def self.filters_match?(object, filters)
58
68
  str = object.to_s
59
69
 
@@ -67,12 +77,23 @@ module Bugsnag
67
77
  end
68
78
  end
69
79
 
70
- def self.cleanup_url(url, filters = nil)
71
- return url unless filters
80
+ def self.cleanup_url(url, filters = [])
81
+ return url if filters.empty?
72
82
 
73
- filter_regex = Regexp.new("([?&](?:[^&=]*#{filters.to_a.join('|[^&=]*')}[^&=]*)=)[^&]*")
83
+ uri = URI(url)
84
+ return url unless uri.query
85
+
86
+ query_params = uri.query.split('&').map { |pair| pair.split('=') }
87
+ query_params.map! do |key, val|
88
+ if filters_match?(key, filters)
89
+ "#{key}=[FILTERED]"
90
+ else
91
+ "#{key}=#{val}"
92
+ end
93
+ end
74
94
 
75
- url.gsub(filter_regex, '\1[FILTERED]')
95
+ uri.query = query_params.join('&')
96
+ uri.to_s
76
97
  end
77
98
 
78
99
  def self.reduce_hash_size(hash)
@@ -4,9 +4,8 @@ module Bugsnag
4
4
  class Mailman
5
5
  def call(mail)
6
6
  begin
7
- Bugsnag.before_notify_callbacks << lambda {|notif|
8
- notif.add_tab(:mailman, {"message" => mail.to_s})
9
- }
7
+
8
+ Bugsnag.set_request_data :mailman_msg, mail.to_s
10
9
 
11
10
  yield
12
11
  rescue Exception => ex
@@ -20,6 +19,9 @@ module Bugsnag
20
19
  end
21
20
  end
22
21
 
22
+
23
23
  if Mailman.config.respond_to?(:middleware)
24
24
  Mailman.config.middleware.add ::Bugsnag::Mailman
25
25
  end
26
+
27
+ Bugsnag.configuration.internal_middleware.use(Bugsnag::Middleware::Mailman)
@@ -0,0 +1,13 @@
1
+ module Bugsnag::Middleware
2
+ class Mailman
3
+ def initialize(bugsnag)
4
+ @bugsnag = bugsnag
5
+ end
6
+
7
+ def call(notification)
8
+ mailman_msg = notification.request_data[:mailman_msg]
9
+ notification.add_tab(:mailman, {"message" => mailman_msg}) if mailman_msg
10
+ @bugsnag.call(notification)
11
+ end
12
+ end
13
+ end
@@ -15,6 +15,7 @@ module Bugsnag::Middleware
15
15
 
16
16
  # Augment the request tab
17
17
  notification.add_tab(:request, {
18
+ :requestId => env["action_dispatch.request_id"],
18
19
  :railsAction => "#{params[:controller]}##{params[:action]}",
19
20
  :params => params
20
21
  })
@@ -0,0 +1,23 @@
1
+ module Bugsnag::Middleware
2
+ class Rake
3
+ def initialize(bugsnag)
4
+ @bugsnag = bugsnag
5
+ end
6
+
7
+ def call(notification)
8
+ task = notification.request_data[:bugsnag_running_task]
9
+
10
+ if task
11
+ notification.add_tab(:rake_task, {
12
+ :name => task.name,
13
+ :description => task.full_comment,
14
+ :arguments => task.arg_description
15
+ })
16
+
17
+ notification.context ||= task.name
18
+ end
19
+
20
+ @bugsnag.call(notification)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,13 @@
1
+ module Bugsnag::Middleware
2
+ class Sidekiq
3
+ def initialize(bugsnag)
4
+ @bugsnag = bugsnag
5
+ end
6
+
7
+ def call(notification)
8
+ sidekiq = notification.request_data[:sidekiq]
9
+ notification.add_tab(:sidekiq, sidekiq) if sidekiq
10
+ @bugsnag.call(notification)
11
+ end
12
+ end
13
+ end
@@ -1,4 +1,12 @@
1
1
  require "multi_json"
2
+
3
+ if RUBY_VERSION =~ /^1\.8/
4
+ begin
5
+ require "iconv"
6
+ rescue LoadError
7
+ end
8
+ end
9
+
2
10
  require "pathname"
3
11
 
4
12
  module Bugsnag
@@ -183,32 +191,34 @@ module Bugsnag
183
191
  # Warn if no release_stage is set
184
192
  Bugsnag.warn "You should set your app's release_stage (see https://bugsnag.com/docs/notifiers/ruby#release_stage)." unless @configuration.release_stage
185
193
 
186
- @meta_data = {}
194
+ @configuration.internal_middleware.run(self) { }
187
195
 
188
- # Run the middleware here, at the end of the middleware stack, execute the actual delivery
189
- @configuration.middleware.run(self) do
190
- # At this point the callbacks have already been run.
191
- # This supports self.ignore! for before_notify_callbacks.
192
- return if @should_ignore
193
-
194
- # Now override the required fields
195
- exceptions.each do |exception|
196
- if exception.class.include?(Bugsnag::MetaData)
197
- if exception.bugsnag_user_id.is_a?(String)
198
- self.user_id = exception.bugsnag_user_id
199
- end
200
- if exception.bugsnag_context.is_a?(String)
201
- self.context = exception.bugsnag_context
202
- end
196
+ exceptions.each do |exception|
197
+ if exception.class.include?(Bugsnag::MetaData)
198
+ if exception.bugsnag_user_id.is_a?(String)
199
+ self.user_id = exception.bugsnag_user_id
200
+ end
201
+ if exception.bugsnag_context.is_a?(String)
202
+ self.context = exception.bugsnag_context
203
203
  end
204
204
  end
205
+ end
205
206
 
206
- [:user_id, :context, :user, :grouping_hash].each do |symbol|
207
- if @overrides[symbol]
208
- self.send("#{symbol}=", @overrides[symbol])
209
- @overrides.delete symbol
210
- end
207
+ [:user_id, :context, :user, :grouping_hash].each do |symbol|
208
+ if @overrides[symbol]
209
+ self.send("#{symbol}=", @overrides[symbol])
210
+ @overrides.delete symbol
211
211
  end
212
+ end
213
+
214
+ # make meta_data available to public middleware
215
+ @meta_data = Bugsnag::Helpers.cleanup_obj(generate_meta_data(@exceptions, @overrides), @configuration.params_filters)
216
+
217
+ # Run the middleware here (including Bugsnag::Middleware::Callbacks)
218
+ # at the end of the middleware stack, execute the actual notification delivery
219
+ @configuration.middleware.run(self) do
220
+ # This supports self.ignore! for before_notify_callbacks.
221
+ return if @should_ignore
212
222
 
213
223
  # Build the endpoint url
214
224
  endpoint = (@configuration.use_ssl ? "https://" : "http://") + @configuration.endpoint
@@ -227,11 +237,17 @@ module Bugsnag
227
237
  :exceptions => exception_list,
228
238
  :severity => self.severity,
229
239
  :groupingHash => self.grouping_hash,
230
- :metaData => Bugsnag::Helpers.cleanup_obj(generate_meta_data(@exceptions, @overrides), @configuration.params_filters)
231
- }.reject {|k,v| v.nil? }
240
+ }
232
241
 
233
242
  payload_event[:device] = {:hostname => @configuration.hostname} if @configuration.hostname
234
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
+
235
251
  # Build the payload hash
236
252
  payload = {
237
253
  :apiKey => api_key,
data/lib/bugsnag/rack.rb CHANGED
@@ -1,8 +1,3 @@
1
- require "bugsnag/middleware/rack_request"
2
- require "bugsnag/middleware/warden_user"
3
- require "bugsnag/middleware/callbacks"
4
- require "bugsnag/middleware/rails3_request"
5
-
6
1
  module Bugsnag
7
2
  class Rack
8
3
  def initialize(app)
@@ -46,7 +41,7 @@ module Bugsnag
46
41
  if env["rack.exception"]
47
42
  Bugsnag.auto_notify(env["rack.exception"])
48
43
  end
49
-
44
+
50
45
  response
51
46
  ensure
52
47
  # Clear per-request data after processing the each request
@@ -3,9 +3,9 @@ module Bugsnag::Rails
3
3
  def self.included(base)
4
4
  base.extend ClassMethods
5
5
  end
6
-
6
+
7
7
  module ClassMethods
8
- private
8
+ private
9
9
  def before_bugsnag_notify(*methods, &block)
10
10
  _add_bugsnag_notify_callback(:before_callbacks, *methods, &block)
11
11
  end
@@ -41,4 +41,4 @@ module Bugsnag::Rails
41
41
  Bugsnag.notify(exception, custom_data)
42
42
  end
43
43
  end
44
- end
44
+ end
data/lib/bugsnag/rake.rb CHANGED
@@ -11,38 +11,27 @@ module Bugsnag::Rake
11
11
  alias_method :define_task, :bugsnag_define_task
12
12
  end
13
13
  end
14
-
15
- Bugsnag.before_notify_callbacks << lambda {|notif|
16
- task = Thread.current[:bugsnag_running_task]
17
- next unless task
18
-
19
- notif.add_tab(:rake_task, {
20
- :name => task.name,
21
- :description => task.full_comment,
22
- :arguments => task.arg_description
23
- })
24
-
25
- notif.context ||= task.name
26
- }
27
14
  end
28
15
 
29
16
  module ClassMethods
30
17
  def bugsnag_define_task(*args, &block)
31
18
  task = self.original_define_task(*args) do |*block_args|
32
19
  begin
33
- old_task = Thread.current[:bugsnag_running_task]
34
- Thread.current[:bugsnag_running_task] = task
20
+ old_task = Bugsnag.configuration.request_data[:bugsnag_running_task]
21
+ Bugsnag.set_request_data :bugsnag_running_task, task
35
22
 
36
23
  yield(*block_args) if block_given?
37
24
  rescue Exception => e
38
25
  Bugsnag.auto_notify(e)
39
26
  raise
40
27
  ensure
41
- Thread.current[:bugsnag_running_task] = old_task
28
+ Bugsnag.set_request_data :bugsnag_running_task, old_task
42
29
  end
43
30
  end
44
31
  end
45
32
  end
46
33
  end
47
34
 
35
+ Bugsnag.configuration.internal_middleware.use(Bugsnag::Middleware::Rake)
36
+
48
37
  Rake::Task.send(:include, Bugsnag::Rake) if defined?(Rake::Task)
@@ -4,10 +4,9 @@ module Bugsnag
4
4
  class Sidekiq
5
5
  def call(worker, msg, queue)
6
6
  begin
7
- Bugsnag.before_notify_callbacks << lambda {|notif|
8
- notif.add_tab(:sidekiq, msg)
9
- notif.context ||= "sidekiq##{queue}"
10
- }
7
+
8
+ # store msg/queue in thread local state to be read by Bugsnag::Middleware::Sidekiq
9
+ Bugsnag.set_request_data :sidekiq, { :msg => msg, :queue => queue }
11
10
 
12
11
  yield
13
12
  rescue Exception => ex
@@ -34,3 +33,5 @@ else
34
33
  end
35
34
  end
36
35
  end
36
+
37
+ Bugsnag.configuration.internal_middleware.use(Bugsnag::Middleware::Sidekiq)
@@ -45,7 +45,9 @@ namespace :bugsnag do
45
45
  }
46
46
 
47
47
  # Fetch heroku config settings
48
- heroku_env = run_command.call("heroku config --shell").split.each_with_object({}) do |c, obj|
48
+ config_command = "heroku config --shell"
49
+ config_command += " --app #{ENV["HEROKU_APP"]}" if ENV["HEROKU_APP"]
50
+ heroku_env = run_command.call(config_command).split(/[\n\r]/).each_with_object({}) do |c, obj|
49
51
  k,v = c.split("=")
50
52
  obj[k] = v.strip.empty? ? nil : v
51
53
  end
@@ -71,6 +73,7 @@ namespace :bugsnag do
71
73
  # Add the hook
72
74
  url = "https://notify.bugsnag.com/deploy?" + params.map {|k,v| "#{k}=#{v}"}.join("&")
73
75
  command = "heroku addons:add deployhooks:http --url=\"#{url}\""
76
+ command += " --app #{ENV["HEROKU_APP"]}" if ENV["HEROKU_APP"]
74
77
 
75
78
  puts "$ #{command}"
76
79
  run_command.call(command)
@@ -0,0 +1,11 @@
1
+ class InternalInfoSetter
2
+ MESSAGE = "set by internal_middleware"
3
+ def initialize(bugsnag)
4
+ @bugsnag = bugsnag
5
+ end
6
+
7
+ def call(notification)
8
+ notification.meta_data[:custom][:info] = MESSAGE
9
+ @bugsnag.call(notification)
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ class PublicInfoSetter
2
+ MESSAGE = "set by middleware"
3
+ def initialize(bugsnag)
4
+ @bugsnag = bugsnag
5
+ end
6
+
7
+ def call(notification)
8
+ notification.meta_data[:custom][:info] = MESSAGE
9
+ @bugsnag.call(notification)
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ require "bugsnag/rake"
2
+
3
+ namespace :test do
4
+ desc "used by integration_spec to test that Bugsnag::Middleware::Rake runs properly"
5
+ task :crash do
6
+ port = ENV['BUGSNAG_TEST_SERVER_PORT']
7
+ Bugsnag.configure do |config|
8
+ config.endpoint = "localhost:#{port}"
9
+ config.api_key = "0" * 32
10
+ config.use_ssl = false
11
+ end
12
+
13
+ raise
14
+ end
15
+ end
data/spec/helper_spec.rb CHANGED
@@ -114,4 +114,20 @@ describe Bugsnag::Helpers do
114
114
 
115
115
  expect(url).to eq("/dir/page?param1=[FILTERED]&param2=[FILTERED]&param3=value3")
116
116
  end
117
+
118
+ it "filters using a combination of string and regex filters" do
119
+ url = Bugsnag::Helpers.cleanup_url "/dir/page?param1=value1&param2=value2&param3=value3", ["param1", /param2/]
120
+
121
+ expect(url).to eq("/dir/page?param1=[FILTERED]&param2=[FILTERED]&param3=value3")
122
+ end
123
+
124
+ it "filters regex matches" do
125
+ url = Bugsnag::Helpers.cleanup_url "https://host.example/sessions?access_token=abc123", [/\Aaccess_token\z/]
126
+ expect(url).to eq("https://host.example/sessions?access_token=[FILTERED]")
127
+ end
128
+
129
+ it "filters partial regex matches" do
130
+ url = Bugsnag::Helpers.cleanup_url "https://host.example/sessions?access_token=abc123", [/token/]
131
+ expect(url).to eq("https://host.example/sessions?access_token=[FILTERED]")
132
+ end
117
133
  end
@@ -1,5 +1,6 @@
1
1
  require 'webrick'
2
2
  require 'spec_helper'
3
+ require 'json'
3
4
 
4
5
  describe 'Bugsnag' do
5
6
  server = nil
@@ -20,6 +21,16 @@ describe 'Bugsnag' do
20
21
 
21
22
  let(:request) { JSON.parse(queue.pop) }
22
23
 
24
+ it 'should run the rake middleware when rake tasks crash' do
25
+ ENV['BUGSNAG_TEST_SERVER_PORT'] = server.config[:Port].to_s
26
+ task_fixtures_path = File.join(File.dirname(__FILE__), 'fixtures', 'tasks')
27
+ Dir.chdir(task_fixtures_path) do
28
+ system("bundle exec rake test:crash > /dev/null 2>&1")
29
+ end
30
+ expect(request["events"][0]["metaData"]["rake_task"]).not_to be_nil
31
+ expect(request["events"][0]["metaData"]["rake_task"]["name"]).to eq("test:crash")
32
+ end
33
+
23
34
  it 'should send notifications over the wire' do
24
35
  Bugsnag.configure do |config|
25
36
  config.endpoint = "localhost:#{server.config[:Port]}"
@@ -1,4 +1,6 @@
1
1
  require 'spec_helper'
2
+ require 'fixtures/middleware/public_info_setter'
3
+ require 'fixtures/middleware/internal_info_setter'
2
4
 
3
5
  describe Bugsnag::MiddlewareStack do
4
6
  it "runs before_bugsnag_notify callbacks, adding a tab" do
@@ -65,23 +67,28 @@ describe Bugsnag::MiddlewareStack do
65
67
 
66
68
  end
67
69
 
68
- it "overrides data set in before_notify" do
70
+ it "allows overrides to override values set by internal middleware" do
71
+ Bugsnag.configuration.internal_middleware.use(InternalInfoSetter)
72
+ Bugsnag.notify(BugsnagTestException.new("It crashed"), {:info => "overridden"})
69
73
 
70
- callback_run_count = 0
71
- Bugsnag.before_notify_callbacks << lambda {|notif|
72
- notif.add_custom_data(:info, "here")
73
- notif.add_custom_data(:data, "also here")
74
-
75
- callback_run_count += 1
74
+ expect(Bugsnag).to have_sent_notification{ |payload|
75
+ event = get_event_from_payload(payload)
76
+ expect(event["metaData"]["custom"]).not_to be_nil
77
+ expect(event["metaData"]["custom"]["info"]).not_to eq(InternalInfoSetter::MESSAGE)
78
+ expect(event["metaData"]["custom"]["info"]).to eq("overridden")
76
79
  }
80
+ end
81
+
82
+ it "doesn't allow overrides to override public middleware" do
83
+ Bugsnag.configuration.middleware.use(PublicInfoSetter)
84
+
85
+ Bugsnag.notify(BugsnagTestException.new("It crashed"), {:info => "overridden"})
77
86
 
78
- Bugsnag.notify(BugsnagTestException.new("It crashed"), {:info => "here2"})
79
- expect(callback_run_count).to eq(1)
80
87
  expect(Bugsnag).to have_sent_notification{ |payload|
81
88
  event = get_event_from_payload(payload)
82
89
  expect(event["metaData"]["custom"]).not_to be_nil
83
- expect(event["metaData"]["custom"]["info"]).to eq("here2")
84
- expect(event["metaData"]["custom"]["data"]).to eq("also here")
90
+ expect(event["metaData"]["custom"]["info"]).not_to eq("overridden")
91
+ expect(event["metaData"]["custom"]["info"]).to eq(PublicInfoSetter::MESSAGE)
85
92
  }
86
93
  end
87
94
 
@@ -93,7 +100,6 @@ describe Bugsnag::MiddlewareStack do
93
100
  event = get_event_from_payload(payload)
94
101
  expect(event["metaData"].size).to eq(0)
95
102
  }
96
-
97
103
  end
98
104
 
99
105
  it "runs after_bugsnag_notify callbacks" do
@@ -105,7 +111,7 @@ describe Bugsnag::MiddlewareStack do
105
111
  Bugsnag.notify(BugsnagTestException.new("It crashed"))
106
112
 
107
113
  expect(callback_run_count).to eq(1)
108
- expect(Bugsnag::Notification).to have_sent_notification
114
+ expect(Bugsnag::Notification).to have_sent_notification { }
109
115
  end
110
116
 
111
117
  it "does not execute disabled bugsnag middleware" do
@@ -127,7 +133,7 @@ describe Bugsnag::MiddlewareStack do
127
133
  notif.ignore!
128
134
  end
129
135
  Bugsnag.notify(BugsnagTestException.new("It crashed"))
130
- expect(Bugsnag::Notification).not_to have_sent_notification
136
+ expect(Bugsnag::Notification).not_to have_sent_notification { }
131
137
  end
132
138
 
133
139
  it "allows inspection of meta_data before ignoring exception" do
@@ -145,4 +151,31 @@ describe Bugsnag::MiddlewareStack do
145
151
  expect(Bugsnag::Notification).not_to have_sent_notification
146
152
 
147
153
  end
154
+
155
+ it "allows meta_data to be modified in a middleware" do
156
+ MetaDataMunger = Class.new do
157
+ def initialize(bugsnag)
158
+ @bugsnag = bugsnag
159
+ end
160
+
161
+ def call(notification)
162
+ token = notification.meta_data[:sidekiq][:args].first
163
+ notification.meta_data[:sidekiq][:args] = ["#{token[0...6]}*****#{token[-4..-1]}"]
164
+ @bugsnag.call(notification)
165
+ end
166
+ end
167
+
168
+ Bugsnag.configure do |c|
169
+ c.middleware.use MetaDataMunger
170
+ end
171
+
172
+ notification = Bugsnag.notify(BugsnagTestException.new("It crashed"), {
173
+ :sidekiq => {
174
+ :args => ["abcdef123456abcdef123456abcdef123456"]
175
+ }
176
+ })
177
+
178
+ expect(notification.meta_data[:sidekiq][:args]).to eq(["abcdef*****3456"])
179
+ end
180
+
148
181
  end
@@ -267,8 +267,8 @@ describe Bugsnag::Notification do
267
267
 
268
268
  expect(Bugsnag).to have_sent_notification{ |payload|
269
269
  # Truncated body should be no bigger than
270
- # 2 truncated hashes (4096*2) + rest of payload (5000)
271
- expect(Bugsnag::Helpers.dump_json(payload).length).to be < 4096*2 + 10000
270
+ # 2 truncated hashes (4096*2) + rest of payload (20000)
271
+ expect(Bugsnag::Helpers.dump_json(payload).length).to be < 4096*2 + 20000
272
272
  }
273
273
  end
274
274
 
@@ -660,6 +660,116 @@ describe Bugsnag::Notification do
660
660
  }
661
661
  end
662
662
 
663
+ it "should handle utf8 encoding errors in exceptions_list" do
664
+ invalid_data = "\"foo\xEBbar\""
665
+ invalid_data = invalid_data.force_encoding("utf-8") if invalid_data.respond_to?(:force_encoding)
666
+
667
+ begin
668
+ JSON.parse(invalid_data)
669
+ rescue
670
+ Bugsnag.notify $!
671
+ end
672
+
673
+ expect(Bugsnag).to have_sent_notification { |payload|
674
+ if defined?(Encoding::UTF_8)
675
+ expect(payload.to_json).to match(/foo�bar/)
676
+ else
677
+ expect(payload.to_json).to match(/foobar/)
678
+ end
679
+ }
680
+ end
681
+
682
+ it "should handle utf8 encoding errors in notification context" do
683
+ invalid_data = "\"foo\xEBbar\""
684
+ invalid_data = invalid_data.force_encoding("utf-8") if invalid_data.respond_to?(:force_encoding)
685
+
686
+ begin
687
+ raise
688
+ rescue
689
+ Bugsnag.notify($!, { :context => invalid_data })
690
+ end
691
+
692
+ expect(Bugsnag).to have_sent_notification { |payload|
693
+ if defined?(Encoding::UTF_8)
694
+ expect(payload.to_json).to match(/foo�bar/)
695
+ else
696
+ expect(payload.to_json).to match(/foobar/)
697
+ end
698
+ }
699
+ end
700
+
701
+ it "should handle utf8 encoding errors in notification app fields" do
702
+ invalid_data = "\"foo\xEBbar\""
703
+ invalid_data = invalid_data.force_encoding("utf-8") if invalid_data.respond_to?(:force_encoding)
704
+
705
+ Bugsnag.configuration.app_version = invalid_data
706
+ Bugsnag.configuration.release_stage = invalid_data
707
+ Bugsnag.configuration.app_type = invalid_data
708
+
709
+ begin
710
+ raise
711
+ rescue
712
+ Bugsnag.notify $!
713
+ end
714
+
715
+ expect(Bugsnag).to have_sent_notification { |payload|
716
+ if defined?(Encoding::UTF_8)
717
+ expect(payload.to_json).to match(/foo�bar/)
718
+ else
719
+ expect(payload.to_json).to match(/foobar/)
720
+ end
721
+ }
722
+ end
723
+
724
+ it "should handle utf8 encoding errors in grouping_hash" do
725
+ invalid_data = "\"foo\xEBbar\""
726
+ invalid_data = invalid_data.force_encoding("utf-8") if invalid_data.respond_to?(:force_encoding)
727
+
728
+ Bugsnag.before_notify_callbacks << lambda do |notif|
729
+ notif.grouping_hash = invalid_data
730
+ end
731
+
732
+ begin
733
+ raise
734
+ rescue
735
+ Bugsnag.notify $!
736
+ end
737
+
738
+ expect(Bugsnag).to have_sent_notification { |payload|
739
+ if defined?(Encoding::UTF_8)
740
+ expect(payload.to_json).to match(/foo�bar/)
741
+ else
742
+ expect(payload.to_json).to match(/foobar/)
743
+ end
744
+ }
745
+ end
746
+
747
+ it "should handle utf8 encoding errors in notification user fields" do
748
+ invalid_data = "\"foo\xEBbar\""
749
+ invalid_data = invalid_data.force_encoding("utf-8") if invalid_data.respond_to?(:force_encoding)
750
+
751
+ Bugsnag.before_notify_callbacks << lambda do |notif|
752
+ notif.user = {
753
+ :email => "#{invalid_data}@foo.com",
754
+ :name => invalid_data
755
+ }
756
+ end
757
+
758
+ begin
759
+ raise
760
+ rescue
761
+ Bugsnag.notify $!
762
+ end
763
+
764
+ expect(Bugsnag).to have_sent_notification { |payload|
765
+ if defined?(Encoding::UTF_8)
766
+ expect(payload.to_json).to match(/foo�bar/)
767
+ else
768
+ expect(payload.to_json).to match(/foobar/)
769
+ end
770
+ }
771
+ end
772
+
663
773
  if defined?(JRUBY_VERSION)
664
774
 
665
775
  it "should work with java.lang.Throwables" do
data/spec/spec_helper.rb CHANGED
@@ -45,8 +45,9 @@ def have_sent_notification(&matcher)
45
45
  have_requested(:post, "https://notify.bugsnag.com/").with do |request|
46
46
  if matcher
47
47
  matcher.call JSON.parse(request.body)
48
- else
49
48
  true
49
+ else
50
+ raise "no matcher provided to have_sent_notification (did you use { })"
50
51
  end
51
52
  end
52
53
  end
metadata CHANGED
@@ -1,97 +1,97 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bugsnag
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.7.1
4
+ version: 2.8.0
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-01-04 00:00:00.000000000 Z
11
+ date: 2015-02-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: multi_json
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ~>
18
18
  - !ruby/object:Gem::Version
19
19
  version: '1.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ~>
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - '>='
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ">="
38
+ - - '>='
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - '>='
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">="
52
+ - - '>='
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rdoc
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ">="
59
+ - - '>='
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ">="
66
+ - - '>='
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: pry
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ">="
73
+ - - '>='
74
74
  - !ruby/object:Gem::Version
75
75
  version: '0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ">="
80
+ - - '>='
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: webmock
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - ">="
87
+ - - '>='
88
88
  - !ruby/object:Gem::Version
89
89
  version: '0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - ">="
94
+ - - '>='
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  description: Ruby notifier for bugsnag.com
@@ -102,10 +102,10 @@ extra_rdoc_files:
102
102
  - LICENSE.txt
103
103
  - README.md
104
104
  files:
105
- - ".document"
106
- - ".gitignore"
107
- - ".rspec"
108
- - ".travis.yml"
105
+ - .document
106
+ - .gitignore
107
+ - .rspec
108
+ - .travis.yml
109
109
  - CHANGELOG.md
110
110
  - Gemfile
111
111
  - LICENSE.txt
@@ -127,9 +127,12 @@ files:
127
127
  - lib/bugsnag/mailman.rb
128
128
  - lib/bugsnag/meta_data.rb
129
129
  - lib/bugsnag/middleware/callbacks.rb
130
+ - lib/bugsnag/middleware/mailman.rb
130
131
  - lib/bugsnag/middleware/rack_request.rb
131
132
  - lib/bugsnag/middleware/rails2_request.rb
132
133
  - lib/bugsnag/middleware/rails3_request.rb
134
+ - lib/bugsnag/middleware/rake.rb
135
+ - lib/bugsnag/middleware/sidekiq.rb
133
136
  - lib/bugsnag/middleware/warden_user.rb
134
137
  - lib/bugsnag/middleware_stack.rb
135
138
  - lib/bugsnag/notification.rb
@@ -152,6 +155,9 @@ files:
152
155
  - spec/fixtures/crashes/end_of_file.rb
153
156
  - spec/fixtures/crashes/short_file.rb
154
157
  - spec/fixtures/crashes/start_of_file.rb
158
+ - spec/fixtures/middleware/internal_info_setter.rb
159
+ - spec/fixtures/middleware/public_info_setter.rb
160
+ - spec/fixtures/tasks/Rakefile
155
161
  - spec/helper_spec.rb
156
162
  - spec/integration_spec.rb
157
163
  - spec/middleware_spec.rb
@@ -168,17 +174,17 @@ require_paths:
168
174
  - lib
169
175
  required_ruby_version: !ruby/object:Gem::Requirement
170
176
  requirements:
171
- - - ">="
177
+ - - '>='
172
178
  - !ruby/object:Gem::Version
173
179
  version: '0'
174
180
  required_rubygems_version: !ruby/object:Gem::Requirement
175
181
  requirements:
176
- - - ">="
182
+ - - '>='
177
183
  - !ruby/object:Gem::Version
178
184
  version: '0'
179
185
  requirements: []
180
186
  rubyforge_project:
181
- rubygems_version: 2.2.2
187
+ rubygems_version: 2.0.14
182
188
  signing_key:
183
189
  specification_version: 4
184
190
  summary: Ruby notifier for bugsnag.com