bugsnag 2.7.1 → 2.8.0

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