airbrake-ruby 5.0.0.rc.2-java → 5.2.0-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.rb +1 -0
- data/lib/airbrake-ruby/backtrace.rb +6 -5
- data/lib/airbrake-ruby/config.rb +19 -38
- data/lib/airbrake-ruby/config/processor.rb +8 -17
- data/lib/airbrake-ruby/config/validator.rb +2 -0
- data/lib/airbrake-ruby/file_cache.rb +1 -1
- data/lib/airbrake-ruby/filter_chain.rb +1 -0
- data/lib/airbrake-ruby/filters/dependency_filter.rb +1 -0
- data/lib/airbrake-ruby/filters/gem_root_filter.rb +1 -0
- data/lib/airbrake-ruby/filters/git_last_checkout_filter.rb +1 -2
- data/lib/airbrake-ruby/filters/git_repository_filter.rb +3 -0
- data/lib/airbrake-ruby/filters/git_revision_filter.rb +2 -0
- data/lib/airbrake-ruby/filters/keys_filter.rb +21 -13
- data/lib/airbrake-ruby/filters/root_directory_filter.rb +1 -0
- data/lib/airbrake-ruby/filters/sql_filter.rb +4 -4
- data/lib/airbrake-ruby/filters/system_exit_filter.rb +1 -0
- data/lib/airbrake-ruby/filters/thread_filter.rb +3 -2
- data/lib/airbrake-ruby/grouppable.rb +1 -1
- data/lib/airbrake-ruby/ignorable.rb +1 -0
- data/lib/airbrake-ruby/mergeable.rb +1 -1
- data/lib/airbrake-ruby/notice_notifier.rb +1 -0
- data/lib/airbrake-ruby/performance_breakdown.rb +1 -6
- data/lib/airbrake-ruby/performance_notifier.rb +1 -14
- 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.rb +16 -54
- data/lib/airbrake-ruby/remote_settings/callback.rb +44 -0
- data/lib/airbrake-ruby/remote_settings/settings_data.rb +14 -14
- data/lib/airbrake-ruby/request.rb +1 -8
- data/lib/airbrake-ruby/stat.rb +1 -12
- data/lib/airbrake-ruby/sync_sender.rb +1 -0
- data/lib/airbrake-ruby/tdigest.rb +2 -0
- data/lib/airbrake-ruby/thread_pool.rb +1 -0
- data/lib/airbrake-ruby/truncator.rb +8 -2
- data/lib/airbrake-ruby/version.rb +2 -2
- data/spec/backtrace_spec.rb +26 -26
- data/spec/code_hunk_spec.rb +2 -2
- data/spec/config/processor_spec.rb +21 -101
- data/spec/config_spec.rb +5 -29
- data/spec/filters/gem_root_filter_spec.rb +4 -4
- data/spec/filters/git_last_checkout_filter_spec.rb +1 -1
- data/spec/filters/keys_allowlist_spec.rb +1 -0
- data/spec/filters/keys_blocklist_spec.rb +10 -0
- data/spec/filters/root_directory_filter_spec.rb +4 -4
- data/spec/filters/sql_filter_spec.rb +2 -2
- data/spec/filters/thread_filter_spec.rb +1 -1
- data/spec/notice_notifier/options_spec.rb +2 -2
- data/spec/notice_notifier_spec.rb +2 -2
- data/spec/notice_spec.rb +1 -1
- data/spec/performance_breakdown_spec.rb +0 -12
- data/spec/performance_notifier_spec.rb +0 -25
- data/spec/query_spec.rb +1 -11
- data/spec/queue_spec.rb +1 -13
- data/spec/remote_settings/callback_spec.rb +143 -0
- data/spec/remote_settings/settings_data_spec.rb +34 -13
- data/spec/remote_settings_spec.rb +40 -83
- data/spec/request_spec.rb +1 -13
- data/spec/spec_helper.rb +4 -4
- data/spec/stat_spec.rb +0 -9
- data/spec/tdigest_spec.rb +1 -1
- metadata +8 -5
@@ -23,7 +23,7 @@ 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|$)/,
|
@@ -33,13 +33,13 @@ module Airbrake
|
|
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'\(.*?(?:\)'|$)
|
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
|
@@ -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
|
@@ -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
|
@@ -104,7 +104,7 @@ module Airbrake
|
|
104
104
|
@payload[resource] = { total: Airbrake::Stat.new }
|
105
105
|
end
|
106
106
|
|
107
|
-
|
107
|
+
@payload[resource][:total].increment_ms(resource.timing)
|
108
108
|
|
109
109
|
resource.groups.each do |name, ms|
|
110
110
|
@payload[resource][name] ||= Airbrake::Stat.new
|
@@ -112,19 +112,6 @@ module Airbrake
|
|
112
112
|
end
|
113
113
|
end
|
114
114
|
|
115
|
-
def update_total(resource, total)
|
116
|
-
if resource.timing
|
117
|
-
total.increment_ms(resource.timing)
|
118
|
-
else
|
119
|
-
loc = caller_locations(6..6).first
|
120
|
-
Kernel.warn(
|
121
|
-
"#{loc.path}:#{loc.lineno}: warning: :start_time and :end_time are " \
|
122
|
-
"deprecated. Use :timing & :time instead",
|
123
|
-
)
|
124
|
-
total.increment(resource.start_time, resource.end_time)
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
115
|
def check_configuration(resource)
|
129
116
|
promise = @config.check_configuration
|
130
117
|
return promise if promise.rejected?
|
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
|
@@ -8,22 +8,11 @@ module Airbrake
|
|
8
8
|
# config.error_notifications = data.error_notifications?
|
9
9
|
# end
|
10
10
|
#
|
11
|
-
#
|
12
|
-
# that it doesn't wait on the result from the API call.
|
13
|
-
#
|
14
|
-
# When {#stop_polling} is called, the current config will be dumped to disk.
|
15
|
-
#
|
16
|
-
# @since ?.?.?
|
11
|
+
# @since 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,37 +22,35 @@ 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
|
31
|
+
# @param [String] host
|
39
32
|
# @yield [data]
|
40
33
|
# @yieldparam data [Airbrake::RemoteSettings::SettingsData]
|
41
34
|
# @return [Airbrake::RemoteSettings]
|
42
|
-
def self.poll(project_id, &block)
|
43
|
-
new(project_id, &block).poll
|
35
|
+
def self.poll(project_id, host, &block)
|
36
|
+
new(project_id, host, &block).poll
|
44
37
|
end
|
45
38
|
|
46
39
|
# @param [Integer] project_id
|
47
40
|
# @yield [data]
|
48
41
|
# @yieldparam data [Airbrake::RemoteSettings::SettingsData]
|
49
|
-
def initialize(project_id, &block)
|
42
|
+
def initialize(project_id, host, &block)
|
50
43
|
@data = SettingsData.new(project_id, {})
|
44
|
+
@host = host
|
51
45
|
@block = block
|
52
46
|
@poll = nil
|
53
47
|
end
|
54
48
|
|
55
|
-
# Polls remote config of the given project in background.
|
56
|
-
# first (if exists).
|
49
|
+
# Polls remote config of the given project in background.
|
57
50
|
#
|
58
51
|
# @return [self]
|
59
52
|
def poll
|
60
53
|
@poll ||= Thread.new do
|
61
|
-
begin
|
62
|
-
load_config
|
63
|
-
rescue StandardError => ex
|
64
|
-
logger.error("#{LOG_LABEL} config loading failed: #{ex}")
|
65
|
-
end
|
66
|
-
|
67
54
|
@block.call(@data)
|
68
55
|
|
69
56
|
loop do
|
@@ -75,17 +62,11 @@ module Airbrake
|
|
75
62
|
self
|
76
63
|
end
|
77
64
|
|
78
|
-
# Stops the background poller thread.
|
65
|
+
# Stops the background poller thread.
|
79
66
|
#
|
80
67
|
# @return [void]
|
81
68
|
def stop_polling
|
82
69
|
@poll.kill if @poll
|
83
|
-
|
84
|
-
begin
|
85
|
-
dump_config
|
86
|
-
rescue StandardError => ex
|
87
|
-
logger.error("#{LOG_LABEL} config dumping failed: #{ex}")
|
88
|
-
end
|
89
70
|
end
|
90
71
|
|
91
72
|
private
|
@@ -93,22 +74,20 @@ module Airbrake
|
|
93
74
|
def fetch_config
|
94
75
|
response = nil
|
95
76
|
begin
|
96
|
-
response = Net::HTTP.
|
77
|
+
response = Net::HTTP.get_response(build_config_uri)
|
97
78
|
rescue StandardError => ex
|
98
79
|
logger.error(ex)
|
99
80
|
return {}
|
100
81
|
end
|
101
82
|
|
102
|
-
|
103
|
-
|
104
|
-
if response.start_with?('<?xml ')
|
105
|
-
logger.error(response)
|
83
|
+
unless response.code == HTTP_OK
|
84
|
+
logger.error(response.body)
|
106
85
|
return {}
|
107
86
|
end
|
108
87
|
|
109
88
|
json = nil
|
110
89
|
begin
|
111
|
-
json = JSON.parse(response)
|
90
|
+
json = JSON.parse(response.body)
|
112
91
|
rescue JSON::ParserError => ex
|
113
92
|
logger.error(ex)
|
114
93
|
return {}
|
@@ -118,26 +97,9 @@ module Airbrake
|
|
118
97
|
end
|
119
98
|
|
120
99
|
def build_config_uri
|
121
|
-
uri = URI(@data.config_route)
|
100
|
+
uri = URI(@data.config_route(@host))
|
122
101
|
uri.query = QUERY_PARAMS
|
123
102
|
uri
|
124
103
|
end
|
125
|
-
|
126
|
-
def load_config
|
127
|
-
config_dir = File.dirname(CONFIG_DUMP_PATH)
|
128
|
-
Dir.mkdir(config_dir) unless File.directory?(config_dir)
|
129
|
-
|
130
|
-
return unless File.exist?(CONFIG_DUMP_PATH)
|
131
|
-
|
132
|
-
config = File.read(CONFIG_DUMP_PATH)
|
133
|
-
@data.merge!(JSON.parse(config))
|
134
|
-
end
|
135
|
-
|
136
|
-
def dump_config
|
137
|
-
config_dir = File.dirname(CONFIG_DUMP_PATH)
|
138
|
-
Dir.mkdir(config_dir) unless File.directory?(config_dir)
|
139
|
-
|
140
|
-
File.write(CONFIG_DUMP_PATH, JSON.dump(@data.to_h))
|
141
|
-
end
|
142
104
|
end
|
143
105
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Airbrake
|
2
|
+
class RemoteSettings
|
3
|
+
# Callback is a class that provides a callback for the config poller, which
|
4
|
+
# updates the local config according to the data.
|
5
|
+
#
|
6
|
+
# @api private
|
7
|
+
# @since 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
|
@@ -11,7 +11,7 @@ module Airbrake
|
|
11
11
|
#
|
12
12
|
# settings_data.interval #=> 600
|
13
13
|
#
|
14
|
-
# @since
|
14
|
+
# @since v5.0.0
|
15
15
|
# @api private
|
16
16
|
class SettingsData
|
17
17
|
# @return [Integer] how frequently we should poll the config API
|
@@ -20,16 +20,15 @@ module Airbrake
|
|
20
20
|
# @return [String] API version of the S3 API to poll
|
21
21
|
API_VER = '2020-06-18'.freeze
|
22
22
|
|
23
|
-
# @return [String] what
|
23
|
+
# @return [String] what path to poll
|
24
24
|
CONFIG_ROUTE_PATTERN =
|
25
|
-
|
26
|
-
"#{API_VER}/config/%<project_id>s/config.json".freeze
|
25
|
+
"%<host>s/#{API_VER}/config/%<project_id>s/config.json".freeze
|
27
26
|
|
28
27
|
# @return [Hash{Symbol=>String}] the hash of all supported settings where
|
29
28
|
# the value is the name of the setting returned by the API
|
30
29
|
SETTINGS = {
|
31
|
-
errors: 'errors',
|
32
|
-
apm: 'apm',
|
30
|
+
errors: 'errors'.freeze,
|
31
|
+
apm: 'apm'.freeze,
|
33
32
|
}.freeze
|
34
33
|
|
35
34
|
# @param [Integer] project_id
|
@@ -56,17 +55,18 @@ module Airbrake
|
|
56
55
|
@data['poll_sec'] > 0 ? @data['poll_sec'] : DEFAULT_INTERVAL
|
57
56
|
end
|
58
57
|
|
58
|
+
# @param [String] remote_config_host
|
59
59
|
# @return [String] where the config is stored on S3.
|
60
|
-
def config_route
|
61
|
-
if
|
62
|
-
return
|
63
|
-
CONFIG_ROUTE_PATTERN,
|
64
|
-
bucket: 'staging-notifier-configs',
|
65
|
-
project_id: @project_id,
|
66
|
-
)
|
60
|
+
def config_route(remote_config_host)
|
61
|
+
if @data['config_route'] && !@data['config_route'].empty?
|
62
|
+
return remote_config_host.chomp('/') + '/' + @data['config_route']
|
67
63
|
end
|
68
64
|
|
69
|
-
|
65
|
+
format(
|
66
|
+
CONFIG_ROUTE_PATTERN,
|
67
|
+
host: remote_config_host.chomp('/'),
|
68
|
+
project_id: @project_id,
|
69
|
+
)
|
70
70
|
end
|
71
71
|
|
72
72
|
# @return [Boolean] whether error notifications are enabled
|