airbrake-ruby 5.0.0.rc.1-java → 5.1.1-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 (60) hide show
  1. checksums.yaml +4 -4
  2. data/lib/airbrake-ruby.rb +1 -0
  3. data/lib/airbrake-ruby/backtrace.rb +6 -5
  4. data/lib/airbrake-ruby/config.rb +9 -35
  5. data/lib/airbrake-ruby/config/processor.rb +7 -17
  6. data/lib/airbrake-ruby/config/validator.rb +2 -0
  7. data/lib/airbrake-ruby/file_cache.rb +1 -1
  8. data/lib/airbrake-ruby/filter_chain.rb +1 -0
  9. data/lib/airbrake-ruby/filters/dependency_filter.rb +1 -0
  10. data/lib/airbrake-ruby/filters/gem_root_filter.rb +1 -0
  11. data/lib/airbrake-ruby/filters/git_last_checkout_filter.rb +1 -2
  12. data/lib/airbrake-ruby/filters/git_repository_filter.rb +3 -0
  13. data/lib/airbrake-ruby/filters/git_revision_filter.rb +2 -0
  14. data/lib/airbrake-ruby/filters/keys_filter.rb +21 -13
  15. data/lib/airbrake-ruby/filters/root_directory_filter.rb +1 -0
  16. data/lib/airbrake-ruby/filters/sql_filter.rb +4 -4
  17. data/lib/airbrake-ruby/filters/system_exit_filter.rb +1 -0
  18. data/lib/airbrake-ruby/filters/thread_filter.rb +2 -0
  19. data/lib/airbrake-ruby/ignorable.rb +1 -0
  20. data/lib/airbrake-ruby/notice.rb +1 -8
  21. data/lib/airbrake-ruby/notice_notifier.rb +1 -0
  22. data/lib/airbrake-ruby/performance_breakdown.rb +1 -6
  23. data/lib/airbrake-ruby/performance_notifier.rb +1 -14
  24. data/lib/airbrake-ruby/promise.rb +1 -0
  25. data/lib/airbrake-ruby/query.rb +1 -6
  26. data/lib/airbrake-ruby/queue.rb +1 -8
  27. data/lib/airbrake-ruby/remote_settings.rb +26 -49
  28. data/lib/airbrake-ruby/remote_settings/callback.rb +44 -0
  29. data/lib/airbrake-ruby/remote_settings/settings_data.rb +14 -14
  30. data/lib/airbrake-ruby/request.rb +1 -8
  31. data/lib/airbrake-ruby/stat.rb +1 -12
  32. data/lib/airbrake-ruby/sync_sender.rb +2 -1
  33. data/lib/airbrake-ruby/tdigest.rb +2 -0
  34. data/lib/airbrake-ruby/thread_pool.rb +1 -0
  35. data/lib/airbrake-ruby/truncator.rb +8 -2
  36. data/lib/airbrake-ruby/version.rb +11 -1
  37. data/spec/backtrace_spec.rb +26 -26
  38. data/spec/code_hunk_spec.rb +2 -2
  39. data/spec/config/processor_spec.rb +13 -102
  40. data/spec/config_spec.rb +4 -29
  41. data/spec/filters/gem_root_filter_spec.rb +4 -4
  42. data/spec/filters/git_last_checkout_filter_spec.rb +1 -1
  43. data/spec/filters/keys_allowlist_spec.rb +1 -0
  44. data/spec/filters/keys_blocklist_spec.rb +10 -0
  45. data/spec/filters/root_directory_filter_spec.rb +4 -4
  46. data/spec/filters/sql_filter_spec.rb +2 -2
  47. data/spec/notice_notifier/options_spec.rb +2 -2
  48. data/spec/notice_notifier_spec.rb +2 -2
  49. data/spec/notice_spec.rb +1 -1
  50. data/spec/performance_breakdown_spec.rb +0 -12
  51. data/spec/performance_notifier_spec.rb +0 -25
  52. data/spec/query_spec.rb +1 -11
  53. data/spec/queue_spec.rb +1 -13
  54. data/spec/remote_settings/callback_spec.rb +143 -0
  55. data/spec/remote_settings/settings_data_spec.rb +34 -13
  56. data/spec/remote_settings_spec.rb +62 -87
  57. data/spec/request_spec.rb +1 -13
  58. data/spec/spec_helper.rb +4 -4
  59. data/spec/stat_spec.rb +0 -9
  60. metadata +11 -8
@@ -16,6 +16,7 @@ module Airbrake
16
16
  # @macro call_filter
17
17
  def call(notice)
18
18
  return if notice[:errors].none? { |error| error[:type] == SYSTEM_EXIT_TYPE }
19
+
19
20
  notice.ignore!
20
21
  end
21
22
  end
@@ -56,6 +56,7 @@ module Airbrake
56
56
  def thread_variables(th)
57
57
  th.thread_variables.map.with_object({}) do |var, h|
58
58
  next if var.to_s.start_with?(IGNORE_PREFIX)
59
+
59
60
  h[var] = sanitize_value(th.thread_variable_get(var))
60
61
  end
61
62
  end
@@ -63,6 +64,7 @@ module Airbrake
63
64
  def fiber_variables(th)
64
65
  th.keys.map.with_object({}) do |key, h|
65
66
  next if key.to_s.start_with?(IGNORE_PREFIX)
67
+
66
68
  h[key] = sanitize_value(th[key])
67
69
  end
68
70
  end
@@ -38,6 +38,7 @@ module Airbrake
38
38
  # @raise [Airbrake::Error] when instance is ignored
39
39
  def raise_if_ignored
40
40
  return unless ignored?
41
+
41
42
  raise Airbrake::Error, "cannot access ignored #{self.class}"
42
43
  end
43
44
  end
@@ -4,19 +4,12 @@ module Airbrake
4
4
  #
5
5
  # @since v1.0.0
6
6
  class Notice
7
- # @return [Hash{Symbol=>String}] the information about the notifier library
8
- NOTIFIER = {
9
- name: 'airbrake-ruby'.freeze,
10
- version: Airbrake::AIRBRAKE_RUBY_VERSION,
11
- url: 'https://github.com/airbrake/airbrake-ruby'.freeze,
12
- }.freeze
13
-
14
7
  # @return [Hash{Symbol=>String,Hash}] the information to be displayed in the
15
8
  # Context tab in the dashboard
16
9
  CONTEXT = {
17
10
  os: RUBY_PLATFORM,
18
11
  language: "#{RUBY_ENGINE}/#{RUBY_VERSION}".freeze,
19
- notifier: NOTIFIER,
12
+ notifier: Airbrake::NOTIFIER_INFO,
20
13
  }.freeze
21
14
 
22
15
  # @return [Integer] the maxium size of the JSON payload in bytes
@@ -135,6 +135,7 @@ module Airbrake
135
135
  # If true, then it's likely an internal library error. In this case return
136
136
  # at least some backtrace to simplify debugging.
137
137
  return caller_copy if clean_bt.empty?
138
+
138
139
  clean_bt
139
140
  end
140
141
  end
@@ -12,16 +12,13 @@ module Airbrake
12
12
  include Stashable
13
13
  include Mergeable
14
14
 
15
- attr_accessor :method, :route, :response_type, :groups, :start_time,
16
- :end_time, :timing, :time
15
+ attr_accessor :method, :route, :response_type, :groups, :timing, :time
17
16
 
18
17
  def initialize(
19
18
  method:,
20
19
  route:,
21
20
  response_type:,
22
21
  groups:,
23
- start_time: Time.now,
24
- end_time: start_time + 1,
25
22
  timing: nil,
26
23
  time: Time.now
27
24
  )
@@ -30,8 +27,6 @@ module Airbrake
30
27
  @route = route
31
28
  @response_type = response_type
32
29
  @groups = groups
33
- @start_time = start_time
34
- @end_time = end_time
35
30
  @timing = timing
36
31
  @time = time
37
32
  end
@@ -104,7 +104,7 @@ module Airbrake
104
104
  @payload[resource] = { total: Airbrake::Stat.new }
105
105
  end
106
106
 
107
- update_total(resource, @payload[resource][:total])
107
+ @payload[resource][:total].increment_ms(resource.timing)
108
108
 
109
109
  resource.groups.each do |name, ms|
110
110
  @payload[resource][name] ||= Airbrake::Stat.new
@@ -112,19 +112,6 @@ module Airbrake
112
112
  end
113
113
  end
114
114
 
115
- def update_total(resource, total)
116
- if resource.timing
117
- total.increment_ms(resource.timing)
118
- else
119
- loc = caller_locations(6..6).first
120
- Kernel.warn(
121
- "#{loc.path}:#{loc.lineno}: warning: :start_time and :end_time are " \
122
- "deprecated. Use :timing & :time instead",
123
- )
124
- total.increment(resource.start_time, resource.end_time)
125
- end
126
- end
127
-
128
115
  def check_configuration(resource)
129
116
  promise = @config.check_configuration
130
117
  return promise if promise.rejected?
@@ -103,6 +103,7 @@ module Airbrake
103
103
  # needed for compatibility but it shouldn't exist in the future
104
104
  def value
105
105
  return @value['ok'] if resolved?
106
+
106
107
  @value
107
108
  end
108
109
  end
@@ -12,8 +12,7 @@ module Airbrake
12
12
  include Mergeable
13
13
  include Grouppable
14
14
 
15
- attr_accessor :method, :route, :query, :func, :file, :line, :start_time,
16
- :end_time, :timing, :time
15
+ attr_accessor :method, :route, :query, :func, :file, :line, :timing, :time
17
16
 
18
17
  def initialize(
19
18
  method:,
@@ -22,8 +21,6 @@ module Airbrake
22
21
  func: nil,
23
22
  file: nil,
24
23
  line: nil,
25
- start_time: Time.now,
26
- end_time: start_time + 1,
27
24
  timing: nil,
28
25
  time: Time.now
29
26
  )
@@ -34,8 +31,6 @@ module Airbrake
34
31
  @func = func
35
32
  @file = file
36
33
  @line = line
37
- @start_time = start_time
38
- @end_time = end_time
39
34
  @timing = timing
40
35
  @time = time
41
36
  end
@@ -4,21 +4,17 @@ module Airbrake
4
4
  # @see Airbrake.notify_queue
5
5
  # @api public
6
6
  # @since v4.9.0
7
- # rubocop:disable Metrics/ParameterLists
8
7
  class Queue
9
8
  include HashKeyable
10
9
  include Ignorable
11
10
  include Stashable
12
11
 
13
- attr_accessor :queue, :error_count, :groups, :start_time, :end_time,
14
- :timing, :time
12
+ attr_accessor :queue, :error_count, :groups, :timing, :time
15
13
 
16
14
  def initialize(
17
15
  queue:,
18
16
  error_count:,
19
17
  groups: {},
20
- start_time: Time.now,
21
- end_time: start_time + 1,
22
18
  timing: nil,
23
19
  time: Time.now
24
20
  )
@@ -26,8 +22,6 @@ module Airbrake
26
22
  @queue = queue
27
23
  @error_count = error_count
28
24
  @groups = groups
29
- @start_time = start_time
30
- @end_time = end_time
31
25
  @timing = timing
32
26
  @time = time
33
27
  end
@@ -68,5 +62,4 @@ module Airbrake
68
62
  ''
69
63
  end
70
64
  end
71
- # rubocop:enable Metrics/ParameterLists
72
65
  end
@@ -8,53 +8,49 @@ module Airbrake
8
8
  # config.error_notifications = data.error_notifications?
9
9
  # end
10
10
  #
11
- # When {#poll} is called, it will try to load remote settings from disk, so
12
- # that it doesn't wait on the result from the API call.
13
- #
14
- # When {#stop_polling} is called, the current config will be dumped to disk.
15
- #
16
- # @since ?.?.?
11
+ # @since 5.0.0
17
12
  # @api private
18
13
  class RemoteSettings
19
14
  include Airbrake::Loggable
20
15
 
21
- # @return [String] the path to the persistent config
22
- CONFIG_DUMP_PATH = File.join(
23
- File.expand_path(__dir__),
24
- '../../config/config.json',
16
+ # @return [Hash{Symbol=>String}] metadata to be attached to every GET
17
+ # request
18
+ QUERY_PARAMS = URI.encode_www_form(
19
+ notifier_name: Airbrake::NOTIFIER_INFO[:name],
20
+ notifier_version: Airbrake::NOTIFIER_INFO[:version],
21
+ os: RUBY_PLATFORM,
22
+ language: "#{RUBY_ENGINE}/#{RUBY_VERSION}".freeze,
25
23
  ).freeze
26
24
 
25
+ # @return [String]
26
+ HTTP_OK = '200'.freeze
27
+
27
28
  # Polls remote config of the given project.
28
29
  #
29
30
  # @param [Integer] project_id
31
+ # @param [String] host
30
32
  # @yield [data]
31
33
  # @yieldparam data [Airbrake::RemoteSettings::SettingsData]
32
34
  # @return [Airbrake::RemoteSettings]
33
- def self.poll(project_id, &block)
34
- new(project_id, &block).poll
35
+ def self.poll(project_id, host, &block)
36
+ new(project_id, host, &block).poll
35
37
  end
36
38
 
37
39
  # @param [Integer] project_id
38
40
  # @yield [data]
39
41
  # @yieldparam data [Airbrake::RemoteSettings::SettingsData]
40
- def initialize(project_id, &block)
42
+ def initialize(project_id, host, &block)
41
43
  @data = SettingsData.new(project_id, {})
44
+ @host = host
42
45
  @block = block
43
46
  @poll = nil
44
47
  end
45
48
 
46
- # Polls remote config of the given project in background. Loads local config
47
- # first (if exists).
49
+ # Polls remote config of the given project in background.
48
50
  #
49
51
  # @return [self]
50
52
  def poll
51
53
  @poll ||= Thread.new do
52
- begin
53
- load_config
54
- rescue StandardError => ex
55
- logger.error("#{LOG_LABEL} config loading failed: #{ex}")
56
- end
57
-
58
54
  @block.call(@data)
59
55
 
60
56
  loop do
@@ -66,17 +62,11 @@ module Airbrake
66
62
  self
67
63
  end
68
64
 
69
- # Stops the background poller thread. Dumps current config to disk.
65
+ # Stops the background poller thread.
70
66
  #
71
67
  # @return [void]
72
68
  def stop_polling
73
69
  @poll.kill if @poll
74
-
75
- begin
76
- dump_config
77
- rescue StandardError => ex
78
- logger.error("#{LOG_LABEL} config dumping failed: #{ex}")
79
- end
80
70
  end
81
71
 
82
72
  private
@@ -84,22 +74,20 @@ module Airbrake
84
74
  def fetch_config
85
75
  response = nil
86
76
  begin
87
- response = Net::HTTP.get(URI(@data.config_route))
77
+ response = Net::HTTP.get_response(build_config_uri)
88
78
  rescue StandardError => ex
89
79
  logger.error(ex)
90
80
  return {}
91
81
  end
92
82
 
93
- # AWS S3 API returns XML when request is not valid. In this case we just
94
- # print the returned body and exit the method.
95
- if response.start_with?('<?xml ')
96
- logger.error(response)
83
+ unless response.code == HTTP_OK
84
+ logger.error(response.body)
97
85
  return {}
98
86
  end
99
87
 
100
88
  json = nil
101
89
  begin
102
- json = JSON.parse(response)
90
+ json = JSON.parse(response.body)
103
91
  rescue JSON::ParserError => ex
104
92
  logger.error(ex)
105
93
  return {}
@@ -108,21 +96,10 @@ module Airbrake
108
96
  json
109
97
  end
110
98
 
111
- def load_config
112
- config_dir = File.dirname(CONFIG_DUMP_PATH)
113
- Dir.mkdir(config_dir) unless File.directory?(config_dir)
114
-
115
- return unless File.exist?(CONFIG_DUMP_PATH)
116
-
117
- config = File.read(CONFIG_DUMP_PATH)
118
- @data.merge!(JSON.parse(config))
119
- end
120
-
121
- def dump_config
122
- config_dir = File.dirname(CONFIG_DUMP_PATH)
123
- Dir.mkdir(config_dir) unless File.directory?(config_dir)
124
-
125
- File.write(CONFIG_DUMP_PATH, JSON.dump(@data.to_h))
99
+ def build_config_uri
100
+ uri = URI(@data.config_route(@host))
101
+ uri.query = QUERY_PARAMS
102
+ uri
126
103
  end
127
104
  end
128
105
  end
@@ -0,0 +1,44 @@
1
+ module Airbrake
2
+ class RemoteSettings
3
+ # Callback is a class that provides a callback for the config poller, which
4
+ # updates the local config according to the data.
5
+ #
6
+ # @api private
7
+ # @since 5.0.2
8
+ class Callback
9
+ def initialize(config)
10
+ @config = config
11
+ @orig_error_notifications = config.error_notifications
12
+ @orig_performance_stats = config.performance_stats
13
+ end
14
+
15
+ # @param [Airbrake::RemoteSettings::SettingsData] data
16
+ # @return [void]
17
+ def call(data)
18
+ @config.logger.debug do
19
+ "#{LOG_LABEL} applying remote settings: #{data.to_h}"
20
+ end
21
+
22
+ @config.error_host = data.error_host if data.error_host
23
+ @config.apm_host = data.apm_host if data.apm_host
24
+
25
+ process_error_notifications(data)
26
+ process_performance_stats(data)
27
+ end
28
+
29
+ private
30
+
31
+ def process_error_notifications(data)
32
+ return unless @orig_error_notifications
33
+
34
+ @config.error_notifications = data.error_notifications?
35
+ end
36
+
37
+ def process_performance_stats(data)
38
+ return unless @orig_performance_stats
39
+
40
+ @config.performance_stats = data.performance_stats?
41
+ end
42
+ end
43
+ end
44
+ end
@@ -11,7 +11,7 @@ module Airbrake
11
11
  #
12
12
  # settings_data.interval #=> 600
13
13
  #
14
- # @since ?.?.?
14
+ # @since 5.0.0
15
15
  # @api private
16
16
  class SettingsData
17
17
  # @return [Integer] how frequently we should poll the config API
@@ -20,16 +20,15 @@ module Airbrake
20
20
  # @return [String] API version of the S3 API to poll
21
21
  API_VER = '2020-06-18'.freeze
22
22
 
23
- # @return [String] what URL to poll
23
+ # @return [String] what path to poll
24
24
  CONFIG_ROUTE_PATTERN =
25
- 'https://%<bucket>s.s3.amazonaws.com/' \
26
- "#{API_VER}/config/%<project_id>s/config.json".freeze
25
+ "%<host>s/#{API_VER}/config/%<project_id>s/config.json".freeze
27
26
 
28
27
  # @return [Hash{Symbol=>String}] the hash of all supported settings where
29
28
  # the value is the name of the setting returned by the API
30
29
  SETTINGS = {
31
- errors: 'errors',
32
- apm: 'apm',
30
+ errors: 'errors'.freeze,
31
+ apm: 'apm'.freeze,
33
32
  }.freeze
34
33
 
35
34
  # @param [Integer] project_id
@@ -56,17 +55,18 @@ module Airbrake
56
55
  @data['poll_sec'] > 0 ? @data['poll_sec'] : DEFAULT_INTERVAL
57
56
  end
58
57
 
58
+ # @param [String] remote_config_host
59
59
  # @return [String] where the config is stored on S3.
60
- def config_route
61
- if !@data.key?('config_route') || !@data['config_route']
62
- return format(
63
- CONFIG_ROUTE_PATTERN,
64
- bucket: 'staging-notifier-configs',
65
- project_id: @project_id,
66
- )
60
+ def config_route(remote_config_host)
61
+ if @data['config_route'] && !@data['config_route'].empty?
62
+ return remote_config_host.chomp('/') + '/' + @data['config_route']
67
63
  end
68
64
 
69
- @data['config_route']
65
+ format(
66
+ CONFIG_ROUTE_PATTERN,
67
+ host: remote_config_host.chomp('/'),
68
+ project_id: @project_id,
69
+ )
70
70
  end
71
71
 
72
72
  # @return [Boolean] whether error notifications are enabled
@@ -4,7 +4,6 @@ module Airbrake
4
4
  # @see Airbrake.notify_request
5
5
  # @api public
6
6
  # @since v3.2.0
7
- # rubocop:disable Metrics/ParameterLists
8
7
  class Request
9
8
  include HashKeyable
10
9
  include Ignorable
@@ -12,15 +11,12 @@ module Airbrake
12
11
  include Mergeable
13
12
  include Grouppable
14
13
 
15
- attr_accessor :method, :route, :status_code, :start_time, :end_time,
16
- :timing, :time
14
+ attr_accessor :method, :route, :status_code, :timing, :time
17
15
 
18
16
  def initialize(
19
17
  method:,
20
18
  route:,
21
19
  status_code:,
22
- start_time: Time.now,
23
- end_time: start_time + 1,
24
20
  timing: nil,
25
21
  time: Time.now
26
22
  )
@@ -28,8 +24,6 @@ module Airbrake
28
24
  @method = method
29
25
  @route = route
30
26
  @status_code = status_code
31
- @start_time = start_time
32
- @end_time = end_time
33
27
  @timing = timing
34
28
  @time = time
35
29
  end
@@ -51,5 +45,4 @@ module Airbrake
51
45
  }.delete_if { |_key, val| val.nil? }
52
46
  end
53
47
  end
54
- # rubocop:enable Metrics/ParameterLists
55
48
  end