airbrake-ruby 5.0.1 → 5.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/lib/airbrake-ruby.rb +4 -2
  3. data/lib/airbrake-ruby/async_sender.rb +3 -1
  4. data/lib/airbrake-ruby/config.rb +15 -6
  5. data/lib/airbrake-ruby/config/processor.rb +7 -20
  6. data/lib/airbrake-ruby/context.rb +51 -0
  7. data/lib/airbrake-ruby/file_cache.rb +1 -1
  8. data/lib/airbrake-ruby/filter_chain.rb +2 -0
  9. data/lib/airbrake-ruby/filters/context_filter.rb +4 -5
  10. data/lib/airbrake-ruby/filters/exception_attributes_filter.rb +1 -1
  11. data/lib/airbrake-ruby/filters/git_last_checkout_filter.rb +1 -1
  12. data/lib/airbrake-ruby/filters/git_revision_filter.rb +1 -1
  13. data/lib/airbrake-ruby/filters/keys_filter.rb +2 -2
  14. data/lib/airbrake-ruby/filters/sql_filter.rb +2 -2
  15. data/lib/airbrake-ruby/filters/thread_filter.rb +2 -3
  16. data/lib/airbrake-ruby/grouppable.rb +1 -1
  17. data/lib/airbrake-ruby/ignorable.rb +0 -2
  18. data/lib/airbrake-ruby/mergeable.rb +1 -1
  19. data/lib/airbrake-ruby/notice_notifier.rb +3 -4
  20. data/lib/airbrake-ruby/performance_notifier.rb +1 -2
  21. data/lib/airbrake-ruby/remote_settings.rb +10 -50
  22. data/lib/airbrake-ruby/remote_settings/callback.rb +44 -0
  23. data/lib/airbrake-ruby/remote_settings/settings_data.rb +3 -8
  24. data/lib/airbrake-ruby/tdigest.rb +7 -6
  25. data/lib/airbrake-ruby/thread_pool.rb +5 -3
  26. data/lib/airbrake-ruby/timed_trace.rb +1 -3
  27. data/lib/airbrake-ruby/version.rb +2 -2
  28. data/spec/airbrake_spec.rb +139 -76
  29. data/spec/async_sender_spec.rb +10 -8
  30. data/spec/backtrace_spec.rb +13 -10
  31. data/spec/benchmark_spec.rb +5 -3
  32. data/spec/code_hunk_spec.rb +24 -15
  33. data/spec/config/processor_spec.rb +29 -87
  34. data/spec/config/validator_spec.rb +5 -2
  35. data/spec/config_spec.rb +26 -17
  36. data/spec/context_spec.rb +54 -0
  37. data/spec/deploy_notifier_spec.rb +6 -4
  38. data/spec/file_cache_spec.rb +1 -0
  39. data/spec/filter_chain_spec.rb +29 -24
  40. data/spec/filters/context_filter_spec.rb +14 -5
  41. data/spec/filters/dependency_filter_spec.rb +3 -1
  42. data/spec/filters/exception_attributes_filter_spec.rb +5 -3
  43. data/spec/filters/gem_root_filter_spec.rb +5 -2
  44. data/spec/filters/git_last_checkout_filter_spec.rb +10 -12
  45. data/spec/filters/git_repository_filter.rb +9 -9
  46. data/spec/filters/git_revision_filter_spec.rb +19 -19
  47. data/spec/filters/keys_allowlist_spec.rb +25 -16
  48. data/spec/filters/keys_blocklist_spec.rb +25 -18
  49. data/spec/filters/root_directory_filter_spec.rb +3 -3
  50. data/spec/filters/sql_filter_spec.rb +26 -26
  51. data/spec/filters/system_exit_filter_spec.rb +4 -2
  52. data/spec/filters/thread_filter_spec.rb +16 -14
  53. data/spec/loggable_spec.rb +2 -2
  54. data/spec/monotonic_time_spec.rb +8 -6
  55. data/spec/nested_exception_spec.rb +46 -46
  56. data/spec/notice_notifier/options_spec.rb +23 -13
  57. data/spec/notice_notifier_spec.rb +52 -47
  58. data/spec/notice_spec.rb +6 -2
  59. data/spec/performance_notifier_spec.rb +67 -60
  60. data/spec/promise_spec.rb +38 -32
  61. data/spec/remote_settings/callback_spec.rb +162 -0
  62. data/spec/remote_settings/settings_data_spec.rb +23 -53
  63. data/spec/remote_settings_spec.rb +42 -75
  64. data/spec/response_spec.rb +34 -12
  65. data/spec/stashable_spec.rb +5 -5
  66. data/spec/stat_spec.rb +7 -5
  67. data/spec/sync_sender_spec.rb +49 -16
  68. data/spec/tdigest_spec.rb +61 -56
  69. data/spec/thread_pool_spec.rb +65 -55
  70. data/spec/time_truncate_spec.rb +4 -2
  71. data/spec/timed_trace_spec.rb +32 -30
  72. data/spec/truncator_spec.rb +72 -43
  73. metadata +53 -47
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 773b982037081f5d6dfb045378a35b2854a251d9e238cd58dd0b1216c75e86c5
4
- data.tar.gz: a7177673edea3b8f05055683972b918bf43255ad68fc21688317ec5ed56dbb7b
3
+ metadata.gz: 6a073eaf249f96805546ce1d9cc45f45ca3a3a09c36bb2c5cbe8b4f145c03fca
4
+ data.tar.gz: 714f8424b206e2842237c5417833118d2960e1eb0a1c4ff7d16ad75467b9bfc1
5
5
  SHA512:
6
- metadata.gz: 6e377bdd85f7aa912cc9341834f9413ec5a89b71bbe2acf561118be97a911baef6c7cc210fa2430e286d135ce829ca7009110180c5938ac7017a403d7be239de
7
- data.tar.gz: b9e6812ed5d2734c7fd3ffd83b14e5d366594366c5460244e43d13375ede211c56d4e1a3b4c79b613de0d480493d9950a833670bb2f59161f1d0db051936b0a1
6
+ metadata.gz: 605bcaf8e438ae77a781d2ae6bc03b4525003e5faa0572cb007aa4f6ae07413518b77eea1cbf947599f1151eff27e35a1ee47e9864c83768ee409795d748f116
7
+ data.tar.gz: af89bef16ed1f0f64b1e65484d680cdd5204905d5981c7a1310d19c9d875cf4ce702b06d51b4c508985b5e1cc7d0a87b33c7cc8a002d673bad11dffa4fc0f248
data/lib/airbrake-ruby.rb CHANGED
@@ -13,6 +13,7 @@ require 'airbrake-ruby/grouppable'
13
13
  require 'airbrake-ruby/config'
14
14
  require 'airbrake-ruby/config/validator'
15
15
  require 'airbrake-ruby/config/processor'
16
+ require 'airbrake-ruby/remote_settings/callback'
16
17
  require 'airbrake-ruby/remote_settings/settings_data'
17
18
  require 'airbrake-ruby/remote_settings'
18
19
  require 'airbrake-ruby/promise'
@@ -57,6 +58,7 @@ require 'airbrake-ruby/benchmark'
57
58
  require 'airbrake-ruby/monotonic_time'
58
59
  require 'airbrake-ruby/timed_trace'
59
60
  require 'airbrake-ruby/queue'
61
+ require 'airbrake-ruby/context'
60
62
 
61
63
  # Airbrake is a thin wrapper around instances of the notifier classes (such as
62
64
  # notice, performance & deploy notifiers). It creates a way to access them via a
@@ -272,7 +274,7 @@ module Airbrake
272
274
  # Airbrake.notify('App crashed!') #=> raises Airbrake::Error
273
275
  #
274
276
  # @return [nil]
275
- # rubocop:disable Style/IfUnlessModifier, Metrics/CyclomaticComplexity
277
+ # rubocop:disable Style/IfUnlessModifier
276
278
  def close
277
279
  if defined?(@notice_notifier) && @notice_notifier
278
280
  @notice_notifier.close
@@ -288,7 +290,7 @@ module Airbrake
288
290
 
289
291
  nil
290
292
  end
291
- # rubocop:enable Style/IfUnlessModifier, Metrics/CyclomaticComplexity
293
+ # rubocop:enable Style/IfUnlessModifier
292
294
 
293
295
  # Pings the Airbrake Deploy API endpoint about the occurred deploy.
294
296
  #
@@ -7,9 +7,10 @@ module Airbrake
7
7
  class AsyncSender
8
8
  include Loggable
9
9
 
10
- def initialize(method = :post)
10
+ def initialize(method = :post, name = 'async-sender')
11
11
  @config = Airbrake::Config.instance
12
12
  @method = method
13
+ @name = name
13
14
  end
14
15
 
15
16
  # Asynchronously sends a notice to Airbrake.
@@ -47,6 +48,7 @@ module Airbrake
47
48
  @thread_pool ||= begin
48
49
  sender = SyncSender.new(@method)
49
50
  ThreadPool.new(
51
+ name: @name,
50
52
  worker_size: @config.workers,
51
53
  queue_size: @config.queue_size,
52
54
  block: proc { |args| sender.send(*args) },
@@ -121,13 +121,21 @@ module Airbrake
121
121
  # @return [Boolean] true if the library should send error reports to
122
122
  # Airbrake, false otherwise
123
123
  # @api public
124
- # @since 5.0.0
124
+ # @since v5.0.0
125
125
  attr_accessor :error_notifications
126
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")
127
+ # @return [String] the host which should be used for fetching remote
128
+ # configuration options
129
+ # @api public
130
+ # @since v5.0.0
129
131
  attr_accessor :remote_config_host
130
132
 
133
+ # @return [String] true if notifier should periodically fetch remote
134
+ # configuration, false otherwise
135
+ # @api public
136
+ # @since v5.2.0
137
+ attr_accessor :remote_config
138
+
131
139
  class << self
132
140
  # @return [Config]
133
141
  attr_writer :instance
@@ -140,7 +148,7 @@ module Airbrake
140
148
 
141
149
  # @param [Hash{Symbol=>Object}] user_config the hash to be used to build the
142
150
  # config
143
- # rubocop:disable Metrics/AbcSize
151
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
144
152
  def initialize(user_config = {})
145
153
  self.proxy = {}
146
154
  self.queue_size = 100
@@ -151,7 +159,7 @@ module Airbrake
151
159
  self.project_key = user_config[:project_key]
152
160
  self.error_host = 'https://api.airbrake.io'
153
161
  self.apm_host = 'https://api.airbrake.io'
154
- self.remote_config_host = 'https://v1-production-notifier-configs.s3.amazonaws.com'
162
+ self.remote_config_host = 'https://notifier-configs.airbrake.io'
155
163
 
156
164
  self.ignore_environments = []
157
165
 
@@ -171,10 +179,11 @@ module Airbrake
171
179
  self.query_stats = true
172
180
  self.job_stats = true
173
181
  self.error_notifications = true
182
+ self.remote_config = true
174
183
 
175
184
  merge(user_config)
176
185
  end
177
- # rubocop:enable Metrics/AbcSize
186
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
178
187
 
179
188
  # The full URL to the Airbrake Notice API. Based on the +:error_host+ option.
180
189
  # @return [URI] the endpoint address
@@ -3,7 +3,7 @@ module Airbrake
3
3
  # Processor is a helper class, which is responsible for setting default
4
4
  # config values, default notifier filters and remote configuration changes.
5
5
  #
6
- # @since 5.0.0
6
+ # @since v5.0.0
7
7
  # @api private
8
8
  class Processor
9
9
  # @param [Airbrake::Config] config
@@ -18,6 +18,7 @@ module Airbrake
18
18
  @blocklist_keys = @config.blocklist_keys
19
19
  @allowlist_keys = @config.allowlist_keys
20
20
  @project_id = @config.project_id
21
+ @poll_callback = Airbrake::RemoteSettings::Callback.new(config)
21
22
  end
22
23
 
23
24
  # @param [Airbrake::NoticeNotifier] notifier
@@ -40,13 +41,13 @@ module Airbrake
40
41
 
41
42
  # @return [Airbrake::RemoteSettings]
42
43
  def process_remote_configuration
44
+ return unless @config.remote_config
43
45
  return unless @project_id
46
+ return if @config.environment == 'test'
44
47
 
45
- RemoteSettings.poll(
46
- @project_id,
47
- @config.remote_config_host,
48
- &method(:poll_callback)
49
- )
48
+ RemoteSettings.poll(@project_id, @config.remote_config_host) do |data|
49
+ @poll_callback.call(data)
50
+ end
50
51
  end
51
52
 
52
53
  # @param [Airbrake::NoticeNotifier] notifier
@@ -65,20 +66,6 @@ module Airbrake
65
66
  notifier.add_filter(filter.new(@config.root_directory))
66
67
  end
67
68
  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
69
  end
83
70
  end
84
71
  end
@@ -0,0 +1,51 @@
1
+ module Airbrake
2
+ # Represents a thread-safe Airbrake context object, which carries arbitrary
3
+ # information added via {Airbrake.merge_context} calls.
4
+ #
5
+ # @example
6
+ # Airbrake::Context.current.merge!(foo: 'bar')
7
+ #
8
+ # @api private
9
+ # @since v5.2.1
10
+ class Context
11
+ # Returns current, thread-local, context.
12
+ # @return [self]
13
+ def self.current
14
+ Thread.current[:airbrake_context] ||= new
15
+ end
16
+
17
+ def initialize
18
+ @mutex = Mutex.new
19
+ @context = {}
20
+ end
21
+
22
+ # Merges the given context with the current one.
23
+ #
24
+ # @param [Hash{Object=>Object}] other
25
+ # @return [void]
26
+ def merge!(other)
27
+ @mutex.synchronize do
28
+ @context.merge!(other)
29
+ end
30
+ end
31
+
32
+ # @return [Hash] duplicated Hash context
33
+ def to_h
34
+ @mutex.synchronize do
35
+ @context.dup
36
+ end
37
+ end
38
+
39
+ # @return [Hash] clears (resets) the current context
40
+ def clear
41
+ @mutex.synchronize do
42
+ @context.clear
43
+ end
44
+ end
45
+
46
+ # @return [Boolean] checks whether the context has any data
47
+ def empty?
48
+ @context.empty?
49
+ end
50
+ end
51
+ end
@@ -40,7 +40,7 @@ module Airbrake
40
40
  data.empty?
41
41
  end
42
42
 
43
- # @since 4.7.0
43
+ # @since v4.7.0
44
44
  # @return [void]
45
45
  def self.reset
46
46
  @data = {}
@@ -57,7 +57,9 @@ module Airbrake
57
57
  # @return [void]
58
58
  # @since v3.1.0
59
59
  def delete_filter(filter_class)
60
+ # rubocop:disable Style/ClassEqualityComparison
60
61
  index = @filters.index { |f| f.class.name == filter_class.name }
62
+ # rubocop:enable Style/ClassEqualityComparison
61
63
  @filters.delete_at(index) if index
62
64
  end
63
65
 
@@ -9,8 +9,7 @@ module Airbrake
9
9
  # @return [Integer]
10
10
  attr_reader :weight
11
11
 
12
- def initialize(context)
13
- @context = context
12
+ def initialize
14
13
  @weight = 119
15
14
  @mutex = Mutex.new
16
15
  end
@@ -18,10 +17,10 @@ module Airbrake
18
17
  # @macro call_filter
19
18
  def call(notice)
20
19
  @mutex.synchronize do
21
- return if @context.empty?
20
+ return if Airbrake::Context.current.empty?
22
21
 
23
- notice[:params][:airbrake_context] = @context.dup
24
- @context.clear
22
+ notice[:params][:airbrake_context] = Airbrake::Context.current.to_h
23
+ Airbrake::Context.current.clear
25
24
  end
26
25
  end
27
26
  end
@@ -13,7 +13,7 @@ module Airbrake
13
13
  end
14
14
 
15
15
  # @macro call_filter
16
- def call(notice)
16
+ def call(notice) # rubocop:disable Metrics/AbcSize
17
17
  exception = notice.stash[:exception]
18
18
  return unless exception.respond_to?(:to_airbrake)
19
19
 
@@ -50,7 +50,7 @@ module Airbrake
50
50
  def last_checkout
51
51
  return unless (line = last_checkout_line)
52
52
 
53
- parts = line.chomp.split("\t").first.split(' ')
53
+ parts = line.chomp.split("\t").first.split
54
54
  if parts.size < MIN_HEAD_COLS
55
55
  logger.error(
56
56
  "#{LOG_LABEL} Airbrake::#{self.class.name}: can't parse line: #{line}",
@@ -57,7 +57,7 @@ module Airbrake
57
57
 
58
58
  File.readlines(packed_refs_path).each do |line|
59
59
  next if %w[# ^].include?(line[0])
60
- next unless (parts = line.split(' ')).size == 2
60
+ next unless (parts = line.split).size == 2
61
61
  return parts.first if parts.last == head
62
62
  end
63
63
 
@@ -82,7 +82,7 @@ module Airbrake
82
82
 
83
83
  private
84
84
 
85
- def filter_hash(hash)
85
+ def filter_hash(hash) # rubocop:disable Metrics/AbcSize
86
86
  return hash unless hash.is_a?(Hash)
87
87
 
88
88
  hash_copy = hash.dup
@@ -103,7 +103,7 @@ module Airbrake
103
103
  end
104
104
 
105
105
  def filter_url_params(url)
106
- url.query = Hash[URI.decode_www_form(url.query)].map do |key, val|
106
+ url.query = URI.decode_www_form(url.query).to_h.map do |key, val|
107
107
  should_filter?(key) ? "#{key}=[Filtered]" : "#{key}=#{val}"
108
108
  end.join('&')
109
109
 
@@ -27,13 +27,13 @@ module Airbrake
27
27
  single_quotes: /'(?:[^']|'')*?(?:\\'.*|'(?!'))/,
28
28
  double_quotes: /"(?:[^"]|"")*?(?:\\".*|"(?!"))/,
29
29
  dollar_quotes: /(\$(?!\d)[^$]*?\$).*?(?:\1|$)/,
30
- uuids: /\{?(?:[0-9a-fA-F]\-*){32}\}?/,
30
+ uuids: /\{?(?:[0-9a-fA-F]-*){32}\}?/,
31
31
  numeric_literals: /\b-?(?:[0-9]+\.)?[0-9]+([eE][+-]?[0-9]+)?\b/,
32
32
  boolean_literals: /\b(?:true|false|null)\b/i,
33
33
  hexadecimal_literals: /0x[0-9a-fA-F]+/,
34
34
  comments: /(?:#|--).*?(?=\r|\n|$)/i,
35
35
  multi_line_comments: %r{/\*(?:[^/]|/[^*])*?(?:\*/|/\*.*)},
36
- oracle_quoted_strings: /q'\[.*?(?:\]'|$)|q'\{.*?(?:\}'|$)|q'\<.*?(?:\>'|$)|q'\(.*?(?:\)'|$)/,
36
+ oracle_quoted_strings: /q'\[.*?(?:\]'|$)|q'\{.*?(?:\}'|$)|q'<.*?(?:>'|$)|q'\(.*?(?:\)'|$)/,
37
37
  # rubocop:enable Layout/LineLength
38
38
  }.freeze
39
39
 
@@ -41,8 +41,7 @@ module Airbrake
41
41
  thread_info[:fiber_variables] = vars
42
42
  end
43
43
 
44
- # Present in Ruby 2.3+.
45
- if th.respond_to?(:name) && (name = th.name)
44
+ if (name = th.name)
46
45
  thread_info[:name] = name
47
46
  end
48
47
 
@@ -84,7 +83,7 @@ module Airbrake
84
83
  when Array
85
84
  value = value.map { |elem| sanitize_value(elem) }
86
85
  when Hash
87
- Hash[value.map { |k, v| [k, sanitize_value(v)] }]
86
+ value.transform_values { |v| sanitize_value(v) }
88
87
  else
89
88
  value.to_s
90
89
  end
@@ -2,7 +2,7 @@ module Airbrake
2
2
  # Grouppable adds the `#groups` method, so that we don't need to define it in
3
3
  # all of performance models every time we add a model without groups.
4
4
  #
5
- # @since 4.9.0
5
+ # @since v4.9.0
6
6
  # @api private
7
7
  module Grouppable
8
8
  def groups
@@ -18,11 +18,9 @@ module Airbrake
18
18
  # Checks whether the instance was ignored.
19
19
  # @return [Boolean]
20
20
  # @see #ignore!
21
- # rubocop:disable Style/DoubleNegation
22
21
  def ignored?
23
22
  !!ignored
24
23
  end
25
- # rubocop:enable Style/DoubleNegation
26
24
 
27
25
  # Ignores an instance. Ignored instances must never reach the Airbrake
28
26
  # dashboard.
@@ -2,7 +2,7 @@ module Airbrake
2
2
  # Mergeable adds the `#merge` method, so that we don't need to define it in
3
3
  # all of performance models every time we add a model.
4
4
  #
5
- # @since 4.9.0
5
+ # @since v4.9.0
6
6
  # @api private
7
7
  module Mergeable
8
8
  def merge(_other)
@@ -20,14 +20,13 @@ module Airbrake
20
20
 
21
21
  def initialize
22
22
  @config = Airbrake::Config.instance
23
- @context = {}
24
23
  @filter_chain = FilterChain.new
25
- @async_sender = AsyncSender.new
24
+ @async_sender = AsyncSender.new(:post, self.class.name)
26
25
  @sync_sender = SyncSender.new
27
26
 
28
27
  DEFAULT_FILTERS.each { |filter| add_filter(filter.new) }
29
28
 
30
- add_filter(Airbrake::Filters::ContextFilter.new(@context))
29
+ add_filter(Airbrake::Filters::ContextFilter.new)
31
30
  add_filter(Airbrake::Filters::ExceptionAttributesFilter.new)
32
31
  end
33
32
 
@@ -79,7 +78,7 @@ module Airbrake
79
78
 
80
79
  # @see Airbrake.merge_context
81
80
  def merge_context(context)
82
- @context.merge!(context)
81
+ Airbrake::Context.current.merge!(context)
83
82
  end
84
83
 
85
84
  # @return [Boolean]
@@ -12,7 +12,7 @@ module Airbrake
12
12
  def initialize
13
13
  @config = Airbrake::Config.instance
14
14
  @flush_period = Airbrake::Config.instance.performance_stats_flush_period
15
- @async_sender = AsyncSender.new(:put)
15
+ @async_sender = AsyncSender.new(:put, self.class.name)
16
16
  @sync_sender = SyncSender.new(:put)
17
17
  @schedule_flush = nil
18
18
  @filter_chain = FilterChain.new
@@ -51,7 +51,6 @@ module Airbrake
51
51
  @payload.synchronize do
52
52
  @schedule_flush.kill if @schedule_flush
53
53
  @async_sender.close
54
- logger.debug("#{LOG_LABEL} performance notifier closed")
55
54
  end
56
55
  end
57
56
 
@@ -8,22 +8,11 @@ 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 5.0.0
11
+ # @since v5.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',
25
- ).freeze
26
-
27
16
  # @return [Hash{Symbol=>String}] metadata to be attached to every GET
28
17
  # request
29
18
  QUERY_PARAMS = URI.encode_www_form(
@@ -33,6 +22,9 @@ module Airbrake
33
22
  language: "#{RUBY_ENGINE}/#{RUBY_VERSION}".freeze,
34
23
  ).freeze
35
24
 
25
+ # @return [String]
26
+ HTTP_OK = '200'.freeze
27
+
36
28
  # Polls remote config of the given project.
37
29
  #
38
30
  # @param [Integer] project_id
@@ -54,18 +46,11 @@ module Airbrake
54
46
  @poll = nil
55
47
  end
56
48
 
57
- # Polls remote config of the given project in background. Loads local config
58
- # first (if exists).
49
+ # Polls remote config of the given project in background.
59
50
  #
60
51
  # @return [self]
61
52
  def poll
62
53
  @poll ||= Thread.new do
63
- begin
64
- load_config
65
- rescue StandardError => ex
66
- logger.error("#{LOG_LABEL} config loading failed: #{ex}")
67
- end
68
-
69
54
  @block.call(@data)
70
55
 
71
56
  loop do
@@ -77,17 +62,11 @@ module Airbrake
77
62
  self
78
63
  end
79
64
 
80
- # Stops the background poller thread. Dumps current config to disk.
65
+ # Stops the background poller thread.
81
66
  #
82
67
  # @return [void]
83
68
  def stop_polling
84
69
  @poll.kill if @poll
85
-
86
- begin
87
- dump_config
88
- rescue StandardError => ex
89
- logger.error("#{LOG_LABEL} config dumping failed: #{ex}")
90
- end
91
70
  end
92
71
 
93
72
  private
@@ -95,22 +74,20 @@ module Airbrake
95
74
  def fetch_config
96
75
  response = nil
97
76
  begin
98
- response = Net::HTTP.get(build_config_uri)
77
+ response = Net::HTTP.get_response(build_config_uri)
99
78
  rescue StandardError => ex
100
79
  logger.error(ex)
101
80
  return {}
102
81
  end
103
82
 
104
- # AWS S3 API returns XML when request is not valid. In this case we just
105
- # print the returned body and exit the method.
106
- if response.start_with?('<?xml ')
107
- logger.error(response)
83
+ unless response.code == HTTP_OK
84
+ logger.error(response.body)
108
85
  return {}
109
86
  end
110
87
 
111
88
  json = nil
112
89
  begin
113
- json = JSON.parse(response)
90
+ json = JSON.parse(response.body)
114
91
  rescue JSON::ParserError => ex
115
92
  logger.error(ex)
116
93
  return {}
@@ -124,22 +101,5 @@ module Airbrake
124
101
  uri.query = QUERY_PARAMS
125
102
  uri
126
103
  end
127
-
128
- def load_config
129
- config_dir = File.dirname(CONFIG_DUMP_PATH)
130
- Dir.mkdir(config_dir) unless File.directory?(config_dir)
131
-
132
- return unless File.exist?(CONFIG_DUMP_PATH)
133
-
134
- config = File.read(CONFIG_DUMP_PATH)
135
- @data.merge!(JSON.parse(config))
136
- end
137
-
138
- def dump_config
139
- config_dir = File.dirname(CONFIG_DUMP_PATH)
140
- Dir.mkdir(config_dir) unless File.directory?(config_dir)
141
-
142
- File.write(CONFIG_DUMP_PATH, JSON.dump(@data.to_h))
143
- end
144
104
  end
145
105
  end