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.
- checksums.yaml +4 -4
- data/lib/airbrake-ruby/async_sender.rb +3 -1
- data/lib/airbrake-ruby/config.rb +3 -3
- data/lib/airbrake-ruby/context.rb +51 -0
- data/lib/airbrake-ruby/filter_chain.rb +2 -0
- data/lib/airbrake-ruby/filters/context_filter.rb +4 -5
- data/lib/airbrake-ruby/filters/exception_attributes_filter.rb +1 -1
- data/lib/airbrake-ruby/filters/git_last_checkout_filter.rb +2 -2
- data/lib/airbrake-ruby/filters/git_repository_filter.rb +1 -1
- data/lib/airbrake-ruby/filters/git_revision_filter.rb +1 -1
- data/lib/airbrake-ruby/filters/keys_filter.rb +2 -2
- data/lib/airbrake-ruby/filters/sql_filter.rb +8 -8
- data/lib/airbrake-ruby/filters/thread_filter.rb +1 -1
- data/lib/airbrake-ruby/ignorable.rb +0 -2
- data/lib/airbrake-ruby/monotonic_time.rb +1 -1
- data/lib/airbrake-ruby/notice_notifier.rb +3 -4
- data/lib/airbrake-ruby/performance_notifier.rb +39 -40
- data/lib/airbrake-ruby/remote_settings/settings_data.rb +1 -1
- data/lib/airbrake-ruby/remote_settings.rb +26 -3
- data/lib/airbrake-ruby/stat.rb +1 -1
- data/lib/airbrake-ruby/tdigest.rb +10 -9
- data/lib/airbrake-ruby/thread_pool.rb +8 -6
- data/lib/airbrake-ruby/time_truncate.rb +2 -2
- data/lib/airbrake-ruby/timed_trace.rb +1 -3
- data/lib/airbrake-ruby/version.rb +1 -1
- data/lib/airbrake-ruby.rb +24 -23
- data/spec/airbrake_spec.rb +139 -76
- data/spec/async_sender_spec.rb +10 -8
- data/spec/backtrace_spec.rb +13 -10
- data/spec/benchmark_spec.rb +5 -3
- data/spec/code_hunk_spec.rb +24 -15
- data/spec/config/processor_spec.rb +12 -4
- data/spec/config/validator_spec.rb +5 -2
- data/spec/config_spec.rb +28 -20
- data/spec/context_spec.rb +54 -0
- data/spec/deploy_notifier_spec.rb +6 -4
- data/spec/file_cache_spec.rb +1 -0
- data/spec/filter_chain_spec.rb +29 -24
- data/spec/filters/context_filter_spec.rb +14 -5
- data/spec/filters/dependency_filter_spec.rb +3 -1
- data/spec/filters/exception_attributes_filter_spec.rb +5 -3
- data/spec/filters/gem_root_filter_spec.rb +5 -2
- data/spec/filters/git_last_checkout_filter_spec.rb +10 -12
- data/spec/filters/git_repository_filter.rb +9 -9
- data/spec/filters/git_revision_filter_spec.rb +20 -20
- data/spec/filters/keys_allowlist_spec.rb +25 -16
- data/spec/filters/keys_blocklist_spec.rb +25 -18
- data/spec/filters/root_directory_filter_spec.rb +3 -3
- data/spec/filters/sql_filter_spec.rb +26 -26
- data/spec/filters/system_exit_filter_spec.rb +4 -2
- data/spec/filters/thread_filter_spec.rb +15 -13
- data/spec/loggable_spec.rb +2 -2
- data/spec/monotonic_time_spec.rb +8 -6
- data/spec/nested_exception_spec.rb +46 -46
- data/spec/notice_notifier/options_spec.rb +23 -13
- data/spec/notice_notifier_spec.rb +52 -47
- data/spec/notice_spec.rb +6 -2
- data/spec/performance_notifier_spec.rb +69 -62
- data/spec/promise_spec.rb +38 -32
- data/spec/remote_settings/callback_spec.rb +27 -8
- data/spec/remote_settings/settings_data_spec.rb +4 -4
- data/spec/remote_settings_spec.rb +23 -9
- data/spec/response_spec.rb +34 -12
- data/spec/stashable_spec.rb +5 -5
- data/spec/stat_spec.rb +7 -5
- data/spec/sync_sender_spec.rb +49 -16
- data/spec/tdigest_spec.rb +60 -55
- data/spec/thread_pool_spec.rb +65 -56
- data/spec/time_truncate_spec.rb +23 -6
- data/spec/timed_trace_spec.rb +32 -30
- data/spec/truncator_spec.rb +72 -43
- metadata +54 -50
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 99722e48e1e7d0c25b7daa374be62e44eba21cde2029d4994a80110a5f5909fb
|
4
|
+
data.tar.gz: 6f5e8d2411eee4e18ff97ef7d89b3c4a1c8ebb3ba5ec14fafe24c25e850672b1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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) },
|
data/lib/airbrake-ruby/config.rb
CHANGED
@@ -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(
|
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
|
256
|
+
elsif metric.is_a?(Airbrake::Query) && !query_stats
|
257
257
|
promise.reject("The Query Stats feature is disabled")
|
258
|
-
elsif
|
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
|
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
|
20
|
+
return if Airbrake::Context.current.empty?
|
22
21
|
|
23
|
-
notice[:params][:airbrake_context] =
|
24
|
-
|
22
|
+
notice[:params][:airbrake_context] = Airbrake::Context.current.to_h
|
23
|
+
Airbrake::Context.current.clear
|
25
24
|
end
|
26
25
|
end
|
27
26
|
end
|
@@ -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
|
-
|
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
|
-
|
39
|
+
'Consider an upgrade to 2.7+'
|
40
40
|
end
|
41
41
|
|
42
42
|
return unless @repository
|
@@ -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 =
|
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]
|
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'
|
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]
|
112
|
-
def call(
|
113
|
-
return unless
|
111
|
+
# @param [Airbrake::Query] metric
|
112
|
+
def call(metric)
|
113
|
+
return unless metric.respond_to?(:query)
|
114
114
|
|
115
|
-
query =
|
115
|
+
query = metric.query
|
116
116
|
if IGNORED_QUERIES.any? { |q| q =~ query }
|
117
|
-
|
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
|
-
|
124
|
+
metric.query = q
|
125
125
|
end
|
126
126
|
end
|
127
127
|
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.
|
@@ -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
|
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
|
-
|
81
|
+
Airbrake::Context.current.merge!(context)
|
83
82
|
end
|
84
83
|
|
85
84
|
# @return [Boolean]
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Airbrake
|
2
|
-
#
|
3
|
-
#
|
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]
|
24
|
+
# @param [Hash] metric
|
25
25
|
# @see Airbrake.notify_query
|
26
26
|
# @see Airbrake.notify_request
|
27
|
-
def notify(
|
27
|
+
def notify(metric)
|
28
28
|
@payload.synchronize do
|
29
|
-
|
29
|
+
send_metric(metric, sync: false)
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
-
# @param [Hash]
|
33
|
+
# @param [Hash] metric
|
34
34
|
# @since v4.10.0
|
35
35
|
# @see Airbrake.notify_queue_sync
|
36
|
-
def notify_sync(
|
37
|
-
|
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
|
83
|
-
promise = check_configuration(
|
81
|
+
def send_metric(metric, sync:)
|
82
|
+
promise = check_configuration(metric)
|
84
83
|
return promise if promise.rejected?
|
85
84
|
|
86
|
-
@filter_chain.refine(
|
87
|
-
if
|
88
|
-
return Promise.new.reject("#{
|
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(
|
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(
|
101
|
-
if (total_stat = @payload[
|
102
|
-
@payload.key(total_stat).merge(
|
99
|
+
def update_payload(metric)
|
100
|
+
if (total_stat = @payload[metric])
|
101
|
+
@payload.key(total_stat).merge(metric)
|
103
102
|
else
|
104
|
-
@payload[
|
103
|
+
@payload[metric] = { total: Airbrake::Stat.new }
|
105
104
|
end
|
106
105
|
|
107
|
-
@payload[
|
106
|
+
@payload[metric][:total].increment_ms(metric.timing)
|
108
107
|
|
109
|
-
|
110
|
-
@payload[
|
111
|
-
@payload[
|
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(
|
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(
|
118
|
+
promise = @config.check_performance_options(metric)
|
120
119
|
return promise if promise.rejected?
|
121
120
|
|
122
|
-
if
|
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 |
|
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__}: #{
|
138
|
+
"#{LOG_LABEL} #{self.class.name}##{__method__}: #{metric_hash}"
|
140
139
|
end
|
141
|
-
sender.send(
|
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 |
|
149
|
-
[
|
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),
|
151
|
+
grouped_payload.each do |(cargo, destination), metrics|
|
153
152
|
payload = {}
|
154
|
-
payload[cargo] =
|
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
|
162
|
-
|
163
|
-
|
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
|
164
|
+
if metric.groups.any?
|
166
165
|
group_stats = stats.reject { |name, _stat| name == :total }
|
167
|
-
|
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
|
-
|
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('/')
|
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 =
|
82
|
+
response = https.request(req)
|
78
83
|
rescue StandardError => ex
|
79
|
-
|
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
|
data/lib/airbrake-ruby/stat.rb
CHANGED
@@ -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
|
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
|
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.
|