airbrake-ruby 4.1.0 → 5.0.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 +5 -5
- data/lib/airbrake-ruby/async_sender.rb +22 -96
- data/lib/airbrake-ruby/backtrace.rb +8 -7
- data/lib/airbrake-ruby/benchmark.rb +39 -0
- data/lib/airbrake-ruby/code_hunk.rb +1 -1
- data/lib/airbrake-ruby/config/processor.rb +84 -0
- data/lib/airbrake-ruby/config/validator.rb +9 -3
- data/lib/airbrake-ruby/config.rb +76 -20
- data/lib/airbrake-ruby/deploy_notifier.rb +1 -1
- data/lib/airbrake-ruby/file_cache.rb +6 -0
- data/lib/airbrake-ruby/filter_chain.rb +16 -1
- data/lib/airbrake-ruby/filters/dependency_filter.rb +1 -0
- data/lib/airbrake-ruby/filters/exception_attributes_filter.rb +2 -2
- data/lib/airbrake-ruby/filters/gem_root_filter.rb +1 -0
- data/lib/airbrake-ruby/filters/git_last_checkout_filter.rb +5 -5
- 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_whitelist.rb → keys_allowlist.rb} +3 -3
- data/lib/airbrake-ruby/filters/{keys_blacklist.rb → keys_blocklist.rb} +3 -3
- data/lib/airbrake-ruby/filters/keys_filter.rb +39 -20
- data/lib/airbrake-ruby/filters/root_directory_filter.rb +1 -0
- data/lib/airbrake-ruby/filters/sql_filter.rb +30 -6
- data/lib/airbrake-ruby/filters/system_exit_filter.rb +1 -0
- data/lib/airbrake-ruby/filters/thread_filter.rb +4 -2
- data/lib/airbrake-ruby/grouppable.rb +12 -0
- data/lib/airbrake-ruby/ignorable.rb +1 -0
- data/lib/airbrake-ruby/inspectable.rb +2 -2
- data/lib/airbrake-ruby/loggable.rb +2 -2
- data/lib/airbrake-ruby/mergeable.rb +12 -0
- data/lib/airbrake-ruby/monotonic_time.rb +48 -0
- data/lib/airbrake-ruby/notice.rb +10 -20
- data/lib/airbrake-ruby/notice_notifier.rb +23 -42
- data/lib/airbrake-ruby/performance_breakdown.rb +52 -0
- data/lib/airbrake-ruby/performance_notifier.rb +126 -49
- data/lib/airbrake-ruby/promise.rb +1 -0
- data/lib/airbrake-ruby/query.rb +26 -11
- data/lib/airbrake-ruby/queue.rb +65 -0
- data/lib/airbrake-ruby/remote_settings/settings_data.rb +120 -0
- data/lib/airbrake-ruby/remote_settings.rb +145 -0
- data/lib/airbrake-ruby/request.rb +20 -6
- data/lib/airbrake-ruby/stashable.rb +15 -0
- data/lib/airbrake-ruby/stat.rb +34 -24
- data/lib/airbrake-ruby/sync_sender.rb +3 -2
- data/lib/airbrake-ruby/tdigest.rb +43 -58
- data/lib/airbrake-ruby/thread_pool.rb +138 -0
- data/lib/airbrake-ruby/timed_trace.rb +58 -0
- data/lib/airbrake-ruby/truncator.rb +10 -4
- data/lib/airbrake-ruby/version.rb +11 -1
- data/lib/airbrake-ruby.rb +219 -53
- data/spec/airbrake_spec.rb +428 -9
- data/spec/async_sender_spec.rb +26 -110
- data/spec/backtrace_spec.rb +44 -44
- data/spec/benchmark_spec.rb +33 -0
- data/spec/code_hunk_spec.rb +11 -11
- data/spec/config/processor_spec.rb +209 -0
- data/spec/config/validator_spec.rb +23 -6
- data/spec/config_spec.rb +77 -7
- data/spec/deploy_notifier_spec.rb +2 -2
- data/spec/{file_cache.rb → file_cache_spec.rb} +2 -4
- data/spec/filter_chain_spec.rb +28 -1
- data/spec/filters/dependency_filter_spec.rb +1 -1
- data/spec/filters/gem_root_filter_spec.rb +9 -9
- data/spec/filters/git_last_checkout_filter_spec.rb +21 -4
- data/spec/filters/git_repository_filter.rb +1 -1
- data/spec/filters/git_revision_filter_spec.rb +13 -11
- data/spec/filters/{keys_whitelist_spec.rb → keys_allowlist_spec.rb} +29 -28
- data/spec/filters/{keys_blacklist_spec.rb → keys_blocklist_spec.rb} +39 -29
- data/spec/filters/root_directory_filter_spec.rb +9 -9
- data/spec/filters/sql_filter_spec.rb +110 -55
- data/spec/filters/system_exit_filter_spec.rb +1 -1
- data/spec/filters/thread_filter_spec.rb +33 -31
- data/spec/fixtures/project_root/code.rb +9 -9
- data/spec/loggable_spec.rb +17 -0
- data/spec/monotonic_time_spec.rb +23 -0
- data/spec/{notice_notifier_spec → notice_notifier}/options_spec.rb +19 -21
- data/spec/notice_notifier_spec.rb +20 -80
- data/spec/notice_spec.rb +9 -11
- data/spec/performance_breakdown_spec.rb +11 -0
- data/spec/performance_notifier_spec.rb +360 -85
- data/spec/query_spec.rb +11 -0
- data/spec/queue_spec.rb +18 -0
- data/spec/remote_settings/settings_data_spec.rb +365 -0
- data/spec/remote_settings_spec.rb +230 -0
- data/spec/request_spec.rb +9 -0
- data/spec/response_spec.rb +8 -8
- data/spec/spec_helper.rb +9 -13
- data/spec/stashable_spec.rb +23 -0
- data/spec/stat_spec.rb +17 -15
- data/spec/sync_sender_spec.rb +14 -12
- data/spec/tdigest_spec.rb +6 -6
- data/spec/thread_pool_spec.rb +187 -0
- data/spec/timed_trace_spec.rb +125 -0
- data/spec/truncator_spec.rb +12 -12
- metadata +55 -18
@@ -27,6 +27,7 @@ module Airbrake
|
|
27
27
|
@git_path = File.join(root_directory, '.git')
|
28
28
|
@weight = 116
|
29
29
|
@last_checkout = nil
|
30
|
+
@deploy_username = ENV['AIRBRAKE_DEPLOY_USERNAME']
|
30
31
|
end
|
31
32
|
|
32
33
|
# @macro call_filter
|
@@ -40,32 +41,31 @@ module Airbrake
|
|
40
41
|
|
41
42
|
return unless File.exist?(@git_path)
|
42
43
|
return unless (checkout = last_checkout)
|
44
|
+
|
43
45
|
notice[:context][:lastCheckout] = checkout
|
44
46
|
end
|
45
47
|
|
46
48
|
private
|
47
49
|
|
48
|
-
# rubocop:disable Metrics/AbcSize
|
49
50
|
def last_checkout
|
50
51
|
return unless (line = last_checkout_line)
|
51
52
|
|
52
53
|
parts = line.chomp.split("\t").first.split(' ')
|
53
54
|
if parts.size < MIN_HEAD_COLS
|
54
55
|
logger.error(
|
55
|
-
"#{LOG_LABEL} Airbrake::#{self.class.name}: can't parse line: #{line}"
|
56
|
+
"#{LOG_LABEL} Airbrake::#{self.class.name}: can't parse line: #{line}",
|
56
57
|
)
|
57
58
|
return
|
58
59
|
end
|
59
60
|
|
60
61
|
author = parts[2..-4]
|
61
62
|
@last_checkout = {
|
62
|
-
username: author[0..1].join(' '),
|
63
|
+
username: @deploy_username || author[0..1].join(' '),
|
63
64
|
email: parts[-3][1..-2],
|
64
65
|
revision: parts[1],
|
65
|
-
time: timestamp(parts[-2].to_i)
|
66
|
+
time: timestamp(parts[-2].to_i),
|
66
67
|
}
|
67
68
|
end
|
68
|
-
# rubocop:enable Metrics/AbcSize
|
69
69
|
|
70
70
|
def last_checkout_line
|
71
71
|
head_path = File.join(@git_path, 'logs', 'HEAD')
|
@@ -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
|
|
@@ -39,6 +40,7 @@ module Airbrake
|
|
39
40
|
end
|
40
41
|
|
41
42
|
return unless @repository
|
43
|
+
|
42
44
|
notice[:context][:repository] = @repository
|
43
45
|
end
|
44
46
|
|
@@ -46,6 +48,7 @@ module Airbrake
|
|
46
48
|
|
47
49
|
def detect_git_version
|
48
50
|
return unless which('git')
|
51
|
+
|
49
52
|
Gem::Version.new(`git --version`.split[2])
|
50
53
|
end
|
51
54
|
|
@@ -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)
|
@@ -4,7 +4,7 @@ module Airbrake
|
|
4
4
|
# notice, but specified keys.
|
5
5
|
#
|
6
6
|
# @example
|
7
|
-
# filter = Airbrake::Filters::
|
7
|
+
# filter = Airbrake::Filters::KeysAllowlist.new(
|
8
8
|
# [:email, /credit/i, 'password']
|
9
9
|
# )
|
10
10
|
# airbrake.add_filter(filter)
|
@@ -22,9 +22,9 @@ module Airbrake
|
|
22
22
|
# # email: 'john@example.com',
|
23
23
|
# # account_id: 42 }
|
24
24
|
#
|
25
|
-
# @see
|
25
|
+
# @see KeysBlocklist
|
26
26
|
# @see KeysFilter
|
27
|
-
class
|
27
|
+
class KeysAllowlist
|
28
28
|
include KeysFilter
|
29
29
|
|
30
30
|
def initialize(*)
|
@@ -4,7 +4,7 @@ module Airbrake
|
|
4
4
|
# list of parameters in the payload of a notice.
|
5
5
|
#
|
6
6
|
# @example
|
7
|
-
# filter = Airbrake::Filters::
|
7
|
+
# filter = Airbrake::Filters::KeysBlocklist.new(
|
8
8
|
# [:email, /credit/i, 'password']
|
9
9
|
# )
|
10
10
|
# airbrake.add_filter(filter)
|
@@ -22,10 +22,10 @@ module Airbrake
|
|
22
22
|
# # email: '[Filtered]',
|
23
23
|
# # credit_card: '[Filtered]' }
|
24
24
|
#
|
25
|
-
# @see
|
25
|
+
# @see KeysAllowlist
|
26
26
|
# @see KeysFilter
|
27
27
|
# @api private
|
28
|
-
class
|
28
|
+
class KeysBlocklist
|
29
29
|
include KeysFilter
|
30
30
|
|
31
31
|
def initialize(*)
|
@@ -7,8 +7,8 @@ module Airbrake
|
|
7
7
|
# class that includes this module must implement.
|
8
8
|
#
|
9
9
|
# @see Notice
|
10
|
-
# @see
|
11
|
-
# @see
|
10
|
+
# @see KeysAllowlist
|
11
|
+
# @see KeysBlocklist
|
12
12
|
# @api private
|
13
13
|
module KeysFilter
|
14
14
|
# @return [String] The label to replace real values of filtered payload
|
@@ -19,19 +19,30 @@ module Airbrake
|
|
19
19
|
VALID_PATTERN_CLASSES = [String, Symbol, Regexp].freeze
|
20
20
|
|
21
21
|
# @return [Array<Symbol>] parts of a Notice's payload that can be modified
|
22
|
-
# by
|
22
|
+
# by blocklist/allowlist filters
|
23
23
|
FILTERABLE_KEYS = %i[environment session params].freeze
|
24
24
|
|
25
25
|
# @return [Array<Symbol>] parts of a Notice's *context* payload that can
|
26
|
-
# be modified by
|
27
|
-
FILTERABLE_CONTEXT_KEYS = %i[
|
26
|
+
# be modified by blocklist/allowlist filters
|
27
|
+
FILTERABLE_CONTEXT_KEYS = %i[
|
28
|
+
user
|
29
|
+
|
30
|
+
# Provided by Airbrake::Rack::HttpHeadersFilter
|
31
|
+
headers
|
32
|
+
referer
|
33
|
+
httpMethod
|
34
|
+
|
35
|
+
# Provided by Airbrake::Rack::ContextFilter
|
36
|
+
userAddr
|
37
|
+
userAgent
|
38
|
+
].freeze
|
28
39
|
|
29
40
|
include Loggable
|
30
41
|
|
31
42
|
# @return [Integer]
|
32
43
|
attr_reader :weight
|
33
44
|
|
34
|
-
# Creates a new
|
45
|
+
# Creates a new KeysBlocklist or KeysAllowlist filter that uses the given
|
35
46
|
# +patterns+ for filtering a notice's payload.
|
36
47
|
#
|
37
48
|
# @param [Array<String,Regexp,Symbol>] patterns
|
@@ -53,10 +64,14 @@ module Airbrake
|
|
53
64
|
validate_patterns
|
54
65
|
end
|
55
66
|
|
56
|
-
FILTERABLE_KEYS.each
|
67
|
+
FILTERABLE_KEYS.each do |key|
|
68
|
+
notice[key] = filter_hash(notice[key])
|
69
|
+
end
|
70
|
+
|
57
71
|
FILTERABLE_CONTEXT_KEYS.each { |key| filter_context_key(notice, key) }
|
58
72
|
|
59
73
|
return unless notice[:context][:url]
|
74
|
+
|
60
75
|
filter_url(notice)
|
61
76
|
end
|
62
77
|
|
@@ -70,26 +85,26 @@ module Airbrake
|
|
70
85
|
def filter_hash(hash)
|
71
86
|
return hash unless hash.is_a?(Hash)
|
72
87
|
|
88
|
+
hash_copy = hash.dup
|
89
|
+
|
73
90
|
hash.each_key do |key|
|
74
91
|
if should_filter?(key.to_s)
|
75
|
-
|
76
|
-
elsif
|
77
|
-
filter_hash(
|
92
|
+
hash_copy[key] = FILTERED
|
93
|
+
elsif hash_copy[key].is_a?(Hash)
|
94
|
+
hash_copy[key] = filter_hash(hash_copy[key])
|
78
95
|
elsif hash[key].is_a?(Array)
|
79
|
-
|
96
|
+
hash_copy[key].each_with_index do |h, i|
|
97
|
+
hash_copy[key][i] = filter_hash(h)
|
98
|
+
end
|
80
99
|
end
|
81
100
|
end
|
101
|
+
|
102
|
+
hash_copy
|
82
103
|
end
|
83
104
|
|
84
105
|
def filter_url_params(url)
|
85
106
|
url.query = Hash[URI.decode_www_form(url.query)].map do |key, val|
|
86
|
-
|
87
|
-
# invalid characters, so be sure to escape individual components.
|
88
|
-
if should_filter?(key)
|
89
|
-
"#{URI.encode_www_form_component(key)}=[Filtered]"
|
90
|
-
else
|
91
|
-
"#{URI.encode_www_form_component(key)}=#{URI.encode_www_form_component(val)}"
|
92
|
-
end
|
107
|
+
should_filter?(key) ? "#{key}=[Filtered]" : "#{key}=#{val}"
|
93
108
|
end.join('&')
|
94
109
|
|
95
110
|
url.to_s
|
@@ -103,6 +118,7 @@ module Airbrake
|
|
103
118
|
end
|
104
119
|
|
105
120
|
return unless url.query
|
121
|
+
|
106
122
|
notice[:context][:url] = filter_url_params(url)
|
107
123
|
end
|
108
124
|
|
@@ -111,6 +127,7 @@ module Airbrake
|
|
111
127
|
|
112
128
|
@patterns = @patterns.flat_map do |pattern|
|
113
129
|
next(pattern) unless pattern.respond_to?(:call)
|
130
|
+
|
114
131
|
pattern.call
|
115
132
|
end
|
116
133
|
end
|
@@ -124,14 +141,16 @@ module Airbrake
|
|
124
141
|
|
125
142
|
logger.error(
|
126
143
|
"#{LOG_LABEL} one of the patterns in #{self.class} is invalid. " \
|
127
|
-
"Known patterns: #{@patterns}"
|
144
|
+
"Known patterns: #{@patterns}",
|
128
145
|
)
|
129
146
|
end
|
130
147
|
|
131
148
|
def filter_context_key(notice, key)
|
132
149
|
return unless notice[:context][key]
|
133
150
|
return if notice[:context][key] == FILTERED
|
134
|
-
|
151
|
+
unless should_filter?(key)
|
152
|
+
return notice[:context][key] = filter_hash(notice[:context][key])
|
153
|
+
end
|
135
154
|
|
136
155
|
notice[:context][key] = FILTERED
|
137
156
|
end
|
@@ -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,10 +33,14 @@ 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
|
+
# @return [Regexp] the regexp that is applied after the feature regexps
|
41
|
+
# were used
|
42
|
+
POST_FILTER = /(?<=[values|in ]\().+(?=\))/i.freeze
|
43
|
+
|
40
44
|
# @return [Hash{Symbol=>Array<Symbol>}] a set of features that corresponds
|
41
45
|
# to a certain dialect
|
42
46
|
DIALECT_FEATURES = {
|
@@ -60,7 +64,7 @@ module Airbrake
|
|
60
64
|
cassandra: %i[
|
61
65
|
single_quotes uuids numeric_literals boolean_literals
|
62
66
|
hexadecimal_literals comments multi_line_comments
|
63
|
-
].freeze
|
67
|
+
].freeze,
|
64
68
|
}.freeze
|
65
69
|
|
66
70
|
# @return [Hash{Symbol=>Regexp}] a set of regexps to check for unmatches
|
@@ -72,9 +76,22 @@ module Airbrake
|
|
72
76
|
sqlite: %r{'|/\*|\*/},
|
73
77
|
cassandra: %r{'|/\*|\*/},
|
74
78
|
oracle: %r{'|/\*|\*/},
|
75
|
-
oracle_enhanced: %r{'|/\*|\*/}
|
79
|
+
oracle_enhanced: %r{'|/\*|\*/},
|
76
80
|
}.freeze
|
77
81
|
|
82
|
+
# @return [Array<Regexp>] the list of queries to be ignored
|
83
|
+
IGNORED_QUERIES = [
|
84
|
+
/\ACOMMIT/i,
|
85
|
+
/\ABEGIN/i,
|
86
|
+
/\ASET/i,
|
87
|
+
/\ASHOW/i,
|
88
|
+
/\AWITH/i,
|
89
|
+
/FROM pg_attribute/i,
|
90
|
+
/FROM pg_index/i,
|
91
|
+
/FROM pg_class/i,
|
92
|
+
/FROM pg_type/i,
|
93
|
+
].freeze
|
94
|
+
|
78
95
|
def initialize(dialect)
|
79
96
|
@dialect =
|
80
97
|
case dialect
|
@@ -95,7 +112,14 @@ module Airbrake
|
|
95
112
|
def call(resource)
|
96
113
|
return unless resource.respond_to?(:query)
|
97
114
|
|
98
|
-
|
115
|
+
query = resource.query
|
116
|
+
if IGNORED_QUERIES.any? { |q| q =~ query }
|
117
|
+
resource.ignore!
|
118
|
+
return
|
119
|
+
end
|
120
|
+
|
121
|
+
q = query.gsub(@regexp, FILTERED)
|
122
|
+
q.gsub!(POST_FILTER, FILTERED) if q =~ POST_FILTER
|
99
123
|
q = ERROR_MSG if UNMATCHED_PAIR[@dialect] =~ q
|
100
124
|
resource.query = q
|
101
125
|
end
|
@@ -16,7 +16,7 @@ module Airbrake
|
|
16
16
|
String,
|
17
17
|
Symbol,
|
18
18
|
Regexp,
|
19
|
-
Numeric
|
19
|
+
Numeric,
|
20
20
|
].freeze
|
21
21
|
|
22
22
|
# Variables starting with this prefix are not attached to a notice.
|
@@ -56,6 +56,7 @@ module Airbrake
|
|
56
56
|
def thread_variables(th)
|
57
57
|
th.thread_variables.map.with_object({}) do |var, h|
|
58
58
|
next if var.to_s.start_with?(IGNORE_PREFIX)
|
59
|
+
|
59
60
|
h[var] = sanitize_value(th.thread_variable_get(var))
|
60
61
|
end
|
61
62
|
end
|
@@ -63,6 +64,7 @@ module Airbrake
|
|
63
64
|
def fiber_variables(th)
|
64
65
|
th.keys.map.with_object({}) do |key, h|
|
65
66
|
next if key.to_s.start_with?(IGNORE_PREFIX)
|
67
|
+
|
66
68
|
h[key] = sanitize_value(th[key])
|
67
69
|
end
|
68
70
|
end
|
@@ -72,7 +74,7 @@ module Airbrake
|
|
72
74
|
thread_info[:group] = th.group.list.map(&:inspect)
|
73
75
|
thread_info[:priority] = th.priority
|
74
76
|
|
75
|
-
thread_info[:safe_level] = th.safe_level
|
77
|
+
thread_info[:safe_level] = th.safe_level if Airbrake::HAS_SAFE_LEVEL
|
76
78
|
end
|
77
79
|
|
78
80
|
def sanitize_value(value)
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Airbrake
|
2
|
+
# Grouppable adds the `#groups` method, so that we don't need to define it in
|
3
|
+
# all of performance models every time we add a model without groups.
|
4
|
+
#
|
5
|
+
# @since 4.9.0
|
6
|
+
# @api private
|
7
|
+
module Grouppable
|
8
|
+
def groups
|
9
|
+
{}
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -21,7 +21,7 @@ module Airbrake
|
|
21
21
|
project_id: @config.project_id,
|
22
22
|
project_key: @config.project_key,
|
23
23
|
host: @config.host,
|
24
|
-
filter_chain: @filter_chain.inspect
|
24
|
+
filter_chain: @filter_chain.inspect,
|
25
25
|
)
|
26
26
|
end
|
27
27
|
|
@@ -30,7 +30,7 @@ module Airbrake
|
|
30
30
|
q.text("#<#{self.class}:0x#{(object_id << 1).to_s(16).rjust(16, '0')} ")
|
31
31
|
q.text(
|
32
32
|
"project_id=\"#{@config.project_id}\" project_key=\"#{@config.project_key}\" " \
|
33
|
-
"host=\"#{@config.host}\" filter_chain="
|
33
|
+
"host=\"#{@config.host}\" filter_chain=",
|
34
34
|
)
|
35
35
|
q.pp(@filter_chain)
|
36
36
|
q.text('>')
|
@@ -17,12 +17,12 @@ module Airbrake
|
|
17
17
|
# @api private
|
18
18
|
module Loggable
|
19
19
|
class << self
|
20
|
-
# @
|
20
|
+
# @return [Logger]
|
21
21
|
attr_writer :instance
|
22
22
|
|
23
23
|
# @return [Logger]
|
24
24
|
def instance
|
25
|
-
@instance ||= ::Logger.new(File::NULL)
|
25
|
+
@instance ||= ::Logger.new(File::NULL).tap { |l| l.level = ::Logger::WARN }
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Airbrake
|
2
|
+
# MonotonicTime is a helper for getting monotonic time suitable for
|
3
|
+
# performance measurements. It guarantees that the time is strictly linearly
|
4
|
+
# increasing (unlike realtime).
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# MonotonicTime.time_in_ms #=> 287138801.144576
|
8
|
+
#
|
9
|
+
# @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html
|
10
|
+
# @since v4.2.4
|
11
|
+
# @api private
|
12
|
+
module MonotonicTime
|
13
|
+
class << self
|
14
|
+
# @return [Integer] current monotonic time in milliseconds
|
15
|
+
def time_in_ms
|
16
|
+
time_in_nanoseconds / (10.0**6)
|
17
|
+
end
|
18
|
+
|
19
|
+
# @return [Integer] current monotonic time in seconds
|
20
|
+
def time_in_s
|
21
|
+
time_in_nanoseconds / (10.0**9)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
if defined?(Process::CLOCK_MONOTONIC)
|
27
|
+
|
28
|
+
def time_in_nanoseconds
|
29
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC, :nanosecond)
|
30
|
+
end
|
31
|
+
|
32
|
+
elsif RUBY_ENGINE == 'jruby'
|
33
|
+
|
34
|
+
def time_in_nanoseconds
|
35
|
+
java.lang.System.nanoTime
|
36
|
+
end
|
37
|
+
|
38
|
+
else
|
39
|
+
|
40
|
+
def time_in_nanoseconds
|
41
|
+
time = Time.now
|
42
|
+
time.to_i * (10**9) + time.nsec
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
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
|
@@ -32,7 +25,7 @@ module Airbrake
|
|
32
25
|
IOError,
|
33
26
|
NotImplementedError,
|
34
27
|
JSON::GeneratorError,
|
35
|
-
Encoding::UndefinedConversionError
|
28
|
+
Encoding::UndefinedConversionError,
|
36
29
|
].freeze
|
37
30
|
|
38
31
|
# @return [Array<Symbol>] the list of keys that can be be overwritten with
|
@@ -51,11 +44,7 @@ module Airbrake
|
|
51
44
|
|
52
45
|
include Ignorable
|
53
46
|
include Loggable
|
54
|
-
|
55
|
-
# @since v1.7.0
|
56
|
-
# @return [Hash{Symbol=>Object}] the hash with arbitrary objects to be used
|
57
|
-
# in filters
|
58
|
-
attr_reader :stash
|
47
|
+
include Stashable
|
59
48
|
|
60
49
|
# @api private
|
61
50
|
def initialize(exception, params = {})
|
@@ -64,13 +53,14 @@ module Airbrake
|
|
64
53
|
errors: NestedException.new(exception).as_json,
|
65
54
|
context: context,
|
66
55
|
environment: {
|
67
|
-
program_name: $PROGRAM_NAME
|
56
|
+
program_name: $PROGRAM_NAME,
|
68
57
|
},
|
69
58
|
session: {},
|
70
|
-
params: params
|
59
|
+
params: params,
|
71
60
|
}
|
72
|
-
@stash = { exception: exception }
|
73
61
|
@truncator = Airbrake::Truncator.new(PAYLOAD_MAX_SIZE)
|
62
|
+
|
63
|
+
stash[:exception] = exception
|
74
64
|
end
|
75
65
|
|
76
66
|
# Converts the notice to JSON. Calls +to_json+ on each object inside
|
@@ -79,7 +69,7 @@ module Airbrake
|
|
79
69
|
#
|
80
70
|
# @return [Hash{String=>String}, nil]
|
81
71
|
# @api private
|
82
|
-
def to_json
|
72
|
+
def to_json(*_args)
|
83
73
|
loop do
|
84
74
|
begin
|
85
75
|
json = @payload.to_json
|
@@ -141,7 +131,7 @@ module Airbrake
|
|
141
131
|
# Make sure we always send hostname.
|
142
132
|
hostname: HOSTNAME,
|
143
133
|
|
144
|
-
severity: DEFAULT_SEVERITY
|
134
|
+
severity: DEFAULT_SEVERITY,
|
145
135
|
}.merge(CONTEXT).delete_if { |_key, val| val.nil? || val.empty? }
|
146
136
|
end
|
147
137
|
|
@@ -155,7 +145,7 @@ module Airbrake
|
|
155
145
|
logger.error(
|
156
146
|
"#{LOG_LABEL} truncation failed. File an issue at " \
|
157
147
|
"https://github.com/airbrake/airbrake-ruby " \
|
158
|
-
"and attach the following payload: #{@payload}"
|
148
|
+
"and attach the following payload: #{@payload}",
|
159
149
|
)
|
160
150
|
end
|
161
151
|
|