airbrake-ruby 4.13.3-java → 5.0.0-java

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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/lib/airbrake-ruby.rb +23 -32
  3. data/lib/airbrake-ruby/async_sender.rb +1 -1
  4. data/lib/airbrake-ruby/backtrace.rb +6 -5
  5. data/lib/airbrake-ruby/config.rb +37 -13
  6. data/lib/airbrake-ruby/config/processor.rb +84 -0
  7. data/lib/airbrake-ruby/config/validator.rb +6 -0
  8. data/lib/airbrake-ruby/file_cache.rb +1 -1
  9. data/lib/airbrake-ruby/filter_chain.rb +16 -1
  10. data/lib/airbrake-ruby/filters/dependency_filter.rb +1 -0
  11. data/lib/airbrake-ruby/filters/gem_root_filter.rb +1 -0
  12. data/lib/airbrake-ruby/filters/git_last_checkout_filter.rb +3 -3
  13. data/lib/airbrake-ruby/filters/git_repository_filter.rb +3 -0
  14. data/lib/airbrake-ruby/filters/git_revision_filter.rb +2 -0
  15. data/lib/airbrake-ruby/filters/{keys_whitelist.rb → keys_allowlist.rb} +3 -3
  16. data/lib/airbrake-ruby/filters/{keys_blacklist.rb → keys_blocklist.rb} +3 -3
  17. data/lib/airbrake-ruby/filters/keys_filter.rb +26 -18
  18. data/lib/airbrake-ruby/filters/root_directory_filter.rb +1 -0
  19. data/lib/airbrake-ruby/filters/sql_filter.rb +4 -4
  20. data/lib/airbrake-ruby/filters/system_exit_filter.rb +1 -0
  21. data/lib/airbrake-ruby/filters/thread_filter.rb +2 -0
  22. data/lib/airbrake-ruby/ignorable.rb +1 -0
  23. data/lib/airbrake-ruby/notice.rb +1 -8
  24. data/lib/airbrake-ruby/notice_notifier.rb +7 -0
  25. data/lib/airbrake-ruby/performance_breakdown.rb +1 -6
  26. data/lib/airbrake-ruby/performance_notifier.rb +2 -15
  27. data/lib/airbrake-ruby/promise.rb +1 -0
  28. data/lib/airbrake-ruby/query.rb +1 -6
  29. data/lib/airbrake-ruby/queue.rb +1 -8
  30. data/lib/airbrake-ruby/remote_settings.rb +145 -0
  31. data/lib/airbrake-ruby/remote_settings/settings_data.rb +120 -0
  32. data/lib/airbrake-ruby/request.rb +1 -8
  33. data/lib/airbrake-ruby/stat.rb +1 -12
  34. data/lib/airbrake-ruby/sync_sender.rb +3 -2
  35. data/lib/airbrake-ruby/tdigest.rb +2 -0
  36. data/lib/airbrake-ruby/thread_pool.rb +2 -0
  37. data/lib/airbrake-ruby/truncator.rb +8 -2
  38. data/lib/airbrake-ruby/version.rb +11 -1
  39. data/spec/airbrake_spec.rb +71 -36
  40. data/spec/backtrace_spec.rb +26 -26
  41. data/spec/code_hunk_spec.rb +2 -2
  42. data/spec/config/processor_spec.rb +209 -0
  43. data/spec/config/validator_spec.rb +18 -1
  44. data/spec/config_spec.rb +13 -6
  45. data/spec/filter_chain_spec.rb +27 -0
  46. data/spec/filters/gem_root_filter_spec.rb +4 -4
  47. data/spec/filters/git_last_checkout_filter_spec.rb +20 -3
  48. data/spec/filters/{keys_whitelist_spec.rb → keys_allowlist_spec.rb} +11 -10
  49. data/spec/filters/{keys_blacklist_spec.rb → keys_blocklist_spec.rb} +20 -10
  50. data/spec/filters/root_directory_filter_spec.rb +4 -4
  51. data/spec/filters/sql_filter_spec.rb +5 -5
  52. data/spec/notice_notifier/options_spec.rb +6 -6
  53. data/spec/notice_notifier_spec.rb +2 -2
  54. data/spec/notice_spec.rb +1 -1
  55. data/spec/performance_breakdown_spec.rb +0 -12
  56. data/spec/performance_notifier_spec.rb +2 -27
  57. data/spec/query_spec.rb +1 -11
  58. data/spec/queue_spec.rb +1 -13
  59. data/spec/remote_settings/settings_data_spec.rb +365 -0
  60. data/spec/remote_settings_spec.rb +230 -0
  61. data/spec/request_spec.rb +1 -13
  62. data/spec/spec_helper.rb +4 -4
  63. data/spec/stat_spec.rb +0 -9
  64. data/spec/sync_sender_spec.rb +3 -1
  65. data/spec/thread_pool_spec.rb +25 -5
  66. metadata +22 -14
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6a2b4edf2ff6ca87fdc92fd067485afa4d01692c33e29c3ea60b0a93d2363f60
4
- data.tar.gz: f2d238127b26e3fdfdc1b7848f847760993a87d15182ec7266e42d7db753609c
3
+ metadata.gz: 81bd0ad6d05fae2f485b64570694fdae739e1d74554d191c8ec9fce8cec780f1
4
+ data.tar.gz: 80464931a1362c4d845ffee737ed7aa1e46693136023b1f08006c49de98e62eb
5
5
  SHA512:
6
- metadata.gz: fcbb40c30a2b67182992498f0582d36210de1798454403145cbf029d1778c7fe34a2426e6caf96678cafa6427bba9fc51cd6cbd96b1bd0c517d0800b07ef387c
7
- data.tar.gz: 845c5c487af401362663273c85d56fb924578332a227ba534ced253d954af17ebdade9c6d5346a8e9640fcb4c8583ad068c8c43d0bc85fa7ec41298aff07c978
6
+ metadata.gz: 2d1d85b685495abedbbf518144cd5dccf4cf7c4e4e23f8457d5c5adf2a1a5220329a5e25bb4ca2f6e49f151d617a5e00b30abfff8e7ca69e7d13325efa0f00e1
7
+ data.tar.gz: 23968940c6f1dfb500be5ab479c1d524cdc9f80e40808b4ff08d7f4b03c97baad603d97504c58a5300ddfa7ec9b1a4b5bd44a24a6a4a15776a82778ef2a0c324
@@ -12,6 +12,9 @@ require 'airbrake-ruby/mergeable'
12
12
  require 'airbrake-ruby/grouppable'
13
13
  require 'airbrake-ruby/config'
14
14
  require 'airbrake-ruby/config/validator'
15
+ require 'airbrake-ruby/config/processor'
16
+ require 'airbrake-ruby/remote_settings/settings_data'
17
+ require 'airbrake-ruby/remote_settings'
15
18
  require 'airbrake-ruby/promise'
16
19
  require 'airbrake-ruby/thread_pool'
17
20
  require 'airbrake-ruby/sync_sender'
@@ -24,8 +27,8 @@ require 'airbrake-ruby/notice'
24
27
  require 'airbrake-ruby/backtrace'
25
28
  require 'airbrake-ruby/truncator'
26
29
  require 'airbrake-ruby/filters/keys_filter'
27
- require 'airbrake-ruby/filters/keys_whitelist'
28
- require 'airbrake-ruby/filters/keys_blacklist'
30
+ require 'airbrake-ruby/filters/keys_allowlist'
31
+ require 'airbrake-ruby/filters/keys_blocklist'
29
32
  require 'airbrake-ruby/filters/gem_root_filter'
30
33
  require 'airbrake-ruby/filters/system_exit_filter'
31
34
  require 'airbrake-ruby/filters/root_directory_filter'
@@ -117,7 +120,15 @@ module Airbrake
117
120
  def configure
118
121
  yield config = Airbrake::Config.instance
119
122
  Airbrake::Loggable.instance = config.logger
120
- process_config_options(config)
123
+
124
+ config_processor = Airbrake::Config::Processor.new(config)
125
+
126
+ config_processor.process_blocklist(notice_notifier)
127
+ config_processor.process_allowlist(notice_notifier)
128
+
129
+ @remote_settings ||= config_processor.process_remote_configuration
130
+
131
+ config_processor.add_filters(notice_notifier)
121
132
  end
122
133
 
123
134
  # @since v4.2.3
@@ -260,8 +271,8 @@ module Airbrake
260
271
  # Airbrake.close
261
272
  # Airbrake.notify('App crashed!') #=> raises Airbrake::Error
262
273
  #
263
- # @return [void]
264
- # rubocop:disable Style/GuardClause, Style/IfUnlessModifier
274
+ # @return [nil]
275
+ # rubocop:disable Style/IfUnlessModifier, Metrics/CyclomaticComplexity
265
276
  def close
266
277
  if defined?(@notice_notifier) && @notice_notifier
267
278
  @notice_notifier.close
@@ -270,8 +281,14 @@ module Airbrake
270
281
  if defined?(@performance_notifier) && @performance_notifier
271
282
  @performance_notifier.close
272
283
  end
284
+
285
+ if defined?(@remote_settings) && @remote_settings
286
+ @remote_settings.stop_polling
287
+ end
288
+
289
+ nil
273
290
  end
274
- # rubocop:enable Style/GuardClause, Style/IfUnlessModifier
291
+ # rubocop:enable Style/IfUnlessModifier, Metrics/CyclomaticComplexity
275
292
 
276
293
  # Pings the Airbrake Deploy API endpoint about the occurred deploy.
277
294
  #
@@ -567,32 +584,6 @@ module Airbrake
567
584
  self.notice_notifier = NoticeNotifier.new
568
585
  self.deploy_notifier = DeployNotifier.new
569
586
  end
570
-
571
- private
572
-
573
- def process_config_options(config)
574
- if config.blacklist_keys.any?
575
- blacklist = Airbrake::Filters::KeysBlacklist.new(config.blacklist_keys)
576
- notice_notifier.add_filter(blacklist)
577
- end
578
-
579
- if config.whitelist_keys.any?
580
- whitelist = Airbrake::Filters::KeysWhitelist.new(config.whitelist_keys)
581
- notice_notifier.add_filter(whitelist)
582
- end
583
-
584
- return if configured?
585
- return unless config.root_directory
586
-
587
- [
588
- Airbrake::Filters::RootDirectoryFilter,
589
- Airbrake::Filters::GitRevisionFilter,
590
- Airbrake::Filters::GitRepositoryFilter,
591
- Airbrake::Filters::GitLastCheckoutFilter,
592
- ].each do |filter|
593
- notice_notifier.add_filter(filter.new(config.root_directory))
594
- end
595
- end
596
587
  end
597
588
  end
598
589
  # rubocop:enable Metrics/ModuleLength
@@ -16,7 +16,7 @@ module Airbrake
16
16
  #
17
17
  # @param [Hash] payload Whatever needs to be sent
18
18
  # @return [Airbrake::Promise]
19
- def send(payload, promise, endpoint = @config.endpoint)
19
+ def send(payload, promise, endpoint = @config.error_endpoint)
20
20
  unless thread_pool << [payload, promise, endpoint]
21
21
  return promise.reject(
22
22
  "AsyncSender has reached its capacity of #{@config.queue_size}",
@@ -22,7 +22,7 @@ module Airbrake
22
22
  (?<line>\d+) # Matches '43'
23
23
  :in\s
24
24
  `(?<function>.*)' # Matches "`block (3 levels) in <top (required)>'"
25
- \z}x
25
+ \z}x.freeze
26
26
 
27
27
  # @return [Regexp] the pattern that matches JRuby Java stack frames, such
28
28
  # as org.jruby.ast.NewlineNode.interpret(NewlineNode.java:105)
@@ -39,7 +39,7 @@ module Airbrake
39
39
  :?
40
40
  (?<line>\d+)? # Matches '105'
41
41
  \)
42
- \z}x
42
+ \z}x.freeze
43
43
 
44
44
  # @return [Regexp] the pattern that tries to assume what a generic stack
45
45
  # frame might look like, when exception's backtrace is set manually.
@@ -53,7 +53,7 @@ module Airbrake
53
53
  |
54
54
  :in\s(?<function>.+) # Matches ":in func"
55
55
  )? # ... or nothing
56
- \z}x
56
+ \z}x.freeze
57
57
 
58
58
  # @return [Regexp] the pattern that matches exceptions from PL/SQL such as
59
59
  # ORA-06512: at "STORE.LI_LICENSES_PACK", line 1945
@@ -67,7 +67,7 @@ module Airbrake
67
67
  |
68
68
  #{GENERIC}
69
69
  )
70
- \z/x
70
+ \z/x.freeze
71
71
 
72
72
  # @return [Regexp] the pattern that matches CoffeeScript backtraces
73
73
  # usually coming from Rails & ExecJS
@@ -82,7 +82,7 @@ module Airbrake
82
82
  # Matches the Ruby part of the backtrace
83
83
  #{RUBY}
84
84
  )
85
- \z/x
85
+ \z/x.freeze
86
86
  end
87
87
 
88
88
  # @return [Integer] how many first frames should include code hunks
@@ -95,6 +95,7 @@ module Airbrake
95
95
  # @return [Array<Hash{Symbol=>String,Integer}>] the parsed backtrace
96
96
  def self.parse(exception)
97
97
  return [] if exception.backtrace.nil? || exception.backtrace.none?
98
+
98
99
  parse_backtrace(exception)
99
100
  end
100
101
 
@@ -46,6 +46,17 @@ module Airbrake
46
46
  # @api public
47
47
  attr_accessor :host
48
48
 
49
+ # @since v5.0.0
50
+ alias error_host host
51
+ # @since v5.0.0
52
+ alias error_host= host=
53
+
54
+ # @return [String] the host, which provides the API endpoint to which
55
+ # APM data should be sent
56
+ # @api public
57
+ # @since v5.0.0
58
+ attr_accessor :apm_host
59
+
49
60
  # @return [String, Pathname] the working directory of your project
50
61
  # @api public
51
62
  attr_accessor :root_directory
@@ -68,14 +79,14 @@ module Airbrake
68
79
  # @return [Array<String, Symbol, Regexp>] the keys, which should be
69
80
  # filtered
70
81
  # @api public
71
- # @since v1.2.0
72
- attr_accessor :blacklist_keys
82
+ # @since v4.15.0
83
+ attr_accessor :allowlist_keys
73
84
 
74
- # @return [Array<String, Symbol, Regexp>] the keys, which shouldn't be
85
+ # @return [Array<String, Symbol, Regexp>] the keys, which should be
75
86
  # filtered
76
87
  # @api public
77
- # @since v1.2.0
78
- attr_accessor :whitelist_keys
88
+ # @since v4.15.0
89
+ attr_accessor :blocklist_keys
79
90
 
80
91
  # @return [Boolean] true if the library should attach code hunks to each
81
92
  # frame in a backtrace, false otherwise
@@ -107,6 +118,16 @@ module Airbrake
107
118
  # @since v4.12.0
108
119
  attr_accessor :job_stats
109
120
 
121
+ # @return [Boolean] true if the library should send error reports to
122
+ # Airbrake, false otherwise
123
+ # @api public
124
+ # @since 5.0.0
125
+ attr_accessor :error_notifications
126
+
127
+ # @return [String] the host such as which should be used for fetching remote
128
+ # configuration options (example: "https://bucket-name.s3.amazonaws.com")
129
+ attr_accessor :remote_config_host
130
+
110
131
  class << self
111
132
  # @return [Config]
112
133
  attr_writer :instance
@@ -128,14 +149,16 @@ module Airbrake
128
149
  self.logger = ::Logger.new(File::NULL).tap { |l| l.level = Logger::WARN }
129
150
  self.project_id = user_config[:project_id]
130
151
  self.project_key = user_config[:project_key]
131
- self.host = 'https://api.airbrake.io'
152
+ self.error_host = 'https://api.airbrake.io'
153
+ self.apm_host = 'https://api.airbrake.io'
154
+ self.remote_config_host = 'https://v1-production-notifier-configs.s3.amazonaws.com'
132
155
 
133
156
  self.ignore_environments = []
134
157
 
135
158
  self.timeout = user_config[:timeout]
136
159
 
137
- self.blacklist_keys = []
138
- self.whitelist_keys = []
160
+ self.blocklist_keys = []
161
+ self.allowlist_keys = []
139
162
 
140
163
  self.root_directory = File.realpath(
141
164
  (defined?(Bundler) && Bundler.root) ||
@@ -147,19 +170,20 @@ module Airbrake
147
170
  self.performance_stats_flush_period = 15
148
171
  self.query_stats = true
149
172
  self.job_stats = true
173
+ self.error_notifications = true
150
174
 
151
175
  merge(user_config)
152
176
  end
153
177
  # rubocop:enable Metrics/AbcSize
154
178
 
155
- # The full URL to the Airbrake Notice API. Based on the +:host+ option.
179
+ # The full URL to the Airbrake Notice API. Based on the +:error_host+ option.
156
180
  # @return [URI] the endpoint address
157
- def endpoint
158
- @endpoint ||=
181
+ def error_endpoint
182
+ @error_endpoint ||=
159
183
  begin
160
- self.host = ('https://' << host) if host !~ %r{\Ahttps?://}
184
+ self.error_host = ('https://' << error_host) if error_host !~ %r{\Ahttps?://}
161
185
  api = "api/v3/projects/#{project_id}/notices"
162
- URI.join(host, api)
186
+ URI.join(error_host, api)
163
187
  end
164
188
  end
165
189
 
@@ -0,0 +1,84 @@
1
+ module Airbrake
2
+ class Config
3
+ # Processor is a helper class, which is responsible for setting default
4
+ # config values, default notifier filters and remote configuration changes.
5
+ #
6
+ # @since 5.0.0
7
+ # @api private
8
+ class Processor
9
+ # @param [Airbrake::Config] config
10
+ # @return [Airbrake::Config::Processor]
11
+ def self.process(config)
12
+ new(config).process
13
+ end
14
+
15
+ # @param [Airbrake::Config] config
16
+ def initialize(config)
17
+ @config = config
18
+ @blocklist_keys = @config.blocklist_keys
19
+ @allowlist_keys = @config.allowlist_keys
20
+ @project_id = @config.project_id
21
+ end
22
+
23
+ # @param [Airbrake::NoticeNotifier] notifier
24
+ # @return [void]
25
+ def process_blocklist(notifier)
26
+ return if @blocklist_keys.none?
27
+
28
+ blocklist = Airbrake::Filters::KeysBlocklist.new(@blocklist_keys)
29
+ notifier.add_filter(blocklist)
30
+ end
31
+
32
+ # @param [Airbrake::NoticeNotifier] notifier
33
+ # @return [void]
34
+ def process_allowlist(notifier)
35
+ return if @allowlist_keys.none?
36
+
37
+ allowlist = Airbrake::Filters::KeysAllowlist.new(@allowlist_keys)
38
+ notifier.add_filter(allowlist)
39
+ end
40
+
41
+ # @return [Airbrake::RemoteSettings]
42
+ def process_remote_configuration
43
+ return unless @project_id
44
+
45
+ RemoteSettings.poll(
46
+ @project_id,
47
+ @config.remote_config_host,
48
+ &method(:poll_callback)
49
+ )
50
+ end
51
+
52
+ # @param [Airbrake::NoticeNotifier] notifier
53
+ # @return [void]
54
+ def add_filters(notifier)
55
+ return unless @config.root_directory
56
+
57
+ [
58
+ Airbrake::Filters::RootDirectoryFilter,
59
+ Airbrake::Filters::GitRevisionFilter,
60
+ Airbrake::Filters::GitRepositoryFilter,
61
+ Airbrake::Filters::GitLastCheckoutFilter,
62
+ ].each do |filter|
63
+ next if notifier.has_filter?(filter)
64
+
65
+ notifier.add_filter(filter.new(@config.root_directory))
66
+ end
67
+ end
68
+
69
+ # @param [Airbrake::RemoteSettings::SettingsData] data
70
+ # @return [void]
71
+ def poll_callback(data)
72
+ @config.logger.debug(
73
+ "#{LOG_LABEL} applying remote settings: #{data.to_h}",
74
+ )
75
+
76
+ @config.error_host = data.error_host if data.error_host
77
+ @config.apm_host = data.apm_host if data.apm_host
78
+
79
+ @config.error_notifications = data.error_notifications?
80
+ @config.performance_stats = data.performance_stats?
81
+ end
82
+ end
83
+ end
84
+ end
@@ -44,6 +44,10 @@ module Airbrake
44
44
  def check_notify_ability(config)
45
45
  promise = Airbrake::Promise.new
46
46
 
47
+ unless config.error_notifications
48
+ return promise.reject('error notifications are disabled')
49
+ end
50
+
47
51
  if ignored_environment?(config)
48
52
  return promise.reject(
49
53
  "current environment '#{config.environment}' is ignored",
@@ -57,12 +61,14 @@ module Airbrake
57
61
 
58
62
  def valid_project_id?(config)
59
63
  return true if config.project_id.to_i > 0
64
+
60
65
  false
61
66
  end
62
67
 
63
68
  def valid_project_key?(config)
64
69
  return false unless config.project_key.is_a?(String)
65
70
  return false if config.project_key.empty?
71
+
66
72
  true
67
73
  end
68
74
 
@@ -40,7 +40,7 @@ module Airbrake
40
40
  data.empty?
41
41
  end
42
42
 
43
- # @since ?.?.?
43
+ # @since 4.7.0
44
44
  # @return [void]
45
45
  def self.reset
46
46
  @data = {}
@@ -70,13 +70,14 @@ module Airbrake
70
70
  def refine(notice)
71
71
  @filters.each do |filter|
72
72
  break if notice.ignored?
73
+
73
74
  filter.call(notice)
74
75
  end
75
76
  end
76
77
 
77
78
  # @return [String] customized inspect to lessen the amount of clutter
78
79
  def inspect
79
- @filters.map(&:class).to_s
80
+ filter_classes.to_s
80
81
  end
81
82
 
82
83
  # @return [String] {#inspect} for PrettyPrint
@@ -91,5 +92,19 @@ module Airbrake
91
92
  end
92
93
  q.text(']')
93
94
  end
95
+
96
+ # @param [Class] filter_class
97
+ # @return [Boolean] true if the current chain has an instance of the given
98
+ # class, false otherwise
99
+ # @since v4.14.0
100
+ def includes?(filter_class)
101
+ filter_classes.include?(filter_class)
102
+ end
103
+
104
+ private
105
+
106
+ def filter_classes
107
+ @filters.map(&:class)
108
+ end
94
109
  end
95
110
  end
@@ -24,6 +24,7 @@ module Airbrake
24
24
 
25
25
  def git_version(spec)
26
26
  return unless spec.respond_to?(:git_version) || spec.git_version
27
+
27
28
  spec.git_version.to_s
28
29
  end
29
30
  end
@@ -23,6 +23,7 @@ module Airbrake
23
23
  # If the frame is unparseable, then 'file' is nil, thus nothing to
24
24
  # filter (all frame's data is in 'function' instead).
25
25
  next unless (file = frame[:file])
26
+
26
27
  frame[:file] = file.sub(/\A#{gem_path}/, GEM_ROOT_LABEL)
27
28
  end
28
29
  end
@@ -27,6 +27,7 @@ module Airbrake
27
27
  @git_path = File.join(root_directory, '.git')
28
28
  @weight = 116
29
29
  @last_checkout = nil
30
+ @deploy_username = ENV['AIRBRAKE_DEPLOY_USERNAME']
30
31
  end
31
32
 
32
33
  # @macro call_filter
@@ -40,12 +41,12 @@ module Airbrake
40
41
 
41
42
  return unless File.exist?(@git_path)
42
43
  return unless (checkout = last_checkout)
44
+
43
45
  notice[:context][:lastCheckout] = checkout
44
46
  end
45
47
 
46
48
  private
47
49
 
48
- # rubocop:disable Metrics/AbcSize
49
50
  def last_checkout
50
51
  return unless (line = last_checkout_line)
51
52
 
@@ -59,13 +60,12 @@ module Airbrake
59
60
 
60
61
  author = parts[2..-4]
61
62
  @last_checkout = {
62
- username: author[0..1].join(' '),
63
+ username: @deploy_username || author[0..1].join(' '),
63
64
  email: parts[-3][1..-2],
64
65
  revision: parts[1],
65
66
  time: timestamp(parts[-2].to_i),
66
67
  }
67
68
  end
68
- # rubocop:enable Metrics/AbcSize
69
69
 
70
70
  def last_checkout_line
71
71
  head_path = File.join(@git_path, 'logs', 'HEAD')