rollbar 2.12.0 → 2.13.0

Sign up to get free protection for your applications and to get access to all the features.
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