airbrake-ruby 4.15.0 → 6.1.0
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 +4 -2
- data/lib/airbrake-ruby/backtrace.rb +6 -5
- data/lib/airbrake-ruby/config/processor.rb +77 -0
- data/lib/airbrake-ruby/config/validator.rb +6 -0
- data/lib/airbrake-ruby/config.rb +44 -35
- data/lib/airbrake-ruby/context.rb +51 -0
- data/lib/airbrake-ruby/file_cache.rb +1 -1
- data/lib/airbrake-ruby/filter_chain.rb +3 -0
- data/lib/airbrake-ruby/filters/context_filter.rb +4 -5
- data/lib/airbrake-ruby/filters/dependency_filter.rb +1 -0
- data/lib/airbrake-ruby/filters/exception_attributes_filter.rb +1 -1
- data/lib/airbrake-ruby/filters/gem_root_filter.rb +1 -0
- data/lib/airbrake-ruby/filters/git_last_checkout_filter.rb +3 -4
- data/lib/airbrake-ruby/filters/git_repository_filter.rb +11 -2
- data/lib/airbrake-ruby/filters/git_revision_filter.rb +3 -1
- data/lib/airbrake-ruby/filters/keys_filter.rb +23 -15
- data/lib/airbrake-ruby/filters/root_directory_filter.rb +1 -0
- data/lib/airbrake-ruby/filters/sql_filter.rb +11 -11
- data/lib/airbrake-ruby/filters/system_exit_filter.rb +1 -0
- data/lib/airbrake-ruby/filters/thread_filter.rb +4 -3
- data/lib/airbrake-ruby/grouppable.rb +1 -1
- data/lib/airbrake-ruby/ignorable.rb +1 -2
- data/lib/airbrake-ruby/mergeable.rb +1 -1
- data/lib/airbrake-ruby/monotonic_time.rb +1 -1
- data/lib/airbrake-ruby/notice.rb +1 -8
- data/lib/airbrake-ruby/notice_notifier.rb +4 -4
- data/lib/airbrake-ruby/performance_breakdown.rb +1 -6
- data/lib/airbrake-ruby/performance_notifier.rb +40 -54
- data/lib/airbrake-ruby/promise.rb +1 -0
- data/lib/airbrake-ruby/query.rb +1 -6
- data/lib/airbrake-ruby/queue.rb +1 -8
- data/lib/airbrake-ruby/remote_settings/callback.rb +44 -0
- data/lib/airbrake-ruby/remote_settings/settings_data.rb +116 -0
- data/lib/airbrake-ruby/remote_settings.rb +128 -0
- data/lib/airbrake-ruby/request.rb +1 -8
- data/lib/airbrake-ruby/stat.rb +2 -13
- data/lib/airbrake-ruby/sync_sender.rb +3 -2
- data/lib/airbrake-ruby/tdigest.rb +12 -9
- data/lib/airbrake-ruby/thread_pool.rb +9 -6
- data/lib/airbrake-ruby/time_truncate.rb +2 -2
- data/lib/airbrake-ruby/timed_trace.rb +1 -3
- data/lib/airbrake-ruby/truncator.rb +8 -2
- data/lib/airbrake-ruby/version.rb +11 -1
- data/lib/airbrake-ruby.rb +44 -54
- data/spec/airbrake_spec.rb +178 -92
- data/spec/async_sender_spec.rb +10 -8
- data/spec/backtrace_spec.rb +39 -36
- data/spec/benchmark_spec.rb +7 -5
- data/spec/code_hunk_spec.rb +26 -17
- data/spec/config/processor_spec.rb +167 -0
- data/spec/config/validator_spec.rb +23 -3
- data/spec/config_spec.rb +43 -55
- 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 +9 -6
- data/spec/filters/git_last_checkout_filter_spec.rb +10 -12
- data/spec/filters/{git_repository_filter.rb → git_repository_filter_spec.rb} +26 -15
- data/spec/filters/git_revision_filter_spec.rb +20 -20
- data/spec/filters/keys_allowlist_spec.rb +26 -16
- data/spec/filters/keys_blocklist_spec.rb +35 -18
- data/spec/filters/root_directory_filter_spec.rb +7 -7
- data/spec/filters/sql_filter_spec.rb +28 -28
- data/spec/filters/system_exit_filter_spec.rb +4 -2
- data/spec/filters/thread_filter_spec.rb +16 -14
- 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 +25 -15
- data/spec/notice_notifier_spec.rb +54 -49
- data/spec/notice_spec.rb +7 -3
- data/spec/performance_breakdown_spec.rb +0 -12
- data/spec/performance_notifier_spec.rb +69 -87
- data/spec/promise_spec.rb +38 -32
- data/spec/query_spec.rb +1 -11
- data/spec/queue_spec.rb +1 -13
- data/spec/remote_settings/callback_spec.rb +162 -0
- data/spec/remote_settings/settings_data_spec.rb +348 -0
- data/spec/remote_settings_spec.rb +201 -0
- data/spec/request_spec.rb +1 -13
- data/spec/response_spec.rb +34 -12
- data/spec/spec_helper.rb +4 -4
- data/spec/stashable_spec.rb +5 -5
- data/spec/stat_spec.rb +7 -14
- data/spec/sync_sender_spec.rb +52 -17
- data/spec/tdigest_spec.rb +61 -56
- data/spec/thread_pool_spec.rb +67 -58
- data/spec/time_truncate_spec.rb +23 -6
- data/spec/timed_trace_spec.rb +32 -30
- data/spec/truncator_spec.rb +72 -43
- metadata +67 -51
@@ -23,23 +23,23 @@ module Airbrake
|
|
23
23
|
|
24
24
|
# @return [Hash{Symbol=>Regexp}] matchers for certain features of SQL
|
25
25
|
ALL_FEATURES = {
|
26
|
-
# rubocop:disable
|
26
|
+
# rubocop:disable Layout/LineLength
|
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'
|
37
|
-
# rubocop:enable
|
36
|
+
oracle_quoted_strings: /q'\[.*?(?:\]'|$)|q'\{.*?(?:\}'|$)|q'<.*?(?:>'|$)|q'\(.*?(?:\)'|$)/,
|
37
|
+
# rubocop:enable Layout/LineLength
|
38
38
|
}.freeze
|
39
39
|
|
40
40
|
# @return [Regexp] the regexp that is applied after the feature regexps
|
41
41
|
# were used
|
42
|
-
POST_FILTER = /(?<=[values|in ]\().+(?=\))/i
|
42
|
+
POST_FILTER = /(?<=[values|in ]\().+(?=\))/i.freeze
|
43
43
|
|
44
44
|
# @return [Hash{Symbol=>Array<Symbol>}] a set of features that corresponds
|
45
45
|
# to a certain dialect
|
@@ -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
|
@@ -41,8 +41,7 @@ module Airbrake
|
|
41
41
|
thread_info[:fiber_variables] = vars
|
42
42
|
end
|
43
43
|
|
44
|
-
|
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
|
|
@@ -56,6 +55,7 @@ module Airbrake
|
|
56
55
|
def thread_variables(th)
|
57
56
|
th.thread_variables.map.with_object({}) do |var, h|
|
58
57
|
next if var.to_s.start_with?(IGNORE_PREFIX)
|
58
|
+
|
59
59
|
h[var] = sanitize_value(th.thread_variable_get(var))
|
60
60
|
end
|
61
61
|
end
|
@@ -63,6 +63,7 @@ module Airbrake
|
|
63
63
|
def fiber_variables(th)
|
64
64
|
th.keys.map.with_object({}) do |key, h|
|
65
65
|
next if key.to_s.start_with?(IGNORE_PREFIX)
|
66
|
+
|
66
67
|
h[key] = sanitize_value(th[key])
|
67
68
|
end
|
68
69
|
end
|
@@ -82,7 +83,7 @@ module Airbrake
|
|
82
83
|
when Array
|
83
84
|
value = value.map { |elem| sanitize_value(elem) }
|
84
85
|
when Hash
|
85
|
-
|
86
|
+
value.transform_values { |v| sanitize_value(v) }
|
86
87
|
else
|
87
88
|
value.to_s
|
88
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.
|
@@ -38,6 +36,7 @@ module Airbrake
|
|
38
36
|
# @raise [Airbrake::Error] when instance is ignored
|
39
37
|
def raise_if_ignored
|
40
38
|
return unless ignored?
|
39
|
+
|
41
40
|
raise Airbrake::Error, "cannot access ignored #{self.class}"
|
42
41
|
end
|
43
42
|
end
|
data/lib/airbrake-ruby/notice.rb
CHANGED
@@ -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:
|
12
|
+
notifier: Airbrake::NOTIFIER_INFO,
|
20
13
|
}.freeze
|
21
14
|
|
22
15
|
# @return [Integer] the maxium size of the JSON payload in bytes
|
@@ -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]
|
@@ -135,6 +134,7 @@ module Airbrake
|
|
135
134
|
# If true, then it's likely an internal library error. In this case return
|
136
135
|
# at least some backtrace to simplify debugging.
|
137
136
|
return caller_copy if clean_bt.empty?
|
137
|
+
|
138
138
|
clean_bt
|
139
139
|
end
|
140
140
|
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, :
|
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
|
@@ -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,42 +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
|
-
|
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
|
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
|
-
def check_configuration(resource)
|
114
|
+
def check_configuration(metric)
|
129
115
|
promise = @config.check_configuration
|
130
116
|
return promise if promise.rejected?
|
131
117
|
|
132
|
-
promise = @config.check_performance_options(
|
118
|
+
promise = @config.check_performance_options(metric)
|
133
119
|
return promise if promise.rejected?
|
134
120
|
|
135
|
-
if
|
121
|
+
if metric.timing && metric.timing == 0
|
136
122
|
return Promise.new.reject(':timing cannot be zero')
|
137
123
|
end
|
138
124
|
|
@@ -142,47 +128,47 @@ module Airbrake
|
|
142
128
|
def send(sender, payload, promise)
|
143
129
|
raise "payload cannot be empty. Race?" if payload.none?
|
144
130
|
|
145
|
-
with_grouped_payload(payload) do |
|
131
|
+
with_grouped_payload(payload) do |metric_hash, destination|
|
146
132
|
url = URI.join(
|
147
|
-
@config.
|
133
|
+
@config.apm_host,
|
148
134
|
"api/v5/projects/#{@config.project_id}/#{destination}",
|
149
135
|
)
|
150
136
|
|
151
137
|
logger.debug do
|
152
|
-
"#{LOG_LABEL} #{self.class.name}##{__method__}: #{
|
138
|
+
"#{LOG_LABEL} #{self.class.name}##{__method__}: #{metric_hash}"
|
153
139
|
end
|
154
|
-
sender.send(
|
140
|
+
sender.send(metric_hash, promise, url)
|
155
141
|
end
|
156
142
|
|
157
143
|
promise
|
158
144
|
end
|
159
145
|
|
160
146
|
def with_grouped_payload(raw_payload)
|
161
|
-
grouped_payload = raw_payload.group_by do |
|
162
|
-
[
|
147
|
+
grouped_payload = raw_payload.group_by do |metric, _stats|
|
148
|
+
[metric.cargo, metric.destination]
|
163
149
|
end
|
164
150
|
|
165
|
-
grouped_payload.each do |(cargo, destination),
|
151
|
+
grouped_payload.each do |(cargo, destination), metrics|
|
166
152
|
payload = {}
|
167
|
-
payload[cargo] =
|
153
|
+
payload[cargo] = serialize_metrics(metrics)
|
168
154
|
payload['environment'] = @config.environment if @config.environment
|
169
155
|
|
170
156
|
yield(payload, destination)
|
171
157
|
end
|
172
158
|
end
|
173
159
|
|
174
|
-
def
|
175
|
-
|
176
|
-
|
160
|
+
def serialize_metrics(metrics)
|
161
|
+
metrics.map do |metric, stats|
|
162
|
+
metric_hash = metric.to_h.merge!(stats[:total].to_h)
|
177
163
|
|
178
|
-
if
|
164
|
+
if metric.groups.any?
|
179
165
|
group_stats = stats.reject { |name, _stat| name == :total }
|
180
|
-
|
166
|
+
metric_hash['groups'] = group_stats.merge(group_stats) do |_name, stat|
|
181
167
|
stat.to_h
|
182
168
|
end
|
183
169
|
end
|
184
170
|
|
185
|
-
|
171
|
+
metric_hash
|
186
172
|
end
|
187
173
|
end
|
188
174
|
end
|
data/lib/airbrake-ruby/query.rb
CHANGED
@@ -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, :
|
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
|
data/lib/airbrake-ruby/queue.rb
CHANGED
@@ -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, :
|
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
|
@@ -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 v5.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
|
@@ -0,0 +1,116 @@
|
|
1
|
+
module Airbrake
|
2
|
+
class RemoteSettings
|
3
|
+
# SettingsData is a container, which wraps JSON payload returned by the
|
4
|
+
# remote settings API. It exposes the payload via convenient methods and
|
5
|
+
# also ensures that in case some data from the payload is missing, a default
|
6
|
+
# value would be returned instead.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # Create the object and pass initial data (empty hash).
|
10
|
+
# settings_data = SettingsData.new({})
|
11
|
+
#
|
12
|
+
# settings_data.interval #=> 600
|
13
|
+
#
|
14
|
+
# @since v5.0.0
|
15
|
+
# @api private
|
16
|
+
class SettingsData
|
17
|
+
# @return [Integer] how frequently we should poll the config API
|
18
|
+
DEFAULT_INTERVAL = 600
|
19
|
+
|
20
|
+
# @return [String] API version of the S3 API to poll
|
21
|
+
API_VER = '2020-06-18'.freeze
|
22
|
+
|
23
|
+
# @return [String] what path to poll
|
24
|
+
CONFIG_ROUTE_PATTERN =
|
25
|
+
"%<host>s/#{API_VER}/config/%<project_id>s/config.json".freeze
|
26
|
+
|
27
|
+
# @return [Hash{Symbol=>String}] the hash of all supported settings where
|
28
|
+
# the value is the name of the setting returned by the API
|
29
|
+
SETTINGS = {
|
30
|
+
errors: 'errors'.freeze,
|
31
|
+
apm: 'apm'.freeze,
|
32
|
+
}.freeze
|
33
|
+
|
34
|
+
# @param [Integer] project_id
|
35
|
+
# @param [Hash{String=>Object}] data
|
36
|
+
def initialize(project_id, data)
|
37
|
+
@project_id = project_id
|
38
|
+
@data = data
|
39
|
+
end
|
40
|
+
|
41
|
+
# Merges the given +hash+ with internal data.
|
42
|
+
#
|
43
|
+
# @param [Hash{String=>Object}] hash
|
44
|
+
# @return [self]
|
45
|
+
def merge!(hash)
|
46
|
+
@data.merge!(hash)
|
47
|
+
|
48
|
+
self
|
49
|
+
end
|
50
|
+
|
51
|
+
# @return [Integer] how frequently we should poll for the config
|
52
|
+
def interval
|
53
|
+
return DEFAULT_INTERVAL if !@data.key?('poll_sec') || !@data['poll_sec']
|
54
|
+
|
55
|
+
@data['poll_sec'] > 0 ? @data['poll_sec'] : DEFAULT_INTERVAL
|
56
|
+
end
|
57
|
+
|
58
|
+
# @param [String] remote_config_host
|
59
|
+
# @return [String] where the config is stored on S3.
|
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']}"
|
63
|
+
end
|
64
|
+
|
65
|
+
format(
|
66
|
+
CONFIG_ROUTE_PATTERN,
|
67
|
+
host: remote_config_host.chomp('/'),
|
68
|
+
project_id: @project_id,
|
69
|
+
)
|
70
|
+
end
|
71
|
+
|
72
|
+
# @return [Boolean] whether error notifications are enabled
|
73
|
+
def error_notifications?
|
74
|
+
return true unless (s = find_setting(SETTINGS[:errors]))
|
75
|
+
|
76
|
+
s['enabled']
|
77
|
+
end
|
78
|
+
|
79
|
+
# @return [Boolean] whether APM is enabled
|
80
|
+
def performance_stats?
|
81
|
+
return true unless (s = find_setting(SETTINGS[:apm]))
|
82
|
+
|
83
|
+
s['enabled']
|
84
|
+
end
|
85
|
+
|
86
|
+
# @return [String, nil] the host, which provides the API endpoint to which
|
87
|
+
# exceptions should be sent
|
88
|
+
def error_host
|
89
|
+
return unless (s = find_setting(SETTINGS[:errors]))
|
90
|
+
|
91
|
+
s['endpoint']
|
92
|
+
end
|
93
|
+
|
94
|
+
# @return [String, nil] the host, which provides the API endpoint to which
|
95
|
+
# APM data should be sent
|
96
|
+
def apm_host
|
97
|
+
return unless (s = find_setting(SETTINGS[:apm]))
|
98
|
+
|
99
|
+
s['endpoint']
|
100
|
+
end
|
101
|
+
|
102
|
+
# @return [Hash{String=>Object}] raw representation of JSON payload
|
103
|
+
def to_h
|
104
|
+
@data.dup
|
105
|
+
end
|
106
|
+
|
107
|
+
private
|
108
|
+
|
109
|
+
def find_setting(name)
|
110
|
+
return unless @data.key?('settings')
|
111
|
+
|
112
|
+
@data['settings'].find { |s| s['name'] == name }
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|