airbrake-ruby 5.2.0-java → 6.0.2-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 (72) hide show
  1. checksums.yaml +4 -4
  2. data/lib/airbrake-ruby/async_sender.rb +3 -1
  3. data/lib/airbrake-ruby/config.rb +3 -3
  4. data/lib/airbrake-ruby/context.rb +51 -0
  5. data/lib/airbrake-ruby/filter_chain.rb +2 -0
  6. data/lib/airbrake-ruby/filters/context_filter.rb +4 -5
  7. data/lib/airbrake-ruby/filters/exception_attributes_filter.rb +1 -1
  8. data/lib/airbrake-ruby/filters/git_last_checkout_filter.rb +2 -2
  9. data/lib/airbrake-ruby/filters/git_repository_filter.rb +1 -1
  10. data/lib/airbrake-ruby/filters/git_revision_filter.rb +1 -1
  11. data/lib/airbrake-ruby/filters/keys_filter.rb +2 -2
  12. data/lib/airbrake-ruby/filters/sql_filter.rb +8 -8
  13. data/lib/airbrake-ruby/filters/thread_filter.rb +1 -1
  14. data/lib/airbrake-ruby/ignorable.rb +0 -2
  15. data/lib/airbrake-ruby/monotonic_time.rb +1 -1
  16. data/lib/airbrake-ruby/notice_notifier.rb +3 -4
  17. data/lib/airbrake-ruby/performance_notifier.rb +39 -40
  18. data/lib/airbrake-ruby/remote_settings/settings_data.rb +1 -1
  19. data/lib/airbrake-ruby/remote_settings.rb +26 -3
  20. data/lib/airbrake-ruby/stat.rb +1 -1
  21. data/lib/airbrake-ruby/tdigest.rb +10 -9
  22. data/lib/airbrake-ruby/thread_pool.rb +8 -6
  23. data/lib/airbrake-ruby/time_truncate.rb +2 -2
  24. data/lib/airbrake-ruby/timed_trace.rb +1 -3
  25. data/lib/airbrake-ruby/version.rb +1 -1
  26. data/lib/airbrake-ruby.rb +24 -23
  27. data/spec/airbrake_spec.rb +139 -76
  28. data/spec/async_sender_spec.rb +10 -8
  29. data/spec/backtrace_spec.rb +13 -10
  30. data/spec/benchmark_spec.rb +5 -3
  31. data/spec/code_hunk_spec.rb +24 -15
  32. data/spec/config/processor_spec.rb +12 -4
  33. data/spec/config/validator_spec.rb +5 -2
  34. data/spec/config_spec.rb +28 -20
  35. data/spec/context_spec.rb +54 -0
  36. data/spec/deploy_notifier_spec.rb +6 -4
  37. data/spec/file_cache_spec.rb +1 -0
  38. data/spec/filter_chain_spec.rb +29 -24
  39. data/spec/filters/context_filter_spec.rb +14 -5
  40. data/spec/filters/dependency_filter_spec.rb +3 -1
  41. data/spec/filters/exception_attributes_filter_spec.rb +5 -3
  42. data/spec/filters/gem_root_filter_spec.rb +5 -2
  43. data/spec/filters/git_last_checkout_filter_spec.rb +10 -12
  44. data/spec/filters/git_repository_filter.rb +9 -9
  45. data/spec/filters/git_revision_filter_spec.rb +20 -20
  46. data/spec/filters/keys_allowlist_spec.rb +25 -16
  47. data/spec/filters/keys_blocklist_spec.rb +25 -18
  48. data/spec/filters/root_directory_filter_spec.rb +3 -3
  49. data/spec/filters/sql_filter_spec.rb +26 -26
  50. data/spec/filters/system_exit_filter_spec.rb +4 -2
  51. data/spec/filters/thread_filter_spec.rb +15 -13
  52. data/spec/loggable_spec.rb +2 -2
  53. data/spec/monotonic_time_spec.rb +8 -6
  54. data/spec/nested_exception_spec.rb +46 -46
  55. data/spec/notice_notifier/options_spec.rb +23 -13
  56. data/spec/notice_notifier_spec.rb +52 -47
  57. data/spec/notice_spec.rb +6 -2
  58. data/spec/performance_notifier_spec.rb +69 -62
  59. data/spec/promise_spec.rb +38 -32
  60. data/spec/remote_settings/callback_spec.rb +27 -8
  61. data/spec/remote_settings/settings_data_spec.rb +4 -4
  62. data/spec/remote_settings_spec.rb +23 -9
  63. data/spec/response_spec.rb +34 -12
  64. data/spec/stashable_spec.rb +5 -5
  65. data/spec/stat_spec.rb +7 -5
  66. data/spec/sync_sender_spec.rb +49 -16
  67. data/spec/tdigest_spec.rb +60 -55
  68. data/spec/thread_pool_spec.rb +65 -56
  69. data/spec/time_truncate_spec.rb +23 -6
  70. data/spec/timed_trace_spec.rb +32 -30
  71. data/spec/truncator_spec.rb +72 -43
  72. metadata +54 -50
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f03821ae0b7ff2d1e1e0b7e1122e2fc8368c4cabd4fac5d623530dd7eafac33c
4
- data.tar.gz: cf2234bd6fc61e439796b0f664163a12fdd4c39c4256a1c469f06dd1f8132de3
3
+ metadata.gz: 99722e48e1e7d0c25b7daa374be62e44eba21cde2029d4994a80110a5f5909fb
4
+ data.tar.gz: 6f5e8d2411eee4e18ff97ef7d89b3c4a1c8ebb3ba5ec14fafe24c25e850672b1
5
5
  SHA512:
6
- metadata.gz: 9980a80ea62fe7602ae7d689e3b35f439370d781b4d4001e4960b18705465fc3bed7f7a49b67eeb7249253c55c58a1ba9b87485979fd9cdb4c320c2a7e1aa67a
7
- data.tar.gz: d13b77d0f959ff3a5326f054b8df67c9402b216038afd25672df8b6803623ac135bb5366739687fc5c234ae2e127d075828f747bb945d9ba4d48f3f354775f17
6
+ metadata.gz: 1700009af941919c7c755536affac726c452e03f0d064a9c69a478cf7757a0b6b1ced42e87bd7f6bbc15a3bbdec538704621dc46fed97b5295a36be8d6bb2cef
7
+ data.tar.gz: f8b22c23d2534b1f4dc12dd1b5d8bf970504b297a61421cda6d496ec2f1143ac9eb031e2c1b033e8d8a24b94b634c2a17ea475f9ef13d482be08a419a54b1d98
@@ -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) },
@@ -248,14 +248,14 @@ module Airbrake
248
248
 
249
249
  # @return [Promise] resolved promise if neither of the performance options
250
250
  # reject it, false otherwise
251
- def check_performance_options(resource)
251
+ def check_performance_options(metric)
252
252
  promise = Airbrake::Promise.new
253
253
 
254
254
  if !performance_stats
255
255
  promise.reject("The Performance Stats feature is disabled")
256
- elsif resource.is_a?(Airbrake::Query) && !query_stats
256
+ elsif metric.is_a?(Airbrake::Query) && !query_stats
257
257
  promise.reject("The Query Stats feature is disabled")
258
- elsif resource.is_a?(Airbrake::Queue) && !job_stats
258
+ elsif metric.is_a?(Airbrake::Queue) && !job_stats
259
259
  promise.reject("The Job Stats feature is disabled")
260
260
  else
261
261
  promise
@@ -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
@@ -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}",
@@ -72,7 +72,7 @@ module Airbrake
72
72
  return unless File.exist?(head_path)
73
73
 
74
74
  last_line = nil
75
- IO.foreach(head_path) do |line|
75
+ File.foreach(head_path) do |line|
76
76
  last_line = line if checkout_line?(line)
77
77
  end
78
78
  last_line
@@ -36,7 +36,7 @@ module Airbrake
36
36
  `cd #{@git_path} && git config --get remote.origin.url`.chomp
37
37
  else
38
38
  "`git remote get-url` is unsupported in git #{@git_version}. " \
39
- 'Consider an upgrade to 2.7+'
39
+ 'Consider an upgrade to 2.7+'
40
40
  end
41
41
 
42
42
  return unless @repository
@@ -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
 
@@ -108,20 +108,20 @@ module Airbrake
108
108
  @regexp = Regexp.union(features)
109
109
  end
110
110
 
111
- # @param [Airbrake::Query] resource
112
- def call(resource)
113
- return unless resource.respond_to?(:query)
111
+ # @param [Airbrake::Query] metric
112
+ def call(metric)
113
+ return unless metric.respond_to?(:query)
114
114
 
115
- query = resource.query
115
+ query = metric.query
116
116
  if IGNORED_QUERIES.any? { |q| q =~ query }
117
- resource.ignore!
117
+ metric.ignore!
118
118
  return
119
119
  end
120
120
 
121
121
  q = query.gsub(@regexp, FILTERED)
122
122
  q.gsub!(POST_FILTER, FILTERED) if q =~ POST_FILTER
123
123
  q = ERROR_MSG if UNMATCHED_PAIR[@dialect] =~ q
124
- resource.query = q
124
+ metric.query = q
125
125
  end
126
126
  end
127
127
  end
@@ -83,7 +83,7 @@ module Airbrake
83
83
  when Array
84
84
  value = value.map { |elem| sanitize_value(elem) }
85
85
  when Hash
86
- Hash[value.map { |k, v| [k, sanitize_value(v)] }]
86
+ value.transform_values { |v| sanitize_value(v) }
87
87
  else
88
88
  value.to_s
89
89
  end
@@ -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.
@@ -39,7 +39,7 @@ module Airbrake
39
39
 
40
40
  def time_in_nanoseconds
41
41
  time = Time.now
42
- time.to_i * (10**9) + time.nsec
42
+ (time.to_i * (10**9)) + time.nsec
43
43
  end
44
44
 
45
45
  end
@@ -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]
@@ -1,6 +1,6 @@
1
1
  module Airbrake
2
- # QueryNotifier aggregates information about SQL queries and periodically sends
3
- # collected data to Airbrake.
2
+ # PerformanceNotifier aggregates performance data and periodically sends it to
3
+ # Airbrake.
4
4
  #
5
5
  # @api public
6
6
  # @since v3.2.0
@@ -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
@@ -21,20 +21,20 @@ module Airbrake
21
21
  @has_payload = @payload.new_cond
22
22
  end
23
23
 
24
- # @param [Hash] resource
24
+ # @param [Hash] metric
25
25
  # @see Airbrake.notify_query
26
26
  # @see Airbrake.notify_request
27
- def notify(resource)
27
+ def notify(metric)
28
28
  @payload.synchronize do
29
- send_resource(resource, sync: false)
29
+ send_metric(metric, sync: false)
30
30
  end
31
31
  end
32
32
 
33
- # @param [Hash] resource
33
+ # @param [Hash] metric
34
34
  # @since v4.10.0
35
35
  # @see Airbrake.notify_queue_sync
36
- def notify_sync(resource)
37
- send_resource(resource, sync: true).value
36
+ def notify_sync(metric)
37
+ send_metric(metric, sync: true).value
38
38
  end
39
39
 
40
40
  # @see Airbrake.add_performance_filter
@@ -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
 
@@ -79,16 +78,16 @@ module Airbrake
79
78
  end
80
79
  end
81
80
 
82
- def send_resource(resource, sync:)
83
- promise = check_configuration(resource)
81
+ def send_metric(metric, sync:)
82
+ promise = check_configuration(metric)
84
83
  return promise if promise.rejected?
85
84
 
86
- @filter_chain.refine(resource)
87
- if resource.ignored?
88
- return Promise.new.reject("#{resource.class} was ignored by a filter")
85
+ @filter_chain.refine(metric)
86
+ if metric.ignored?
87
+ return Promise.new.reject("#{metric.class} was ignored by a filter")
89
88
  end
90
89
 
91
- update_payload(resource)
90
+ update_payload(metric)
92
91
  if sync || @flush_period == 0
93
92
  send(@sync_sender, @payload, promise)
94
93
  else
@@ -97,29 +96,29 @@ module Airbrake
97
96
  end
98
97
  end
99
98
 
100
- def update_payload(resource)
101
- if (total_stat = @payload[resource])
102
- @payload.key(total_stat).merge(resource)
99
+ def update_payload(metric)
100
+ if (total_stat = @payload[metric])
101
+ @payload.key(total_stat).merge(metric)
103
102
  else
104
- @payload[resource] = { total: Airbrake::Stat.new }
103
+ @payload[metric] = { total: Airbrake::Stat.new }
105
104
  end
106
105
 
107
- @payload[resource][:total].increment_ms(resource.timing)
106
+ @payload[metric][:total].increment_ms(metric.timing)
108
107
 
109
- resource.groups.each do |name, ms|
110
- @payload[resource][name] ||= Airbrake::Stat.new
111
- @payload[resource][name].increment_ms(ms)
108
+ metric.groups.each do |name, ms|
109
+ @payload[metric][name] ||= Airbrake::Stat.new
110
+ @payload[metric][name].increment_ms(ms)
112
111
  end
113
112
  end
114
113
 
115
- def check_configuration(resource)
114
+ def check_configuration(metric)
116
115
  promise = @config.check_configuration
117
116
  return promise if promise.rejected?
118
117
 
119
- promise = @config.check_performance_options(resource)
118
+ promise = @config.check_performance_options(metric)
120
119
  return promise if promise.rejected?
121
120
 
122
- if resource.timing && resource.timing == 0
121
+ if metric.timing && metric.timing == 0
123
122
  return Promise.new.reject(':timing cannot be zero')
124
123
  end
125
124
 
@@ -129,47 +128,47 @@ module Airbrake
129
128
  def send(sender, payload, promise)
130
129
  raise "payload cannot be empty. Race?" if payload.none?
131
130
 
132
- with_grouped_payload(payload) do |resource_hash, destination|
131
+ with_grouped_payload(payload) do |metric_hash, destination|
133
132
  url = URI.join(
134
133
  @config.apm_host,
135
134
  "api/v5/projects/#{@config.project_id}/#{destination}",
136
135
  )
137
136
 
138
137
  logger.debug do
139
- "#{LOG_LABEL} #{self.class.name}##{__method__}: #{resource_hash}"
138
+ "#{LOG_LABEL} #{self.class.name}##{__method__}: #{metric_hash}"
140
139
  end
141
- sender.send(resource_hash, promise, url)
140
+ sender.send(metric_hash, promise, url)
142
141
  end
143
142
 
144
143
  promise
145
144
  end
146
145
 
147
146
  def with_grouped_payload(raw_payload)
148
- grouped_payload = raw_payload.group_by do |resource, _stats|
149
- [resource.cargo, resource.destination]
147
+ grouped_payload = raw_payload.group_by do |metric, _stats|
148
+ [metric.cargo, metric.destination]
150
149
  end
151
150
 
152
- grouped_payload.each do |(cargo, destination), resources|
151
+ grouped_payload.each do |(cargo, destination), metrics|
153
152
  payload = {}
154
- payload[cargo] = serialize_resources(resources)
153
+ payload[cargo] = serialize_metrics(metrics)
155
154
  payload['environment'] = @config.environment if @config.environment
156
155
 
157
156
  yield(payload, destination)
158
157
  end
159
158
  end
160
159
 
161
- def serialize_resources(resources)
162
- resources.map do |resource, stats|
163
- resource_hash = resource.to_h.merge!(stats[:total].to_h)
160
+ def serialize_metrics(metrics)
161
+ metrics.map do |metric, stats|
162
+ metric_hash = metric.to_h.merge!(stats[:total].to_h)
164
163
 
165
- if resource.groups.any?
164
+ if metric.groups.any?
166
165
  group_stats = stats.reject { |name, _stat| name == :total }
167
- resource_hash['groups'] = group_stats.merge(group_stats) do |_name, stat|
166
+ metric_hash['groups'] = group_stats.merge(group_stats) do |_name, stat|
168
167
  stat.to_h
169
168
  end
170
169
  end
171
170
 
172
- resource_hash
171
+ metric_hash
173
172
  end
174
173
  end
175
174
  end
@@ -59,7 +59,7 @@ module Airbrake
59
59
  # @return [String] where the config is stored on S3.
60
60
  def config_route(remote_config_host)
61
61
  if @data['config_route'] && !@data['config_route'].empty?
62
- return remote_config_host.chomp('/') + '/' + @data['config_route']
62
+ return "#{remote_config_host.chomp('/')}/#{@data['config_route']}"
63
63
  end
64
64
 
65
65
  format(
@@ -1,7 +1,7 @@
1
1
  module Airbrake
2
2
  # RemoteSettings polls the remote config of the passed project at fixed
3
3
  # intervals. The fetched config is yielded as a callback parameter so that the
4
- # invoker can define read config values.
4
+ # invoker can define read config values. Supports proxies.
5
5
  #
6
6
  # @example Disable/enable error notifications based on the remote value
7
7
  # RemoteSettings.poll do |data|
@@ -43,6 +43,7 @@ module Airbrake
43
43
  @data = SettingsData.new(project_id, {})
44
44
  @host = host
45
45
  @block = block
46
+ @config = Airbrake::Config.instance
46
47
  @poll = nil
47
48
  end
48
49
 
@@ -72,11 +73,16 @@ module Airbrake
72
73
  private
73
74
 
74
75
  def fetch_config
76
+ uri = build_config_uri
77
+ https = build_https(uri)
78
+ req = Net::HTTP::Get.new(uri.request_uri)
75
79
  response = nil
80
+
76
81
  begin
77
- response = Net::HTTP.get_response(build_config_uri)
82
+ response = https.request(req)
78
83
  rescue StandardError => ex
79
- logger.error(ex)
84
+ reason = "#{LOG_LABEL} HTTP error: #{ex}"
85
+ logger.error(reason)
80
86
  return {}
81
87
  end
82
88
 
@@ -101,5 +107,22 @@ module Airbrake
101
107
  uri.query = QUERY_PARAMS
102
108
  uri
103
109
  end
110
+
111
+ def build_https(uri)
112
+ Net::HTTP.new(uri.host, uri.port, *proxy_params).tap do |https|
113
+ https.use_ssl = uri.is_a?(URI::HTTPS)
114
+ if @config.timeout
115
+ https.open_timeout = @config.timeout
116
+ https.read_timeout = @config.timeout
117
+ end
118
+ end
119
+ end
120
+
121
+ def proxy_params
122
+ return unless @config.proxy.key?(:host)
123
+
124
+ [@config.proxy[:host], @config.proxy[:port], @config.proxy[:user],
125
+ @config.proxy[:password]]
126
+ end
104
127
  end
105
128
  end
@@ -4,7 +4,7 @@ module Airbrake
4
4
  # Stat is a data structure that allows accumulating performance data (route
5
5
  # performance, SQL query performance and such). It's powered by TDigests.
6
6
  #
7
- # Usually, one Stat corresponds to one resource (route or query,
7
+ # Usually, one Stat corresponds to one metric (route or query,
8
8
  # etc.). Incrementing a stat means pushing new performance statistics.
9
9
  #
10
10
  # @example
@@ -24,6 +24,7 @@ module Airbrake
24
24
  # @since v3.2.0
25
25
  class Centroid
26
26
  attr_accessor :mean, :n, :cumn, :mean_cumn
27
+
27
28
  def initialize(mean, n, cumn, mean_cumn = nil)
28
29
  @mean = mean
29
30
  @n = n
@@ -130,7 +131,7 @@ module Airbrake
130
131
  points = to_a
131
132
  reset!
132
133
  push_centroid(points.shuffle)
133
- _cumulate(true, true)
134
+ _cumulate(exact: true, force: true)
134
135
  nil
135
136
  end
136
137
 
@@ -175,7 +176,7 @@ module Airbrake
175
176
  elsif item > max[1].mean
176
177
  1.0
177
178
  else
178
- _cumulate(true)
179
+ _cumulate(exact: true)
179
180
  bound = bound_mean(item)
180
181
  lower, upper = bound
181
182
  mean_cumn = lower.mean_cumn
@@ -204,7 +205,7 @@ module Airbrake
204
205
  if size == 0
205
206
  nil
206
207
  else
207
- _cumulate(true)
208
+ _cumulate(exact: true)
208
209
  h = @size * item
209
210
  lower, upper = bound_mean_cumn(h)
210
211
  if lower.nil? && upper.nil?
@@ -255,7 +256,7 @@ module Airbrake
255
256
  array = bytes[start_idx..-1].unpack("G#{size}N#{size}")
256
257
  means, counts = array.each_slice(size).to_a if array.any?
257
258
  when SMALL_ENCODING
258
- means = bytes[start_idx..(start_idx + 4 * size)].unpack("g#{size}")
259
+ means = bytes[start_idx..(start_idx + (4 * size))].unpack("g#{size}")
259
260
  # Decode delta encoding of means
260
261
  x = 0
261
262
  means.map! do |m|
@@ -263,7 +264,7 @@ module Airbrake
263
264
  x = m
264
265
  m
265
266
  end
266
- counts_bytes = bytes[(start_idx + 4 * size)..-1].unpack('C*')
267
+ counts_bytes = bytes[(start_idx + (4 * size))..-1].unpack('C*')
267
268
  counts = []
268
269
  # Decode variable length integer bytes
269
270
  size.times do
@@ -306,7 +307,7 @@ module Airbrake
306
307
  centroid.mean += n * (x - centroid.mean) / (centroid.n + n)
307
308
  end
308
309
 
309
- _cumulate(false, true) if centroid.mean_cumn.nil?
310
+ _cumulate(exact: false, force: true) if centroid.mean_cumn.nil?
310
311
 
311
312
  centroid.cumn += n
312
313
  centroid.mean_cumn += n / 2.0
@@ -314,7 +315,7 @@ module Airbrake
314
315
  end
315
316
 
316
317
  # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
317
- def _cumulate(exact = false, force = false)
318
+ def _cumulate(exact: false, force: false)
318
319
  unless force
319
320
  factor = if @last_cumulate == 0
320
321
  Float::INFINITY
@@ -326,7 +327,7 @@ module Airbrake
326
327
 
327
328
  cumn = 0
328
329
  @centroids.each_value do |c|
329
- c.mean_cumn = cumn + c.n / 2.0
330
+ c.mean_cumn = cumn + (c.n / 2.0)
330
331
  cumn = c.cumn = cumn + c.n
331
332
  end
332
333
  @size = @last_cumulate = cumn
@@ -361,7 +362,7 @@ module Airbrake
361
362
  end
362
363
  end
363
364
 
364
- _cumulate(false)
365
+ _cumulate(exact: false)
365
366
 
366
367
  # If the number of centroids has grown to a very large size,
367
368
  # it may be due to values being inserted in sorted order.