rollbar 2.12.0 → 2.13.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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +33 -6
  3. data/README.md +58 -8
  4. data/docs/configuration.md +12 -0
  5. data/gemfiles/rails30.gemfile +1 -0
  6. data/gemfiles/rails31.gemfile +1 -0
  7. data/gemfiles/rails32.gemfile +1 -0
  8. data/gemfiles/rails40.gemfile +3 -0
  9. data/gemfiles/rails41.gemfile +1 -0
  10. data/gemfiles/rails42.gemfile +7 -1
  11. data/gemfiles/rails50.gemfile +2 -1
  12. data/gemfiles/ruby_1_8_and_1_9_2.gemfile +3 -1
  13. data/lib/rollbar.rb +70 -654
  14. data/lib/rollbar/configuration.rb +32 -0
  15. data/lib/rollbar/item.rb +16 -6
  16. data/lib/rollbar/item/backtrace.rb +26 -17
  17. data/lib/rollbar/item/frame.rb +112 -0
  18. data/lib/rollbar/middleware/js.rb +39 -35
  19. data/lib/rollbar/middleware/rails/rollbar.rb +3 -3
  20. data/lib/rollbar/notifier.rb +645 -0
  21. data/lib/rollbar/plugins/delayed_job/job_data.rb +40 -21
  22. data/lib/rollbar/plugins/rails.rb +2 -2
  23. data/lib/rollbar/plugins/rake.rb +32 -6
  24. data/lib/rollbar/plugins/resque.rb +11 -0
  25. data/lib/rollbar/plugins/resque/failure.rb +39 -0
  26. data/lib/rollbar/plugins/validations.rb +10 -0
  27. data/lib/rollbar/request_data_extractor.rb +36 -18
  28. data/lib/rollbar/scrubbers/params.rb +2 -1
  29. data/lib/rollbar/truncation.rb +1 -1
  30. data/lib/rollbar/truncation/frames_strategy.rb +2 -1
  31. data/lib/rollbar/truncation/min_body_strategy.rb +2 -1
  32. data/lib/rollbar/truncation/strings_strategy.rb +1 -1
  33. data/lib/rollbar/version.rb +1 -1
  34. data/spec/controllers/home_controller_spec.rb +13 -24
  35. data/spec/delayed/backend/test.rb +1 -0
  36. data/spec/requests/home_spec.rb +1 -1
  37. data/spec/rollbar/configuration_spec.rb +22 -0
  38. data/spec/rollbar/item/backtrace_spec.rb +26 -0
  39. data/spec/rollbar/item/frame_spec.rb +267 -0
  40. data/spec/rollbar/item_spec.rb +27 -2
  41. data/spec/rollbar/middleware/js_spec.rb +23 -0
  42. data/spec/rollbar/middleware/sinatra_spec.rb +7 -7
  43. data/spec/rollbar/notifier_spec.rb +43 -0
  44. data/spec/rollbar/plugins/delayed_job/{job_data.rb → job_data_spec.rb} +15 -2
  45. data/spec/rollbar/plugins/rack_spec.rb +7 -7
  46. data/spec/rollbar/plugins/rake_spec.rb +1 -2
  47. data/spec/rollbar/plugins/resque/failure_spec.rb +36 -0
  48. data/spec/rollbar/request_data_extractor_spec.rb +103 -1
  49. data/spec/rollbar/truncation/min_body_strategy_spec.rb +1 -1
  50. data/spec/rollbar/truncation/strings_strategy_spec.rb +2 -2
  51. data/spec/rollbar_bc_spec.rb +4 -4
  52. data/spec/rollbar_spec.rb +99 -37
  53. data/spec/spec_helper.rb +2 -2
  54. data/spec/support/notifier_helpers.rb +2 -0
  55. metadata +16 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c81062a0a25993cc7d6e1cb8a16d6f2f2b2faf43
4
- data.tar.gz: ddfba1b5a84dafd6d2b2113ae383a1a1255dd1b7
3
+ metadata.gz: d7a60c8f3a1929550de7236c1f2cad3f06d686ef
4
+ data.tar.gz: 7c91ff957d85efa7387384948174d1ea6f745b00
5
5
  SHA512:
6
- metadata.gz: 498f4e0b6509703b0c2c8044f669bf9aa60417ff198376abfbb02ac5d8e4953c0cc470d97e4f68212b38368e1d62e5bcb61783d80a078fcc7dc5735eb7408ac4
7
- data.tar.gz: 23fa88ce1a8422d70cc6f409439a32a703321435b2a43d7c6f2eb30ecb0ba60510d1b3e2fa0a79ff493eab9be053ac8b007767c6df8d4fd741ae0d6acd3042bf
6
+ metadata.gz: a53c437380edf552740dec8ece8c8bf90f774b5c1ba420ac8526f8a11eaf8bd502ec6798f70da4ce056cbadae215ebef4629cd75e81742164cc78838fc89a0ba
7
+ data.tar.gz: f5bda5da6010fa1a5d6d4d1571c5973e78d42fba2523731be1f5c38295cf808c7f2e9bfdb9035da143963fdb65dc8c586b739e91b4200a2a70f4f7fbafc5eea9
data/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # Change Log
2
2
 
3
+ ## 2.13.0
4
+
5
+ Features:
6
+ - Allow to override config. See [#519](https://github.com/rollbar/rollbar-gem/pull/519).
7
+ - Send code and context frame data. See [#523](https://github.com/rollbar/rollbar-gem/pull/523).
8
+ - Send GET, POST and raw body in their correct place. See [#522](https://github.com/rollbar/rollbar-gem/pull/522).
9
+ - Increase max payload from 128kb to 512kb. See [#521](https://github.com/rollbar/rollbar-gem/pull/521).
10
+ - Add resque-rollbar functionality to the gem. See [#516](https://github.com/rollbar/rollbar-gem/pull/516).
11
+ - Send custom.orig_host and custom.orig_uuid on too large payloads. See [#518](https://github.com/rollbar/rollbar-gem/pull/518).
12
+ - Add Content-Length and Content-Type headers to the reports. See [#513](https://github.com/rollbar/rollbar-gem/pull/513).
13
+
14
+ Bug fixes:
15
+ - SecureHeaders fixes. See [#478](https://github.com/rollbar/rollbar-gem/pull/478).
16
+ - Include validations plugin in activerecord base. See [#503](https://github.com/rollbar/rollbar-gem/pull/503).
17
+ - Require tempfile and use ::Tempfile. See [#514](https://github.com/rollbar/rollbar-gem/pull/514).
18
+ - Extract correct client IP from X-Forwarded-For header. See [#515](https://github.com/rollbar/rollbar-gem/pull/515).
19
+ - Delayed job fix on job serialization. See [#512](https://github.com/rollbar/rollbar-gem/pull/512).
20
+
21
+ Others:
22
+ - Fix tests on rails40 and ruby 1.8.7. See [#485](https://github.com/rollbar/rollbar-gem/pull/485).
23
+ - Move log methods to public section. See [#498](https://github.com/rollbar/rollbar-gem/pull/498).
24
+ - Change rails50.gemfile to use Rails 5.0.0. See [#495](https://github.com/rollbar/rollbar-gem/pull/495).
25
+ - Update CHANGELOG.md to fix incorrect links. See [#502](https://github.com/rollbar/rollbar-gem/pull/502).
26
+ - Improve Rake support to avoid conflicts with other services. See [#517](https://github.com/rollbar/rollbar-gem/pull/517).
27
+ - Make Codeclimate happier with Rollbar::Middlware::Js. See [#520](https://github.com/rollbar/rollbar-gem/pull/520).
28
+
29
+
3
30
  ## 2.12.0
4
31
 
5
32
  Features:
@@ -13,7 +40,7 @@ Others:
13
40
 
14
41
  ## 2.11.5
15
42
 
16
- Bugfixes:
43
+ Bugf ixes:
17
44
 
18
45
  - Use require_dependency for rake and sidekiq plugins. See [#485](https://github.com/rollbar/rollbar-gem/pull/485).
19
46
  - Add immediate ActiveModel::Validations monkey patch. See [#484](https://github.com/rollbar/rollbar-gem/pull/484).
@@ -53,7 +80,7 @@ Bug fixes:
53
80
 
54
81
  New features:
55
82
 
56
- - Rollbar.js support wit SecureHeaders 2.0. See [#448](https://github.com/rollbar/rollbar-gem/pull/448).
83
+ - Rollbar.js support with SecureHeaders 2.0. See [#448](https://github.com/rollbar/rollbar-gem/pull/448).
57
84
  - Inject extensions in ActiveModel::Validations instead of ActiveRecord::Base. See [#445](https://github.com/rollbar/rollbar-gem/pull/445).
58
85
 
59
86
  Bug fixes:
@@ -64,7 +91,7 @@ Bug fixes:
64
91
 
65
92
  Refactors and others:
66
93
 
67
- - Refactor Item payload building. See [#452](https://github.com/rollbar/rollbar-gem/pull/454).
94
+ - Refactor Item payload building. See [#452](https://github.com/rollbar/rollbar-gem/pull/452).
68
95
  - Mock the requests to Rollbar API. See [#450](https://github.com/rollbar/rollbar-gem/pull/450).
69
96
  - Add plugins architecture. See [#438](https://github.com/rollbar/rollbar-gem/pull/438).
70
97
  - Add TOC for README.md. See [#444](https://github.com/rollbar/rollbar-gem/pull/444).
@@ -199,8 +226,8 @@ Features
199
226
 
200
227
  Bug fixes:
201
228
 
202
- - Use ACCEPT header to check json requests. See [#328](https://github.com/rollbar/rollbar-gem/pull/333)
203
- - Fix URL scrubbing when using a malformed URL. See [#328](https://github.com/rollbar/rollbar-gem/pull/332)
229
+ - Use ACCEPT header to check json requests. See [#333](https://github.com/rollbar/rollbar-gem/pull/333)
230
+ - Fix URL scrubbing when using a malformed URL. See [#332](https://github.com/rollbar/rollbar-gem/pull/332)
204
231
 
205
232
  ## 2.5.1
206
233
 
@@ -237,7 +264,7 @@ Documentation:
237
264
 
238
265
  Bug fixes:
239
266
 
240
- - Remove better errors hook. This was causing to report twice the errors. See [#313](https://github.com/rollbar/rollbar-gem/pull/300)
267
+ - Remove better errors hook. This was causing to report twice the errors. See [#313](https://github.com/rollbar/rollbar-gem/pull/313)
241
268
 
242
269
 
243
270
  ## 2.3.0
data/README.md CHANGED
@@ -1,10 +1,4 @@
1
- ---
2
- layout: page
3
- sidebar: rollbar_sidebar
4
- permalink: /notifiers/rollbar-gem/
5
- toc: false
6
- ---
7
- # Rollbar [![Build Status](https://api.travis-ci.org/rollbar/rollbar-gem.svg?branch=v2.12.0)](https://travis-ci.org/rollbar/rollbar-gem/branches)
1
+ # Rollbar [![Build Status](https://api.travis-ci.org/rollbar/rollbar-gem.svg?branch=v2.13.0)](https://travis-ci.org/rollbar/rollbar-gem/branches)
8
2
 
9
3
  <!-- RemoveNext -->
10
4
  [Rollbar](https://rollbar.com) is an error tracking service for Ruby and other languages. The Rollbar service will alert you of problems with your code and help you understand them in a ways never possible before. We love it and we hope you will too.
@@ -36,6 +30,8 @@ This is the Ruby library for Rollbar. It will instrument many kinds of Ruby appl
36
30
  - [Before process hook](#before-process-hook)
37
31
  - [Transform hook](#transform-hook)
38
32
  - [The Scope](#the-scope)
33
+ - [Override configuration](#override-configuration)
34
+ - [Code and context](#code-and-context)
39
35
  - [Silencing exceptions at runtime](#silencing-exceptions-at-runtime)
40
36
  - [Sending backtrace without rescued exceptions](#sending-backtrace-without-rescued-exceptions)
41
37
  - [ActiveJob integration](#activejob-integration)
@@ -613,6 +609,49 @@ your_handler = proc do |options|
613
609
  end
614
610
  ```
615
611
 
612
+ ## Override configuration
613
+
614
+ There are some cases where you would need to change the Rollbar configuration for a specific block of code so a new configuration is used on the reported errors in that block. You can use `Rollbar.with_config` to do this. It receives a `Hash` object with the configuration overrides you want to use for the given block. The configuration options to use can be read at [Configuration](https://rollbar.com/docs/notifier/rollbar-gem/configuration/). So the `Hash` passed to `with_config` can be like `{environment: 'specific-environment'}`. Example:
615
+
616
+ ```ruby
617
+ Rollbar.with_config(use_async: false) do
618
+ begin
619
+ # do work that may crash
620
+ rescue => e
621
+ Rollbar.error(e)
622
+ end
623
+ end
624
+ ```
625
+
626
+ This method looks similar to `Rollbar.scoped` and internally `Rollbar.with_config` uses it. Now `Rollbar.scoped` can receive a second argument with the config overrides for the given block of code. So if you need to set a new payload scope and new config for a code block, you can:
627
+
628
+ ```ruby
629
+ scope = {context: 'foo'}
630
+ new_config = {framework: 'Sinatra'}
631
+
632
+ Rollbar.scoped(scope, new_config) do
633
+ begin
634
+ # do work that may crash
635
+ rescue => e
636
+ Rollbar.error(e)
637
+ end
638
+ end
639
+ ```
640
+
641
+ In the example from above we are defining a new payload scope and overriding the `framework` configuration for the reported errors inside the given block.
642
+
643
+ ## Code and context
644
+
645
+ By default we send the following values for each backtrace frame: `filename`, `lineno` and `method`. You can configure Rollbar to additionally send `code` (the actual line of code) and `context` (lines before and after) for each frame.
646
+
647
+ Since the backtrace can be very long, you can configure to send this data for all the frames or only your in-project frames. There are three levels: `:none` (default), `:app` (only your project files) and `:all`. Example:
648
+
649
+ ```ruby
650
+ Rollbar.configure do |config|
651
+ config.send_extra_frame_data = :app
652
+ end
653
+ ```
654
+
616
655
  ## Silencing exceptions at runtime
617
656
 
618
657
  If you just want to disable exception reporting for a single block, use ```Rollbar.silenced```:
@@ -937,7 +976,18 @@ If you're using [Goalie](https://github.com/obvio171/goalie) for custom error pa
937
976
 
938
977
  ## Resque
939
978
 
940
- Check out [resque-rollbar](https://github.com/dimko/resque-rollbar) for using Rollbar as a failure backend for Resque.
979
+ From a time ago, Resque errors reporting was supported by the gem [resque-rollbar](https://github.com/dimko/resque-rollbar). Now that functionality is built-in in the own gem. All you need to do is use `Resque::Failure::Rollbar` as the failure backend for Resque.
980
+
981
+ In your resque configuration add next lines:
982
+
983
+ ```ruby
984
+ require 'resque/failure/multiple'
985
+ require 'resque/failure/redis'
986
+ require 'rollbar'
987
+
988
+ Resque::Failure::Multiple.classes = [ Resque::Failure::Redis, Resque::Failure::Rollbar ]
989
+ Resque::Failure.backend = Resque::Failure::Multiple
990
+ ```
941
991
 
942
992
  ## SSL
943
993
 
@@ -102,6 +102,18 @@ Rollbar notifier.
102
102
 
103
103
  The number of job failures before reporting the failure to Rollbar.
104
104
 
105
+ ### enabled
106
+
107
+ **Default** `true`
108
+
109
+ Set to false to turn Rollbar off and stop reporting errors.
110
+
111
+ ### environment
112
+
113
+ **Default** unspecified
114
+
115
+ The environment that your code is running in.
116
+
105
117
  ### failover_handlers
106
118
 
107
119
  An array of backup handlers if the async handlers fails. Each should respond to
@@ -41,5 +41,6 @@ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.0')
41
41
  end
42
42
 
43
43
  gem 'webmock', :require => false
44
+ gem 'resque'
44
45
 
45
46
  gemspec :path => '../'
@@ -39,5 +39,6 @@ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.0')
39
39
  end
40
40
 
41
41
  gem 'webmock', :require => false
42
+ gem 'resque'
42
43
 
43
44
  gemspec :path => "../"
@@ -41,5 +41,6 @@ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.0')
41
41
  end
42
42
 
43
43
  gem 'webmock', :require => false
44
+ gem 'resque'
44
45
 
45
46
  gemspec :path => "../"
@@ -23,8 +23,10 @@ gem 'sidekiq', '>= 2.13.0' if RUBY_VERSION != '1.8.7'
23
23
 
24
24
  if RUBY_VERSION.start_with?('1.9')
25
25
  gem 'sucker_punch', '~> 1.0'
26
+ gem 'json', '~> 1.8'
26
27
  elsif RUBY_VERSION.start_with?('2')
27
28
  gem 'sucker_punch', '~> 2.0'
29
+ gem 'json', '~> 2.0'
28
30
  end
29
31
 
30
32
  gem 'sinatra'
@@ -41,5 +43,6 @@ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.0')
41
43
  end
42
44
 
43
45
  gem 'webmock', :require => false
46
+ gem 'resque'
44
47
 
45
48
  gemspec :path => "../"
@@ -39,5 +39,6 @@ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.0')
39
39
  end
40
40
 
41
41
  gem 'webmock', :require => false
42
+ gem 'resque'
42
43
 
43
44
  gemspec :path => "../"
@@ -16,7 +16,6 @@ gem "rails", "4.2.3"
16
16
  gem 'rspec-rails', '~> 3.4'
17
17
  gem 'rake'
18
18
 
19
- gem 'oj', '~> 2.12.14' unless is_jruby
20
19
  gem 'sidekiq', '>= 2.13.0' if RUBY_VERSION != '1.8.7'
21
20
 
22
21
  if RUBY_VERSION.start_with?('1.9')
@@ -25,6 +24,12 @@ elsif RUBY_VERSION.start_with?('2')
25
24
  gem 'sucker_punch', '~> 2.0'
26
25
  end
27
26
 
27
+ if RUBY_VERSION.start_with?('2.4')
28
+ gem 'oj', '~> 2.16.0' unless is_jruby
29
+ else
30
+ gem 'oj', '~> 2.12.14' unless is_jruby
31
+ end
32
+
28
33
  gem 'sinatra'
29
34
  gem 'resque'
30
35
  gem 'delayed_job', :require => false
@@ -39,5 +44,6 @@ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.0')
39
44
  end
40
45
 
41
46
  gem 'webmock', :require => false
47
+ gem 'resque'
42
48
 
43
49
  gemspec :path => "../"
@@ -12,7 +12,7 @@ gem 'rubysl', '~> 2.0', :platform => :rbx
12
12
  gem 'racc', :platform => :rbx
13
13
  gem 'minitest', :platform => :rbx
14
14
  gem 'rubinius-developer_tools', :platform => :rbx
15
- gem 'rails', '~> 5.0.0.beta1'
15
+ gem 'rails', '~> 5.0.0'
16
16
 
17
17
  gem 'rspec-core', '~> 3.5.0.beta3'
18
18
  gem 'rspec-rails', '~> 3.5.0.beta3'
@@ -45,5 +45,6 @@ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.0')
45
45
  end
46
46
 
47
47
  gem 'webmock', :require => false
48
+ gem 'resque'
48
49
 
49
50
  gemspec :path => '../'
@@ -33,11 +33,13 @@ gem 'resque'
33
33
  gem 'delayed_job', :require => false
34
34
  gem 'redis'
35
35
  gem 'database_cleaner', '~> 1.0.0'
36
- gem 'genspec', '>= 0.2.8'
36
+ gem 'genspec', '= 0.2.8'
37
37
  gem 'girl_friday', '>= 0.11.1'
38
38
 
39
39
  if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.0')
40
40
  gem 'mime-types', '< 3.0'
41
41
  end
42
42
 
43
+ gem 'resque'
44
+
43
45
  gemspec :path => '../'
data/lib/rollbar.rb CHANGED
@@ -12,633 +12,19 @@ end
12
12
 
13
13
  require 'rollbar/version'
14
14
  require 'rollbar/plugins'
15
- require 'rollbar/json'
16
- require 'rollbar/js'
17
15
  require 'rollbar/configuration'
18
- require 'rollbar/item'
19
- require 'rollbar/encoding'
20
16
  require 'rollbar/logger_proxy'
21
- require 'rollbar/exception_reporter'
22
- require 'rollbar/util'
23
- require 'rollbar/delay/girl_friday' if defined?(GirlFriday)
24
- require 'rollbar/delay/thread'
25
- require 'rollbar/truncation'
26
17
  require 'rollbar/exceptions'
27
18
  require 'rollbar/lazy_store'
28
- require 'rollbar/language_support'
19
+ require 'rollbar/notifier'
29
20
 
21
+ # The Rollbar module. It stores a Rollbar::Notifier per thread and
22
+ # provides some module methods in order to use the current thread notifier.
30
23
  module Rollbar
31
24
  PUBLIC_NOTIFIER_METHODS = %w(debug info warn warning error critical log logger
32
- process_item process_from_async_handler scope send_failsafe log_info log_debug
33
- log_warning log_error silenced)
34
-
35
- class Notifier
36
- attr_accessor :configuration
37
- attr_accessor :last_report
38
- attr_reader :scope_object
39
-
40
- @file_semaphore = Mutex.new
41
-
42
- def initialize(parent_notifier = nil, payload_options = nil, scope = nil)
43
- if parent_notifier
44
- @configuration = parent_notifier.configuration.clone
45
- @scope_object = parent_notifier.scope_object.clone
46
-
47
- Rollbar::Util.deep_merge(@configuration.payload_options, payload_options) if payload_options
48
- Rollbar::Util.deep_merge(@scope_object, scope) if scope
49
- else
50
- @configuration = ::Rollbar::Configuration.new
51
- @scope_object = ::Rollbar::LazyStore.new(scope)
52
- end
53
- end
54
-
55
- # Similar to configure below, but used only internally within the gem
56
- # to configure it without initializing any of the third party hooks
57
- def preconfigure
58
- yield(configuration)
59
- end
60
-
61
- # Configures the notifier instance
62
- def configure
63
- configuration.enabled = true if configuration.enabled.nil?
64
-
65
- yield(configuration)
66
- end
67
-
68
- def scope(options = {})
69
- self.class.new(self, nil, options)
70
- end
71
-
72
- def scope!(options = {})
73
- Rollbar::Util.deep_merge(scope_object, options)
74
-
75
- self
76
- end
77
-
78
- # Returns a new notifier with same configuration options
79
- # but it sets Configuration#safely to true.
80
- # We are using this flag to avoid having inifite loops
81
- # when evaluating some custom user methods.
82
- def safely
83
- new_notifier = scope
84
- new_notifier.configuration.safely = true
85
-
86
- new_notifier
87
- end
88
-
89
- # Turns off reporting for the given block.
90
- #
91
- # @example
92
- # Rollbar.silenced { raise }
93
- #
94
- # @yield Block which exceptions won't be reported.
95
- def silenced
96
- yield
97
- rescue => e
98
- e.instance_variable_set(:@_rollbar_do_not_report, true)
99
- raise
100
- end
101
-
102
- # Sends a report to Rollbar.
103
- #
104
- # Accepts any number of arguments. The last String argument will become
105
- # the message or description of the report. The last Exception argument
106
- # will become the associated exception for the report. The last hash
107
- # argument will be used as the extra data for the report.
108
- #
109
- # @example
110
- # begin
111
- # foo = bar
112
- # rescue => e
113
- # Rollbar.log(e)
114
- # end
115
- #
116
- # @example
117
- # Rollbar.log('This is a simple log message')
118
- #
119
- # @example
120
- # Rollbar.log(e, 'This is a description of the exception')
121
- #
122
- def log(level, *args)
123
- return 'disabled' unless configuration.enabled
124
-
125
- message, exception, extra = extract_arguments(args)
126
- use_exception_level_filters = extra && extra.delete(:use_exception_level_filters) == true
127
-
128
- return 'ignored' if ignored?(exception, use_exception_level_filters)
129
-
130
- begin
131
- call_before_process(:level => level,
132
- :exception => exception,
133
- :message => message,
134
- :extra => extra)
135
- rescue Rollbar::Ignore
136
- return 'ignored'
137
- end
138
-
139
- level = lookup_exception_level(level, exception,
140
- use_exception_level_filters)
141
-
142
- begin
143
- report(level, message, exception, extra)
144
- rescue Exception => e
145
- report_internal_error(e)
146
-
147
- 'error'
148
- end
149
- end
150
-
151
- # See log() above
152
- def debug(*args)
153
- log('debug', *args)
154
- end
155
-
156
- # See log() above
157
- def info(*args)
158
- log('info', *args)
159
- end
160
-
161
- # See log() above
162
- def warn(*args)
163
- log('warning', *args)
164
- end
165
-
166
- # See log() above
167
- def warning(*args)
168
- log('warning', *args)
169
- end
170
-
171
- # See log() above
172
- def error(*args)
173
- log('error', *args)
174
- end
175
-
176
- # See log() above
177
- def critical(*args)
178
- log('critical', *args)
179
- end
180
-
181
- def process_item(item)
182
- if configuration.write_to_file
183
- if configuration.use_async
184
- @file_semaphore.synchronize {
185
- write_item(item)
186
- }
187
- else
188
- write_item(item)
189
- end
190
- else
191
- send_item(item)
192
- end
193
- rescue => e
194
- log_error("[Rollbar] Error processing the item: #{e.class}, #{e.message}. Item: #{item.payload.inspect}")
195
- raise e
196
- end
197
-
198
- # We will reraise exceptions in this method so async queues
199
- # can retry the job or, in general, handle an error report some way.
200
- #
201
- # At same time that exception is silenced so we don't generate
202
- # infinite reports. This example is what we want to avoid:
203
- #
204
- # 1. New exception in a the project is raised
205
- # 2. That report enqueued to Sidekiq queue.
206
- # 3. The Sidekiq job tries to send the report to our API
207
- # 4. The report fails, for example cause a network failure,
208
- # and a exception is raised
209
- # 5. We report an internal error for that exception
210
- # 6. We reraise the exception so Sidekiq job fails and
211
- # Sidekiq can retry the job reporting the original exception
212
- # 7. Because the job failed and Sidekiq can be managed by rollbar we'll
213
- # report a new exception.
214
- # 8. Go to point 2.
215
- #
216
- # We'll then push to Sidekiq queue indefinitely until the network failure
217
- # is fixed.
218
- #
219
- # Using Rollbar.silenced we avoid the above behavior but Sidekiq
220
- # will have a chance to retry the original job.
221
- def process_from_async_handler(payload)
222
- payload = Rollbar::JSON.load(payload) if payload.is_a?(String)
223
-
224
- item = Item.build_with(payload,
225
- :notifier => self,
226
- :configuration => configuration,
227
- :logger => logger)
228
-
229
- Rollbar.silenced do
230
- begin
231
- process_item(item)
232
- rescue => e
233
- report_internal_error(e)
234
-
235
- raise
236
- end
237
- end
238
- end
239
-
240
- def send_failsafe(message, exception)
241
- exception_reason = failsafe_reason(message, exception)
242
-
243
- log_error "[Rollbar] Sending failsafe response due to #{exception_reason}"
244
-
245
- body = failsafe_body(exception_reason)
246
-
247
- failsafe_data = {
248
- :level => 'error',
249
- :environment => configuration.environment.to_s,
250
- :body => {
251
- :message => {
252
- :body => body
253
- }
254
- },
255
- :notifier => {
256
- :name => 'rollbar-gem',
257
- :version => VERSION
258
- },
259
- :internal => true,
260
- :failsafe => true
261
- }
262
-
263
- failsafe_payload = {
264
- 'access_token' => configuration.access_token,
265
- 'data' => failsafe_data
266
- }
267
-
268
- begin
269
- item = Item.build_with(failsafe_payload,
270
- :notifier => self,
271
- :configuration => configuration,
272
- :logger => logger)
273
- schedule_item(item)
274
- rescue => e
275
- log_error "[Rollbar] Error sending failsafe : #{e}"
276
- end
277
-
278
- failsafe_payload
279
- end
280
-
281
- private
282
-
283
- def call_before_process(options)
284
- options = {
285
- :level => options[:level],
286
- :scope => scope_object,
287
- :exception => options[:exception],
288
- :message => options[:message],
289
- :extra => options[:extra]
290
- }
291
- handlers = configuration.before_process
292
-
293
- handlers.each do |handler|
294
- begin
295
- handler.call(options)
296
- rescue Rollbar::Ignore
297
- raise
298
- rescue => e
299
- log_error("[Rollbar] Error calling the `before_process` hook: #{e}")
300
-
301
- break
302
- end
303
- end
304
- end
305
-
306
- def extract_arguments(args)
307
- message = nil
308
- exception = nil
309
- extra = nil
310
-
311
- args.each do |arg|
312
- if arg.is_a?(String)
313
- message = arg
314
- elsif arg.is_a?(Exception)
315
- exception = arg
316
- elsif arg.is_a?(Hash)
317
- extra = arg
318
- end
319
- end
320
-
321
- [message, exception, extra]
322
- end
323
-
324
- def lookup_exception_level(orig_level, exception, use_exception_level_filters)
325
- return orig_level unless use_exception_level_filters
326
-
327
- exception_level = filtered_level(exception)
328
- return exception_level if exception_level
329
-
330
- orig_level
331
- end
332
-
333
- def ignored?(exception, use_exception_level_filters = false)
334
- return false unless exception
335
- return true if use_exception_level_filters && filtered_level(exception) == 'ignore'
336
- return true if exception.instance_variable_get(:@_rollbar_do_not_report)
337
-
338
- false
339
- end
340
-
341
- def filtered_level(exception)
342
- return unless exception
343
-
344
- filter = configuration.exception_level_filters[exception.class.name]
345
- if filter.respond_to?(:call)
346
- filter.call(exception)
347
- else
348
- filter
349
- end
350
- end
351
-
352
- def report(level, message, exception, extra)
353
- unless message || exception || extra
354
- log_error '[Rollbar] Tried to send a report with no message, exception or extra data.'
355
-
356
- return 'error'
357
- end
358
-
359
- item = build_item(level, message, exception, extra)
360
-
361
- return 'ignored' if item.ignored?
362
-
363
- schedule_item(item)
364
-
365
- data = item['data']
366
- log_instance_link(data)
367
- Rollbar.last_report = data
368
-
369
- data
370
- end
371
-
372
- # Reports an internal error in the Rollbar library. This will be reported within the configured
373
- # Rollbar project. We'll first attempt to provide a report including the exception traceback.
374
- # If that fails, we'll fall back to a more static failsafe response.
375
- def report_internal_error(exception)
376
- log_error "[Rollbar] Reporting internal error encountered while sending data to Rollbar."
377
-
378
- begin
379
- item = build_item('error', nil, exception, {:internal => true})
380
- rescue => e
381
- send_failsafe("build_item in exception_data", e)
382
- return
383
- end
384
-
385
- begin
386
- process_item(item)
387
- rescue => e
388
- send_failsafe("error in process_item", e)
389
- return
390
- end
391
-
392
- begin
393
- log_instance_link(item['data'])
394
- rescue => e
395
- send_failsafe("error logging instance link", e)
396
- return
397
- end
398
- end
399
-
400
- ## Payload building functions
401
-
402
- def build_item(level, message, exception, extra)
403
- options = {
404
- :level => level,
405
- :message => message,
406
- :exception => exception,
407
- :extra => extra,
408
- :configuration => configuration,
409
- :logger => logger,
410
- :scope => scope_object,
411
- :notifier => self
412
- }
413
-
414
- item = Item.new(options)
415
- item.build
416
-
417
- item
418
- end
419
-
420
- ## Delivery functions
421
-
422
- def send_item_using_eventmachine(item)
423
- body = item.dump
424
- return unless body
425
-
426
- headers = { 'X-Rollbar-Access-Token' => item['access_token'] }
427
- req = EventMachine::HttpRequest.new(configuration.endpoint).post(:body => body, :head => headers)
428
-
429
- req.callback do
430
- if req.response_header.status == 200
431
- log_info '[Rollbar] Success'
432
- else
433
- log_warning "[Rollbar] Got unexpected status code from Rollbar.io api: #{req.response_header.status}"
434
- log_info "[Rollbar] Response: #{req.response}"
435
- end
436
- end
437
-
438
- req.errback do
439
- log_warning "[Rollbar] Call to API failed, status code: #{req.response_header.status}"
440
- log_info "[Rollbar] Error's response: #{req.response}"
441
- end
442
- end
443
-
444
- def send_item(item)
445
- log_info '[Rollbar] Sending item'
446
-
447
- if configuration.use_eventmachine
448
- send_item_using_eventmachine(item)
449
- return
450
- end
451
-
452
- body = item.dump
453
- return unless body
454
-
455
- uri = URI.parse(configuration.endpoint)
456
-
457
- handle_response(do_post(uri, body, item['access_token']))
458
- end
459
-
460
- def do_post(uri, body, access_token)
461
- http = Net::HTTP.new(uri.host, uri.port)
462
- http.open_timeout = configuration.open_timeout
463
- http.read_timeout = configuration.request_timeout
464
-
465
- if uri.scheme == 'https'
466
- http.use_ssl = true
467
- # This is needed to have 1.8.7 passing tests
468
- http.ca_file = ENV['ROLLBAR_SSL_CERT_FILE'] if ENV.has_key?('ROLLBAR_SSL_CERT_FILE')
469
- http.verify_mode = ssl_verify_mode
470
- end
471
-
472
- request = Net::HTTP::Post.new(uri.request_uri)
473
-
474
- request.body = body
475
- request.add_field('X-Rollbar-Access-Token', access_token)
476
-
477
- handle_net_retries { http.request(request) }
478
- end
479
-
480
- def handle_net_retries
481
- return yield if skip_retries?
482
-
483
- retries = configuration.net_retries - 1
484
-
485
- begin
486
- yield
487
- rescue *LanguageSupport.timeout_exceptions
488
- raise if retries <= 0
489
-
490
- retries -= 1
491
-
492
- retry
493
- end
494
- end
495
-
496
- def skip_retries?
497
- Rollbar::LanguageSupport.ruby_18? || Rollbar::LanguageSupport.ruby_19?
498
- end
499
-
500
- def handle_response(response)
501
- if response.code == '200'
502
- log_info '[Rollbar] Success'
503
- else
504
- log_warning "[Rollbar] Got unexpected status code from Rollbar api: #{response.code}"
505
- log_info "[Rollbar] Response: #{response.body}"
506
- end
507
- end
508
-
509
- def ssl_verify_mode
510
- if configuration.verify_ssl_peer
511
- OpenSSL::SSL::VERIFY_PEER
512
- else
513
- OpenSSL::SSL::VERIFY_NONE
514
- end
515
- end
516
-
517
- def write_item(item)
518
- if configuration.use_async
519
- @file_semaphore.synchronize {
520
- do_write_item(item)
521
- }
522
- else
523
- do_write_item(item)
524
- end
525
- end
526
-
527
- def do_write_item(item)
528
- log_info '[Rollbar] Writing item to file'
529
-
530
- body = item.dump
531
- return unless body
532
-
533
- begin
534
- unless @file
535
- @file = File.open(configuration.filepath, "a")
536
- end
537
-
538
- @file.puts(body)
539
- @file.flush
540
- log_info "[Rollbar] Success"
541
- rescue IOError => e
542
- log_error "[Rollbar] Error opening/writing to file: #{e}"
543
- end
544
- end
545
-
546
- def failsafe_reason(message, exception)
547
- body = ''
548
-
549
- if exception
550
- begin
551
- backtrace = exception.backtrace || []
552
- nearest_frame = backtrace[0]
553
-
554
- exception_info = exception.class.name
555
- # #to_s and #message defaults to class.to_s. Add message only if add valuable info.
556
- exception_info += %Q{: "#{exception.message}"} if exception.message != exception.class.to_s
557
- exception_info += " in #{nearest_frame}" if nearest_frame
558
-
559
- body += "#{exception_info}: #{message}"
560
- rescue
561
- end
562
- else
563
- begin
564
- body += message.to_s
565
- rescue
566
- end
567
- end
568
-
569
- body
570
- end
571
-
572
- def failsafe_body(reason)
573
- "Failsafe from rollbar-gem. #{reason}"
574
- end
575
-
576
- def schedule_item(item)
577
- return unless item
578
-
579
- log_info '[Rollbar] Scheduling item'
580
-
581
- if configuration.use_async
582
- process_async_item(item)
583
- else
584
- process_item(item)
585
- end
586
- end
587
-
588
- def default_async_handler
589
- return Rollbar::Delay::GirlFriday if defined?(GirlFriday)
590
-
591
- Rollbar::Delay::Thread
592
- end
593
-
594
- def process_async_item(item)
595
- configuration.async_handler ||= default_async_handler
596
- configuration.async_handler.call(item.payload)
597
- rescue => e
598
- if configuration.failover_handlers.empty?
599
- log_error '[Rollbar] Async handler failed, and there are no failover handlers configured. See the docs for "failover_handlers"'
600
- return
601
- end
602
-
603
- async_failover(item)
604
- end
605
-
606
- def async_failover(item)
607
- log_warning '[Rollbar] Primary async handler failed. Trying failovers...'
608
-
609
- failover_handlers = configuration.failover_handlers
610
-
611
- failover_handlers.each do |handler|
612
- begin
613
- handler.call(item.payload)
614
- rescue
615
- next unless handler == failover_handlers.last
616
-
617
- log_error "[Rollbar] All failover handlers failed while processing item: #{Rollbar::JSON.dump(item.payload)}"
618
- end
619
- end
620
- end
621
-
622
- ## Logging
623
- %w(debug info warn error).each do |level|
624
- define_method(:"log_#{level}") do |message|
625
- logger.send(level, message)
626
- end
627
- end
628
-
629
- alias_method :log_warning, :log_warn
630
-
631
- def log_instance_link(data)
632
- if data[:uuid]
633
- uuid_url = Util.uuid_rollbar_url(data, configuration)
634
- log_info "[Rollbar] Details: #{uuid_url} (only available if report was successful)"
635
- end
636
- end
637
-
638
- def logger
639
- @logger ||= LoggerProxy.new(configuration.logger)
640
- end
641
- end
25
+ process_item process_from_async_handler scope
26
+ send_failsafe log_info log_debug log_warning
27
+ log_error silenced scope_object with_config).freeze
642
28
 
643
29
  class << self
644
30
  extend Forwardable
@@ -646,43 +32,57 @@ module Rollbar
646
32
  def_delegators :notifier, *PUBLIC_NOTIFIER_METHODS
647
33
 
648
34
  attr_writer :plugins
35
+ attr_writer :root_notifier
649
36
 
650
- # Similar to configure below, but used only internally within the gem
651
- # to configure it without initializing any of the third party hooks
652
- def preconfigure
653
- yield(configuration)
37
+ def notifier
38
+ # Use the global instance @root_notifier so we don't fall
39
+ # in a infinite loop
40
+ Thread.current[:_rollbar_notifier] ||= Notifier.new(@root_notifier)
41
+ end
654
42
 
655
- reset_notifier!
43
+ def notifier=(notifier)
44
+ Thread.current[:_rollbar_notifier] = notifier
656
45
  end
657
46
 
658
- def configure
659
- # if configuration.enabled has not been set yet (is still 'nil'), set to true.
660
- configuration.enabled = true if configuration.enabled.nil?
47
+ # It's the first notifier instantiated in the
48
+ # process. We store it so all the next per-thread
49
+ # notifiers can inherit its configuration
50
+ # The methods Rollbar.configure, Rollbar.reconfigure,
51
+ # Rollbar.preconfigure and Rollbar.unconfigure work
52
+ # on this notifier.
53
+ # Before v2.13.0 these methods worked on the global
54
+ # configuration, so in the practice the behavior is the same,
55
+ # since they work on the root notifier's configuration
56
+ def root_notifier
57
+ @root_notifier ||= notifier
58
+ end
59
+
60
+ def preconfigure(&block)
61
+ root_notifier.preconfigure(&block)
62
+ end
661
63
 
662
- yield(configuration)
64
+ # Configures the root notifier and loads the plugins
65
+ def configure(&block)
66
+ root_notifier.configure(&block)
663
67
 
664
68
  plugins.load!
665
- reset_notifier!
666
69
  end
667
70
 
668
- def reconfigure
669
- @configuration = Configuration.new
670
- @configuration.enabled = true
671
- yield(configuration)
672
-
673
- reset_notifier!
71
+ # Reconfigures the root notifier
72
+ def reconfigure(&block)
73
+ root_notifier.reconfigure(&block)
674
74
  end
675
75
 
76
+ # Unconfigures the root notifier
676
77
  def unconfigure
677
- @configuration = nil
78
+ root_notifier.unconfigure
678
79
  end
679
80
 
81
+ # Returns the configuration for the current notifier.
82
+ # The current notifier is Rollbar.notifier and exists
83
+ # one per thread.
680
84
  def configuration
681
- @configuration ||= Configuration.new
682
- end
683
-
684
- def scope_object
685
- @scope_obejct ||= ::Rollbar::LazyStore.new({})
85
+ notifier.configuration
686
86
  end
687
87
 
688
88
  def safely?
@@ -693,14 +93,6 @@ module Rollbar
693
93
  @plugins ||= Rollbar::Plugins.new
694
94
  end
695
95
 
696
- def notifier
697
- Thread.current[:_rollbar_notifier] ||= Notifier.new(self)
698
- end
699
-
700
- def notifier=(notifier)
701
- Thread.current[:_rollbar_notifier] = notifier
702
- end
703
-
704
96
  def last_report
705
97
  Thread.current[:_rollbar_last_report]
706
98
  end
@@ -709,8 +101,24 @@ module Rollbar
709
101
  Thread.current[:_rollbar_last_report] = report
710
102
  end
711
103
 
104
+ # Resets the scope for the current thread notifier. The notifier
105
+ # reference is kept so we reuse the notifier.
106
+ # This is a change from version 2.13.0. Before this version
107
+ # this method clears the notifier.
108
+ #
109
+ # It was used in order to reset the scope and reusing the global
110
+ # configuration Rollbar.configuration. Since now Rollbar.configuration
111
+ # points to the current notifier configuration, we can resue the
112
+ # notifier instance and just reset the scope.
712
113
  def reset_notifier!
114
+ notifier.reset!
115
+ end
116
+
117
+ # Clears the current thread notifier and the root notifier.
118
+ # In the practice this should be used only on the specs
119
+ def clear_notifier!
713
120
  self.notifier = nil
121
+ self.root_notifier = nil
714
122
  end
715
123
 
716
124
  # Create a new Notifier instance using the received options and
@@ -721,16 +129,18 @@ module Rollbar
721
129
  # @example
722
130
  #
723
131
  # new_scope = { job_type: 'scheduled' }
724
- # Rollbar.scoped(new_scope) do
132
+ # new_config = { use_async: false }
133
+ #
134
+ # Rollbar.scoped(new_scope, new_config) do
725
135
  # begin
726
136
  # # do stuff
727
137
  # rescue => e
728
- # Rollbar.log(e)
138
+ # Rollbar.error(e)
729
139
  # end
730
140
  # end
731
- def scoped(options = {})
141
+ def scoped(options = {}, config_overrides = {})
732
142
  old_notifier = notifier
733
- self.notifier = old_notifier.scope(options)
143
+ self.notifier = old_notifier.scope(options, config_overrides)
734
144
 
735
145
  result = yield
736
146
  result
@@ -738,6 +148,12 @@ module Rollbar
738
148
  self.notifier = old_notifier
739
149
  end
740
150
 
151
+ # Create a new Notifier instance with a new configuration
152
+ # using the current one but merging the passed options.
153
+ def with_config(overrides, &block)
154
+ scoped(nil, overrides, &block)
155
+ end
156
+
741
157
  def scope!(options = {})
742
158
  notifier.scope!(options)
743
159
  end