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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2dfccc9b2cf013d06ad40e4b3726319c13bd09dcba70d9c1fa4b382c7d80b1b4
|
4
|
+
data.tar.gz: 63c8aa81c33948f26ead281e81769a274dbca9740880a420d62b4d951b352984
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 694a9114eb130976c052748a51e0490b3276bf32fe347bf466e64caf68e26c703941cd131bb43a0b7f3b6c6c9580067feffd5c1d443a46319a09ec6d0d1f6a37
|
7
|
+
data.tar.gz: 59bf1fd79c2467401aabc0c352397d82bae83805cb54ccac40c5ca132dfcfdefa5281a8ba11dc96f67d569405837af61aeb05a22ce9e2f3425d0ecc4a1c69251
|
@@ -7,16 +7,17 @@ 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.
|
16
17
|
#
|
17
18
|
# @param [Hash] payload Whatever needs to be sent
|
18
19
|
# @return [Airbrake::Promise]
|
19
|
-
def send(payload, promise, endpoint = @config.
|
20
|
+
def send(payload, promise, endpoint = @config.error_endpoint)
|
20
21
|
unless thread_pool << [payload, promise, endpoint]
|
21
22
|
return promise.reject(
|
22
23
|
"AsyncSender has reached its capacity of #{@config.queue_size}",
|
@@ -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) },
|
@@ -22,7 +22,7 @@ module Airbrake
|
|
22
22
|
(?<line>\d+) # Matches '43'
|
23
23
|
:in\s
|
24
24
|
`(?<function>.*)' # Matches "`block (3 levels) in <top (required)>'"
|
25
|
-
\z}x
|
25
|
+
\z}x.freeze
|
26
26
|
|
27
27
|
# @return [Regexp] the pattern that matches JRuby Java stack frames, such
|
28
28
|
# as org.jruby.ast.NewlineNode.interpret(NewlineNode.java:105)
|
@@ -39,7 +39,7 @@ module Airbrake
|
|
39
39
|
:?
|
40
40
|
(?<line>\d+)? # Matches '105'
|
41
41
|
\)
|
42
|
-
\z}x
|
42
|
+
\z}x.freeze
|
43
43
|
|
44
44
|
# @return [Regexp] the pattern that tries to assume what a generic stack
|
45
45
|
# frame might look like, when exception's backtrace is set manually.
|
@@ -53,7 +53,7 @@ module Airbrake
|
|
53
53
|
|
|
54
54
|
:in\s(?<function>.+) # Matches ":in func"
|
55
55
|
)? # ... or nothing
|
56
|
-
\z}x
|
56
|
+
\z}x.freeze
|
57
57
|
|
58
58
|
# @return [Regexp] the pattern that matches exceptions from PL/SQL such as
|
59
59
|
# ORA-06512: at "STORE.LI_LICENSES_PACK", line 1945
|
@@ -67,7 +67,7 @@ module Airbrake
|
|
67
67
|
|
|
68
68
|
#{GENERIC}
|
69
69
|
)
|
70
|
-
\z/x
|
70
|
+
\z/x.freeze
|
71
71
|
|
72
72
|
# @return [Regexp] the pattern that matches CoffeeScript backtraces
|
73
73
|
# usually coming from Rails & ExecJS
|
@@ -82,7 +82,7 @@ module Airbrake
|
|
82
82
|
# Matches the Ruby part of the backtrace
|
83
83
|
#{RUBY}
|
84
84
|
)
|
85
|
-
\z/x
|
85
|
+
\z/x.freeze
|
86
86
|
end
|
87
87
|
|
88
88
|
# @return [Integer] how many first frames should include code hunks
|
@@ -95,6 +95,7 @@ module Airbrake
|
|
95
95
|
# @return [Array<Hash{Symbol=>String,Integer}>] the parsed backtrace
|
96
96
|
def self.parse(exception)
|
97
97
|
return [] if exception.backtrace.nil? || exception.backtrace.none?
|
98
|
+
|
98
99
|
parse_backtrace(exception)
|
99
100
|
end
|
100
101
|
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Airbrake
|
2
|
+
class Config
|
3
|
+
# Processor is a helper class, which is responsible for setting default
|
4
|
+
# config values, default notifier filters and remote configuration changes.
|
5
|
+
#
|
6
|
+
# @since v5.0.0
|
7
|
+
# @api private
|
8
|
+
class Processor
|
9
|
+
# @param [Airbrake::Config] config
|
10
|
+
# @return [Airbrake::Config::Processor]
|
11
|
+
def self.process(config)
|
12
|
+
new(config).process
|
13
|
+
end
|
14
|
+
|
15
|
+
# @param [Airbrake::Config] config
|
16
|
+
def initialize(config)
|
17
|
+
@config = config
|
18
|
+
@blocklist_keys = @config.blocklist_keys
|
19
|
+
@allowlist_keys = @config.allowlist_keys
|
20
|
+
@project_id = @config.project_id
|
21
|
+
@poll_callback = Airbrake::RemoteSettings::Callback.new(config)
|
22
|
+
end
|
23
|
+
|
24
|
+
# @param [Airbrake::NoticeNotifier] notifier
|
25
|
+
# @return [void]
|
26
|
+
def process_blocklist(notifier)
|
27
|
+
return if @blocklist_keys.none?
|
28
|
+
|
29
|
+
blocklist = Airbrake::Filters::KeysBlocklist.new(@blocklist_keys)
|
30
|
+
notifier.add_filter(blocklist)
|
31
|
+
end
|
32
|
+
|
33
|
+
# @param [Airbrake::NoticeNotifier] notifier
|
34
|
+
# @return [void]
|
35
|
+
def process_allowlist(notifier)
|
36
|
+
return if @allowlist_keys.none?
|
37
|
+
|
38
|
+
allowlist = Airbrake::Filters::KeysAllowlist.new(@allowlist_keys)
|
39
|
+
notifier.add_filter(allowlist)
|
40
|
+
end
|
41
|
+
|
42
|
+
# @return [Airbrake::RemoteSettings]
|
43
|
+
def process_remote_configuration
|
44
|
+
return unless @config.remote_config
|
45
|
+
return unless @project_id
|
46
|
+
|
47
|
+
# Never poll remote configuration in the test environment.
|
48
|
+
return if @config.environment == 'test'
|
49
|
+
|
50
|
+
# If the current environment is ignored, don't try to poll remote
|
51
|
+
# configuration.
|
52
|
+
return if @config.ignore_environments.include?(@config.environment)
|
53
|
+
|
54
|
+
RemoteSettings.poll(@project_id, @config.remote_config_host) do |data|
|
55
|
+
@poll_callback.call(data)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# @param [Airbrake::NoticeNotifier] notifier
|
60
|
+
# @return [void]
|
61
|
+
def add_filters(notifier)
|
62
|
+
return unless @config.root_directory
|
63
|
+
|
64
|
+
[
|
65
|
+
Airbrake::Filters::RootDirectoryFilter,
|
66
|
+
Airbrake::Filters::GitRevisionFilter,
|
67
|
+
Airbrake::Filters::GitRepositoryFilter,
|
68
|
+
Airbrake::Filters::GitLastCheckoutFilter,
|
69
|
+
].each do |filter|
|
70
|
+
next if notifier.has_filter?(filter)
|
71
|
+
|
72
|
+
notifier.add_filter(filter.new(@config.root_directory))
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -44,6 +44,10 @@ module Airbrake
|
|
44
44
|
def check_notify_ability(config)
|
45
45
|
promise = Airbrake::Promise.new
|
46
46
|
|
47
|
+
unless config.error_notifications
|
48
|
+
return promise.reject('error notifications are disabled')
|
49
|
+
end
|
50
|
+
|
47
51
|
if ignored_environment?(config)
|
48
52
|
return promise.reject(
|
49
53
|
"current environment '#{config.environment}' is ignored",
|
@@ -57,12 +61,14 @@ module Airbrake
|
|
57
61
|
|
58
62
|
def valid_project_id?(config)
|
59
63
|
return true if config.project_id.to_i > 0
|
64
|
+
|
60
65
|
false
|
61
66
|
end
|
62
67
|
|
63
68
|
def valid_project_key?(config)
|
64
69
|
return false unless config.project_key.is_a?(String)
|
65
70
|
return false if config.project_key.empty?
|
71
|
+
|
66
72
|
true
|
67
73
|
end
|
68
74
|
|
data/lib/airbrake-ruby/config.rb
CHANGED
@@ -46,6 +46,17 @@ module Airbrake
|
|
46
46
|
# @api public
|
47
47
|
attr_accessor :host
|
48
48
|
|
49
|
+
# @since v5.0.0
|
50
|
+
alias error_host host
|
51
|
+
# @since v5.0.0
|
52
|
+
alias error_host= host=
|
53
|
+
|
54
|
+
# @return [String] the host, which provides the API endpoint to which
|
55
|
+
# APM data should be sent
|
56
|
+
# @api public
|
57
|
+
# @since v5.0.0
|
58
|
+
attr_accessor :apm_host
|
59
|
+
|
49
60
|
# @return [String, Pathname] the working directory of your project
|
50
61
|
# @api public
|
51
62
|
attr_accessor :root_directory
|
@@ -71,18 +82,12 @@ module Airbrake
|
|
71
82
|
# @since v4.15.0
|
72
83
|
attr_accessor :allowlist_keys
|
73
84
|
|
74
|
-
# @deprecated Use allowlist_keys instead
|
75
|
-
alias whitelist_keys allowlist_keys
|
76
|
-
|
77
85
|
# @return [Array<String, Symbol, Regexp>] the keys, which should be
|
78
86
|
# filtered
|
79
87
|
# @api public
|
80
88
|
# @since v4.15.0
|
81
89
|
attr_accessor :blocklist_keys
|
82
90
|
|
83
|
-
# @deprecated Use blocklist_keys instead
|
84
|
-
alias blacklist_keys blocklist_keys
|
85
|
-
|
86
91
|
# @return [Boolean] true if the library should attach code hunks to each
|
87
92
|
# frame in a backtrace, false otherwise
|
88
93
|
# @api public
|
@@ -113,6 +118,24 @@ module Airbrake
|
|
113
118
|
# @since v4.12.0
|
114
119
|
attr_accessor :job_stats
|
115
120
|
|
121
|
+
# @return [Boolean] true if the library should send error reports to
|
122
|
+
# Airbrake, false otherwise
|
123
|
+
# @api public
|
124
|
+
# @since v5.0.0
|
125
|
+
attr_accessor :error_notifications
|
126
|
+
|
127
|
+
# @return [String] the host which should be used for fetching remote
|
128
|
+
# configuration options
|
129
|
+
# @api public
|
130
|
+
# @since v5.0.0
|
131
|
+
attr_accessor :remote_config_host
|
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
|
+
|
116
139
|
class << self
|
117
140
|
# @return [Config]
|
118
141
|
attr_writer :instance
|
@@ -125,7 +148,7 @@ module Airbrake
|
|
125
148
|
|
126
149
|
# @param [Hash{Symbol=>Object}] user_config the hash to be used to build the
|
127
150
|
# config
|
128
|
-
# rubocop:disable Metrics/AbcSize
|
151
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
129
152
|
def initialize(user_config = {})
|
130
153
|
self.proxy = {}
|
131
154
|
self.queue_size = 100
|
@@ -134,7 +157,9 @@ module Airbrake
|
|
134
157
|
self.logger = ::Logger.new(File::NULL).tap { |l| l.level = Logger::WARN }
|
135
158
|
self.project_id = user_config[:project_id]
|
136
159
|
self.project_key = user_config[:project_key]
|
137
|
-
self.
|
160
|
+
self.error_host = 'https://api.airbrake.io'
|
161
|
+
self.apm_host = 'https://api.airbrake.io'
|
162
|
+
self.remote_config_host = 'https://notifier-configs.airbrake.io'
|
138
163
|
|
139
164
|
self.ignore_environments = []
|
140
165
|
|
@@ -153,37 +178,21 @@ module Airbrake
|
|
153
178
|
self.performance_stats_flush_period = 15
|
154
179
|
self.query_stats = true
|
155
180
|
self.job_stats = true
|
181
|
+
self.error_notifications = true
|
182
|
+
self.remote_config = true
|
156
183
|
|
157
184
|
merge(user_config)
|
158
185
|
end
|
159
|
-
# rubocop:enable Metrics/AbcSize
|
160
|
-
|
161
|
-
def blacklist_keys=(keys)
|
162
|
-
loc = caller_locations(1..1).first
|
163
|
-
Kernel.warn(
|
164
|
-
"#{loc.path}:#{loc.lineno}: warning: blacklist_keys= is deprecated " \
|
165
|
-
"use blocklist_keys= instead",
|
166
|
-
)
|
167
|
-
self.blocklist_keys = keys
|
168
|
-
end
|
169
|
-
|
170
|
-
def whitelist_keys=(keys)
|
171
|
-
loc = caller_locations(1..1).first
|
172
|
-
Kernel.warn(
|
173
|
-
"#{loc.path}:#{loc.lineno}: warning: whitelist_keys= is deprecated " \
|
174
|
-
"use allowlist_keys= instead",
|
175
|
-
)
|
176
|
-
self.allowlist_keys = keys
|
177
|
-
end
|
186
|
+
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
178
187
|
|
179
|
-
# The full URL to the Airbrake Notice API. Based on the +:
|
188
|
+
# The full URL to the Airbrake Notice API. Based on the +:error_host+ option.
|
180
189
|
# @return [URI] the endpoint address
|
181
|
-
def
|
182
|
-
@
|
190
|
+
def error_endpoint
|
191
|
+
@error_endpoint ||=
|
183
192
|
begin
|
184
|
-
self.
|
193
|
+
self.error_host = ('https://' << error_host) if error_host !~ %r{\Ahttps?://}
|
185
194
|
api = "api/v3/projects/#{project_id}/notices"
|
186
|
-
URI.join(
|
195
|
+
URI.join(error_host, api)
|
187
196
|
end
|
188
197
|
end
|
189
198
|
|
@@ -239,14 +248,14 @@ module Airbrake
|
|
239
248
|
|
240
249
|
# @return [Promise] resolved promise if neither of the performance options
|
241
250
|
# reject it, false otherwise
|
242
|
-
def check_performance_options(
|
251
|
+
def check_performance_options(metric)
|
243
252
|
promise = Airbrake::Promise.new
|
244
253
|
|
245
254
|
if !performance_stats
|
246
255
|
promise.reject("The Performance Stats feature is disabled")
|
247
|
-
elsif
|
256
|
+
elsif metric.is_a?(Airbrake::Query) && !query_stats
|
248
257
|
promise.reject("The Query Stats feature is disabled")
|
249
|
-
elsif
|
258
|
+
elsif metric.is_a?(Airbrake::Queue) && !job_stats
|
250
259
|
promise.reject("The Job Stats feature is disabled")
|
251
260
|
else
|
252
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
|
|
@@ -70,6 +72,7 @@ module Airbrake
|
|
70
72
|
def refine(notice)
|
71
73
|
@filters.each do |filter|
|
72
74
|
break if notice.ignored?
|
75
|
+
|
73
76
|
filter.call(notice)
|
74
77
|
end
|
75
78
|
end
|
@@ -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
|
@@ -41,16 +41,16 @@ module Airbrake
|
|
41
41
|
|
42
42
|
return unless File.exist?(@git_path)
|
43
43
|
return unless (checkout = last_checkout)
|
44
|
+
|
44
45
|
notice[:context][:lastCheckout] = checkout
|
45
46
|
end
|
46
47
|
|
47
48
|
private
|
48
49
|
|
49
|
-
# rubocop:disable Metrics/AbcSize
|
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}",
|
@@ -66,14 +66,13 @@ module Airbrake
|
|
66
66
|
time: timestamp(parts[-2].to_i),
|
67
67
|
}
|
68
68
|
end
|
69
|
-
# rubocop:enable Metrics/AbcSize
|
70
69
|
|
71
70
|
def last_checkout_line
|
72
71
|
head_path = File.join(@git_path, 'logs', 'HEAD')
|
73
72
|
return unless File.exist?(head_path)
|
74
73
|
|
75
74
|
last_line = nil
|
76
|
-
|
75
|
+
File.foreach(head_path) do |line|
|
77
76
|
last_line = line if checkout_line?(line)
|
78
77
|
end
|
79
78
|
last_line
|
@@ -18,6 +18,7 @@ module Airbrake
|
|
18
18
|
# @macro call_filter
|
19
19
|
def call(notice)
|
20
20
|
return if notice[:context].key?(:repository)
|
21
|
+
|
21
22
|
attach_repository(notice)
|
22
23
|
end
|
23
24
|
|
@@ -35,10 +36,11 @@ module Airbrake
|
|
35
36
|
`cd #{@git_path} && git config --get remote.origin.url`.chomp
|
36
37
|
else
|
37
38
|
"`git remote get-url` is unsupported in git #{@git_version}. " \
|
38
|
-
|
39
|
+
'Consider an upgrade to 2.7+'
|
39
40
|
end
|
40
41
|
|
41
42
|
return unless @repository
|
43
|
+
|
42
44
|
notice[:context][:repository] = @repository
|
43
45
|
end
|
44
46
|
|
@@ -46,7 +48,14 @@ module Airbrake
|
|
46
48
|
|
47
49
|
def detect_git_version
|
48
50
|
return unless which('git')
|
49
|
-
|
51
|
+
|
52
|
+
begin
|
53
|
+
Gem::Version.new(`git --version`.split[2])
|
54
|
+
rescue Errno::EAGAIN
|
55
|
+
# Bugfix for the case when the system cannot allocate memory for
|
56
|
+
# a fork() call: https://github.com/airbrake/airbrake-ruby/issues/680
|
57
|
+
nil
|
58
|
+
end
|
50
59
|
end
|
51
60
|
|
52
61
|
# Cross-platform way to tell if an executable is accessible.
|
@@ -30,6 +30,7 @@ module Airbrake
|
|
30
30
|
|
31
31
|
@revision = find_revision
|
32
32
|
return unless @revision
|
33
|
+
|
33
34
|
notice[:context][:revision] = @revision
|
34
35
|
end
|
35
36
|
|
@@ -41,6 +42,7 @@ module Airbrake
|
|
41
42
|
|
42
43
|
head = File.read(head_path)
|
43
44
|
return head unless head.start_with?(PREFIX)
|
45
|
+
|
44
46
|
head = head.chomp[PREFIX.size..-1]
|
45
47
|
|
46
48
|
ref_path = File.join(@git_path, head)
|
@@ -55,7 +57,7 @@ module Airbrake
|
|
55
57
|
|
56
58
|
File.readlines(packed_refs_path).each do |line|
|
57
59
|
next if %w[# ^].include?(line[0])
|
58
|
-
next unless (parts = line.split
|
60
|
+
next unless (parts = line.split).size == 2
|
59
61
|
return parts.first if parts.last == head
|
60
62
|
end
|
61
63
|
|
@@ -64,10 +64,14 @@ module Airbrake
|
|
64
64
|
validate_patterns
|
65
65
|
end
|
66
66
|
|
67
|
-
FILTERABLE_KEYS.each
|
67
|
+
FILTERABLE_KEYS.each do |key|
|
68
|
+
notice[key] = filter_hash(notice[key])
|
69
|
+
end
|
70
|
+
|
68
71
|
FILTERABLE_CONTEXT_KEYS.each { |key| filter_context_key(notice, key) }
|
69
72
|
|
70
73
|
return unless notice[:context][:url]
|
74
|
+
|
71
75
|
filter_url(notice)
|
72
76
|
end
|
73
77
|
|
@@ -78,29 +82,29 @@ module Airbrake
|
|
78
82
|
|
79
83
|
private
|
80
84
|
|
81
|
-
def filter_hash(hash)
|
85
|
+
def filter_hash(hash) # rubocop:disable Metrics/AbcSize
|
82
86
|
return hash unless hash.is_a?(Hash)
|
83
87
|
|
88
|
+
hash_copy = hash.dup
|
89
|
+
|
84
90
|
hash.each_key do |key|
|
85
91
|
if should_filter?(key.to_s)
|
86
|
-
|
87
|
-
elsif
|
88
|
-
filter_hash(
|
92
|
+
hash_copy[key] = FILTERED
|
93
|
+
elsif hash_copy[key].is_a?(Hash)
|
94
|
+
hash_copy[key] = filter_hash(hash_copy[key])
|
89
95
|
elsif hash[key].is_a?(Array)
|
90
|
-
|
96
|
+
hash_copy[key].each_with_index do |h, i|
|
97
|
+
hash_copy[key][i] = filter_hash(h)
|
98
|
+
end
|
91
99
|
end
|
92
100
|
end
|
101
|
+
|
102
|
+
hash_copy
|
93
103
|
end
|
94
104
|
|
95
105
|
def filter_url_params(url)
|
96
|
-
url.query =
|
97
|
-
|
98
|
-
# invalid characters, so be sure to escape individual components.
|
99
|
-
if should_filter?(key)
|
100
|
-
"#{URI.encode_www_form_component(key)}=[Filtered]"
|
101
|
-
else
|
102
|
-
"#{URI.encode_www_form_component(key)}=#{URI.encode_www_form_component(val)}"
|
103
|
-
end
|
106
|
+
url.query = URI.decode_www_form(url.query).to_h.map do |key, val|
|
107
|
+
should_filter?(key) ? "#{key}=[Filtered]" : "#{key}=#{val}"
|
104
108
|
end.join('&')
|
105
109
|
|
106
110
|
url.to_s
|
@@ -114,6 +118,7 @@ module Airbrake
|
|
114
118
|
end
|
115
119
|
|
116
120
|
return unless url.query
|
121
|
+
|
117
122
|
notice[:context][:url] = filter_url_params(url)
|
118
123
|
end
|
119
124
|
|
@@ -122,6 +127,7 @@ module Airbrake
|
|
122
127
|
|
123
128
|
@patterns = @patterns.flat_map do |pattern|
|
124
129
|
next(pattern) unless pattern.respond_to?(:call)
|
130
|
+
|
125
131
|
pattern.call
|
126
132
|
end
|
127
133
|
end
|
@@ -142,7 +148,9 @@ module Airbrake
|
|
142
148
|
def filter_context_key(notice, key)
|
143
149
|
return unless notice[:context][key]
|
144
150
|
return if notice[:context][key] == FILTERED
|
145
|
-
|
151
|
+
unless should_filter?(key)
|
152
|
+
return notice[:context][key] = filter_hash(notice[:context][key])
|
153
|
+
end
|
146
154
|
|
147
155
|
notice[:context][key] = FILTERED
|
148
156
|
end
|