airbrake-ruby 6.0.0 → 6.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f8371a959c69ffddca0dd25b6e8096450ecea66e13ddd6f6ace583eb37976516
4
- data.tar.gz: f769f0604e3dd7118df53cb6de2e3115beed43a898e9eefb5828174c29f16f67
3
+ metadata.gz: 2dfccc9b2cf013d06ad40e4b3726319c13bd09dcba70d9c1fa4b382c7d80b1b4
4
+ data.tar.gz: 63c8aa81c33948f26ead281e81769a274dbca9740880a420d62b4d951b352984
5
5
  SHA512:
6
- metadata.gz: ef094ddf119abfe8fd552980dbbc05ce907ed7608c12f7012fbcde1ee7861a33da67a435c8ef6fc378ef2490274050b7ccde598ac2a1f0f1098cd587c36b1222
7
- data.tar.gz: 737a3900b60024d24303d10277d89ab782f60c58cadeb8e7fef3b7da17e983c8dd0033724e3640fe07d3428f1f86952f65ef378f81547213c2a8b11a9271eaa7
6
+ metadata.gz: 694a9114eb130976c052748a51e0490b3276bf32fe347bf466e64caf68e26c703941cd131bb43a0b7f3b6c6c9580067feffd5c1d443a46319a09ec6d0d1f6a37
7
+ data.tar.gz: 59bf1fd79c2467401aabc0c352397d82bae83805cb54ccac40c5ca132dfcfdefa5281a8ba11dc96f67d569405837af61aeb05a22ce9e2f3425d0ecc4a1c69251
@@ -43,8 +43,14 @@ module Airbrake
43
43
  def process_remote_configuration
44
44
  return unless @config.remote_config
45
45
  return unless @project_id
46
+
47
+ # Never poll remote configuration in the test environment.
46
48
  return if @config.environment == 'test'
47
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
+
48
54
  RemoteSettings.poll(@project_id, @config.remote_config_host) do |data|
49
55
  @poll_callback.call(data)
50
56
  end
@@ -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(resource)
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 resource.is_a?(Airbrake::Query) && !query_stats
256
+ elsif metric.is_a?(Airbrake::Query) && !query_stats
257
257
  promise.reject("The Query Stats feature is disabled")
258
- elsif resource.is_a?(Airbrake::Queue) && !job_stats
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
@@ -72,7 +72,7 @@ module Airbrake
72
72
  return unless File.exist?(head_path)
73
73
 
74
74
  last_line = nil
75
- IO.foreach(head_path) do |line|
75
+ File.foreach(head_path) do |line|
76
76
  last_line = line if checkout_line?(line)
77
77
  end
78
78
  last_line
@@ -49,7 +49,13 @@ module Airbrake
49
49
  def detect_git_version
50
50
  return unless which('git')
51
51
 
52
- Gem::Version.new(`git --version`.split[2])
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
53
59
  end
54
60
 
55
61
  # Cross-platform way to tell if an executable is accessible.
@@ -108,20 +108,20 @@ module Airbrake
108
108
  @regexp = Regexp.union(features)
109
109
  end
110
110
 
111
- # @param [Airbrake::Query] resource
112
- def call(resource)
113
- return unless resource.respond_to?(:query)
111
+ # @param [Airbrake::Query] metric
112
+ def call(metric)
113
+ return unless metric.respond_to?(:query)
114
114
 
115
- query = resource.query
115
+ query = metric.query
116
116
  if IGNORED_QUERIES.any? { |q| q =~ query }
117
- resource.ignore!
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
- resource.query = q
124
+ metric.query = q
125
125
  end
126
126
  end
127
127
  end
@@ -1,6 +1,6 @@
1
1
  module Airbrake
2
- # QueryNotifier aggregates information about SQL queries and periodically sends
3
- # collected data to Airbrake.
2
+ # PerformanceNotifier aggregates performance data and periodically sends it to
3
+ # Airbrake.
4
4
  #
5
5
  # @api public
6
6
  # @since v3.2.0
@@ -21,20 +21,20 @@ module Airbrake
21
21
  @has_payload = @payload.new_cond
22
22
  end
23
23
 
24
- # @param [Hash] resource
24
+ # @param [Hash] metric
25
25
  # @see Airbrake.notify_query
26
26
  # @see Airbrake.notify_request
27
- def notify(resource)
27
+ def notify(metric)
28
28
  @payload.synchronize do
29
- send_resource(resource, sync: false)
29
+ send_metric(metric, sync: false)
30
30
  end
31
31
  end
32
32
 
33
- # @param [Hash] resource
33
+ # @param [Hash] metric
34
34
  # @since v4.10.0
35
35
  # @see Airbrake.notify_queue_sync
36
- def notify_sync(resource)
37
- send_resource(resource, sync: true).value
36
+ def notify_sync(metric)
37
+ send_metric(metric, sync: true).value
38
38
  end
39
39
 
40
40
  # @see Airbrake.add_performance_filter
@@ -78,16 +78,16 @@ module Airbrake
78
78
  end
79
79
  end
80
80
 
81
- def send_resource(resource, sync:)
82
- promise = check_configuration(resource)
81
+ def send_metric(metric, sync:)
82
+ promise = check_configuration(metric)
83
83
  return promise if promise.rejected?
84
84
 
85
- @filter_chain.refine(resource)
86
- if resource.ignored?
87
- return Promise.new.reject("#{resource.class} was ignored by a filter")
85
+ @filter_chain.refine(metric)
86
+ if metric.ignored?
87
+ return Promise.new.reject("#{metric.class} was ignored by a filter")
88
88
  end
89
89
 
90
- update_payload(resource)
90
+ update_payload(metric)
91
91
  if sync || @flush_period == 0
92
92
  send(@sync_sender, @payload, promise)
93
93
  else
@@ -96,29 +96,29 @@ module Airbrake
96
96
  end
97
97
  end
98
98
 
99
- def update_payload(resource)
100
- if (total_stat = @payload[resource])
101
- @payload.key(total_stat).merge(resource)
99
+ def update_payload(metric)
100
+ if (total_stat = @payload[metric])
101
+ @payload.key(total_stat).merge(metric)
102
102
  else
103
- @payload[resource] = { total: Airbrake::Stat.new }
103
+ @payload[metric] = { total: Airbrake::Stat.new }
104
104
  end
105
105
 
106
- @payload[resource][:total].increment_ms(resource.timing)
106
+ @payload[metric][:total].increment_ms(metric.timing)
107
107
 
108
- resource.groups.each do |name, ms|
109
- @payload[resource][name] ||= Airbrake::Stat.new
110
- @payload[resource][name].increment_ms(ms)
108
+ metric.groups.each do |name, ms|
109
+ @payload[metric][name] ||= Airbrake::Stat.new
110
+ @payload[metric][name].increment_ms(ms)
111
111
  end
112
112
  end
113
113
 
114
- def check_configuration(resource)
114
+ def check_configuration(metric)
115
115
  promise = @config.check_configuration
116
116
  return promise if promise.rejected?
117
117
 
118
- promise = @config.check_performance_options(resource)
118
+ promise = @config.check_performance_options(metric)
119
119
  return promise if promise.rejected?
120
120
 
121
- if resource.timing && resource.timing == 0
121
+ if metric.timing && metric.timing == 0
122
122
  return Promise.new.reject(':timing cannot be zero')
123
123
  end
124
124
 
@@ -128,47 +128,47 @@ module Airbrake
128
128
  def send(sender, payload, promise)
129
129
  raise "payload cannot be empty. Race?" if payload.none?
130
130
 
131
- with_grouped_payload(payload) do |resource_hash, destination|
131
+ with_grouped_payload(payload) do |metric_hash, destination|
132
132
  url = URI.join(
133
133
  @config.apm_host,
134
134
  "api/v5/projects/#{@config.project_id}/#{destination}",
135
135
  )
136
136
 
137
137
  logger.debug do
138
- "#{LOG_LABEL} #{self.class.name}##{__method__}: #{resource_hash}"
138
+ "#{LOG_LABEL} #{self.class.name}##{__method__}: #{metric_hash}"
139
139
  end
140
- sender.send(resource_hash, promise, url)
140
+ sender.send(metric_hash, promise, url)
141
141
  end
142
142
 
143
143
  promise
144
144
  end
145
145
 
146
146
  def with_grouped_payload(raw_payload)
147
- grouped_payload = raw_payload.group_by do |resource, _stats|
148
- [resource.cargo, resource.destination]
147
+ grouped_payload = raw_payload.group_by do |metric, _stats|
148
+ [metric.cargo, metric.destination]
149
149
  end
150
150
 
151
- grouped_payload.each do |(cargo, destination), resources|
151
+ grouped_payload.each do |(cargo, destination), metrics|
152
152
  payload = {}
153
- payload[cargo] = serialize_resources(resources)
153
+ payload[cargo] = serialize_metrics(metrics)
154
154
  payload['environment'] = @config.environment if @config.environment
155
155
 
156
156
  yield(payload, destination)
157
157
  end
158
158
  end
159
159
 
160
- def serialize_resources(resources)
161
- resources.map do |resource, stats|
162
- resource_hash = resource.to_h.merge!(stats[:total].to_h)
160
+ def serialize_metrics(metrics)
161
+ metrics.map do |metric, stats|
162
+ metric_hash = metric.to_h.merge!(stats[:total].to_h)
163
163
 
164
- if resource.groups.any?
164
+ if metric.groups.any?
165
165
  group_stats = stats.reject { |name, _stat| name == :total }
166
- resource_hash['groups'] = group_stats.merge(group_stats) do |_name, stat|
166
+ metric_hash['groups'] = group_stats.merge(group_stats) do |_name, stat|
167
167
  stat.to_h
168
168
  end
169
169
  end
170
170
 
171
- resource_hash
171
+ metric_hash
172
172
  end
173
173
  end
174
174
  end
@@ -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 = Net::HTTP.get_response(build_config_uri)
82
+ response = https.request(req)
78
83
  rescue StandardError => ex
79
- logger.error(ex)
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
@@ -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 resource (route or query,
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
@@ -48,11 +48,11 @@ module Airbrake
48
48
  # false if the queue is full
49
49
  def <<(message)
50
50
  if backlog >= @queue_size
51
- logger.error(
51
+ logger.info do
52
52
  "#{LOG_LABEL} ThreadPool has reached its capacity of " \
53
53
  "#{@queue_size} and the following message will not be " \
54
- "processed: #{message.inspect}",
55
- )
54
+ "processed: #{message.inspect}"
55
+ end
56
56
  return false
57
57
  end
58
58
 
@@ -6,10 +6,10 @@ module Airbrake
6
6
  module TimeTruncate
7
7
  # Truncate +time+ to floor minute and turn it into an RFC3339 timestamp.
8
8
  #
9
- # @param [Time] time
9
+ # @param [Time, Integer, Float] time
10
10
  # @return [String]
11
11
  def self.utc_truncate_minutes(time)
12
- tm = time.getutc
12
+ tm = Time.at(time).getutc
13
13
 
14
14
  Time.utc(tm.year, tm.month, tm.day, tm.hour, tm.min).to_datetime.rfc3339
15
15
  end
@@ -3,7 +3,7 @@
3
3
  module Airbrake
4
4
  # @return [String] the library version
5
5
  # @api public
6
- AIRBRAKE_RUBY_VERSION = '6.0.0'.freeze
6
+ AIRBRAKE_RUBY_VERSION = '6.1.0'.freeze
7
7
 
8
8
  # @return [Hash{Symbol=>String}] the information about the notifier library
9
9
  # @since v5.0.0
data/lib/airbrake-ruby.rb CHANGED
@@ -364,23 +364,14 @@ module Airbrake
364
364
  # method: 'POST',
365
365
  # route: '/thing/:id/create',
366
366
  # status_code: 200,
367
- # func: 'do_stuff',
368
- # file: 'app/models/foo.rb',
369
- # line: 452,
370
367
  # timing: 123.45 # ms
371
368
  # )
372
369
  #
373
370
  # @param [Hash{Symbol=>Object}] request_info
374
371
  # @option request_info [String] :method The HTTP method that was invoked
375
372
  # @option request_info [String] :route The route that was invoked
376
- # @option request_info [Integer] :status_code The respose code that the
373
+ # @option request_info [Integer] :status_code The response code that the
377
374
  # route returned
378
- # @option request_info [String] :func The function that called the query
379
- # (optional)
380
- # @option request_info [String] :file The file that has the function that
381
- # called the query (optional)
382
- # @option request_info [Integer] :line The line that executes the query
383
- # (optional)
384
375
  # @option request_info [Float] :timing How much time it took to process the
385
376
  # request (in ms)
386
377
  # @param [Hash] stash What needs to be appeneded to the stash, so it's
@@ -415,6 +406,9 @@ module Airbrake
415
406
  # method: 'GET',
416
407
  # route: '/things',
417
408
  # query: 'SELECT * FROM things',
409
+ # func: 'do_stuff',
410
+ # file: 'app/models/foo.rb',
411
+ # line: 452,
418
412
  # timing: 123.45 # ms
419
413
  # )
420
414
  #
@@ -424,6 +418,12 @@ module Airbrake
424
418
  # @option query_info [String] :route The route that triggered this SQL
425
419
  # query (optional)
426
420
  # @option query_info [String] :query The query that was executed
421
+ # @option request_info [String] :func The function that called the query
422
+ # (optional)
423
+ # @option request_info [String] :file The file that has the function that
424
+ # called the query (optional)
425
+ # @option request_info [Integer] :line The line that executes the query
426
+ # (optional)
427
427
  # @option query_info [Float] :timing How much time it took to process the
428
428
  # query (in ms)
429
429
  # @param [Hash] stash What needs to be appeneded to the stash, so it's
@@ -451,7 +451,7 @@ module Airbrake
451
451
  # Increments performance breakdown statistics of a certain route.
452
452
  #
453
453
  # @example
454
- # Airbrake.notify_request(
454
+ # Airbrake.notify_performance_breakdown(
455
455
  # method: 'POST',
456
456
  # route: '/thing/:id/create',
457
457
  # response_type: 'json',
@@ -523,24 +523,24 @@ module Airbrake
523
523
  performance_notifier.notify_sync(queue)
524
524
  end
525
525
 
526
- # Runs a callback before {.notify_request} or {.notify_query} kicks in. This
527
- # is useful if you want to ignore specific resources or filter the data the
528
- # resource contains.
526
+ # Runs a callback before {.notify_request}, {.notify_query}, {.notify_queue}
527
+ # or {.notify_performance_breakdown} kicks in. This is useful if you want to
528
+ # ignore specific metrics or filter the data the metric contains.
529
529
  #
530
- # @example Ignore all resources
530
+ # @example Ignore all metrics
531
531
  # Airbrake.add_performance_filter(&:ignore!)
532
532
  # @example Filter sensitive data
533
- # Airbrake.add_performance_filter do |resource|
534
- # case resource
533
+ # Airbrake.add_performance_filter do |metric|
534
+ # case metric
535
535
  # when Airbrake::Query
536
- # resource.route = '[Filtered]'
536
+ # metric.route = '[Filtered]'
537
537
  # when Airbrake::Request
538
- # resource.query = '[Filtered]'
538
+ # metric.query = '[Filtered]'
539
539
  # end
540
540
  # end
541
541
  # @example Filter with help of a class
542
542
  # class MyFilter
543
- # def call(resource)
543
+ # def call(metric)
544
544
  # # ...
545
545
  # end
546
546
  # end
@@ -548,7 +548,7 @@ module Airbrake
548
548
  # Airbrake.add_performance_filter(MyFilter.new)
549
549
  #
550
550
  # @param [#call] filter The filter object
551
- # @yield [resource] The resource to filter
551
+ # @yield [metric] The metric to filter
552
552
  # @yieldparam [Airbrake::Query, Airbrake::Request]
553
553
  # @yieldreturn [void]
554
554
  # @return [void]
@@ -11,13 +11,13 @@ RSpec.describe Airbrake::Benchmark do
11
11
  before { benchmark }
12
12
 
13
13
  context "when called one time" do
14
- its(:stop) { is_expected.to eq(true) }
14
+ its(:stop) { is_expected.to be(true) }
15
15
  end
16
16
 
17
17
  context "when called twice or more" do
18
18
  before { benchmark.stop }
19
19
 
20
- its(:stop) { is_expected.to eq(false) }
20
+ its(:stop) { is_expected.to be(false) }
21
21
  end
22
22
  end
23
23
 
@@ -7,7 +7,7 @@ RSpec.describe Airbrake::Config::Processor do
7
7
  context "when there ARE blocklist keys" do
8
8
  it "adds the blocklist filter" do
9
9
  described_class.new(config).process_blocklist(notifier)
10
- expect(notifier.has_filter?(Airbrake::Filters::KeysBlocklist)).to eq(true)
10
+ expect(notifier.has_filter?(Airbrake::Filters::KeysBlocklist)).to be(true)
11
11
  end
12
12
  end
13
13
 
@@ -17,7 +17,7 @@ RSpec.describe Airbrake::Config::Processor do
17
17
  it "doesn't add the blocklist filter" do
18
18
  described_class.new(config).process_blocklist(notifier)
19
19
  expect(notifier.has_filter?(Airbrake::Filters::KeysBlocklist))
20
- .to eq(false)
20
+ .to be(false)
21
21
  end
22
22
  end
23
23
  end
@@ -28,7 +28,7 @@ RSpec.describe Airbrake::Config::Processor do
28
28
  context "when there ARE allowlist keys" do
29
29
  it "adds the allowlist filter" do
30
30
  described_class.new(config).process_allowlist(notifier)
31
- expect(notifier.has_filter?(Airbrake::Filters::KeysAllowlist)).to eq(true)
31
+ expect(notifier.has_filter?(Airbrake::Filters::KeysAllowlist)).to be(true)
32
32
  end
33
33
  end
34
34
 
@@ -38,7 +38,7 @@ RSpec.describe Airbrake::Config::Processor do
38
38
  it "doesn't add the allowlist filter" do
39
39
  described_class.new(config).process_allowlist(notifier)
40
40
  expect(notifier.has_filter?(Airbrake::Filters::KeysAllowlist))
41
- .to eq(false)
41
+ .to be(false)
42
42
  end
43
43
  end
44
44
  end
@@ -68,6 +68,22 @@ RSpec.describe Airbrake::Config::Processor do
68
68
  end
69
69
  end
70
70
 
71
+ context "when the config sets :ignore_environments and :environment matches" do
72
+ let(:config) do
73
+ Airbrake::Config.new(
74
+ project_id: 123,
75
+ ignore_environments: %w[dev],
76
+ environment: 'dev',
77
+ )
78
+ end
79
+
80
+ it "doesn't set remote settings" do
81
+ described_class.new(config).process_remote_configuration
82
+
83
+ expect(Airbrake::RemoteSettings).not_to have_received(:poll)
84
+ end
85
+ end
86
+
71
87
  context "when the config defines a project_id" do
72
88
  let(:config) do
73
89
  Airbrake::Config.new(project_id: 123, environment: 'not-test')
@@ -98,25 +114,25 @@ RSpec.describe Airbrake::Config::Processor do
98
114
  it "adds RootDirectoryFilter" do
99
115
  described_class.new(config).add_filters(notifier)
100
116
  expect(notifier.has_filter?(Airbrake::Filters::RootDirectoryFilter))
101
- .to eq(true)
117
+ .to be(true)
102
118
  end
103
119
 
104
120
  it "adds GitRevisionFilter" do
105
121
  described_class.new(config).add_filters(notifier)
106
122
  expect(notifier.has_filter?(Airbrake::Filters::GitRevisionFilter))
107
- .to eq(true)
123
+ .to be(true)
108
124
  end
109
125
 
110
126
  it "adds GitRepositoryFilter" do
111
127
  described_class.new(config).add_filters(notifier)
112
128
  expect(notifier.has_filter?(Airbrake::Filters::GitRepositoryFilter))
113
- .to eq(true)
129
+ .to be(true)
114
130
  end
115
131
 
116
132
  it "adds GitLastCheckoutFilter" do
117
133
  described_class.new(config).add_filters(notifier)
118
134
  expect(notifier.has_filter?(Airbrake::Filters::GitLastCheckoutFilter))
119
- .to eq(true)
135
+ .to be(true)
120
136
  end
121
137
  end
122
138
 
@@ -126,25 +142,25 @@ RSpec.describe Airbrake::Config::Processor do
126
142
  it "doesn't add RootDirectoryFilter" do
127
143
  described_class.new(config).add_filters(notifier)
128
144
  expect(notifier.has_filter?(Airbrake::Filters::RootDirectoryFilter))
129
- .to eq(false)
145
+ .to be(false)
130
146
  end
131
147
 
132
148
  it "doesn't add GitRevisionFilter" do
133
149
  described_class.new(config).add_filters(notifier)
134
150
  expect(notifier.has_filter?(Airbrake::Filters::GitRevisionFilter))
135
- .to eq(false)
151
+ .to be(false)
136
152
  end
137
153
 
138
154
  it "doesn't add GitRepositoryFilter" do
139
155
  described_class.new(config).add_filters(notifier)
140
156
  expect(notifier.has_filter?(Airbrake::Filters::GitRepositoryFilter))
141
- .to eq(false)
157
+ .to be(false)
142
158
  end
143
159
 
144
160
  it "doesn't add GitLastCheckoutFilter" do
145
161
  described_class.new(config).add_filters(notifier)
146
162
  expect(notifier.has_filter?(Airbrake::Filters::GitLastCheckoutFilter))
147
- .to eq(false)
163
+ .to be(false)
148
164
  end
149
165
  end
150
166
  end
data/spec/config_spec.rb CHANGED
@@ -23,12 +23,12 @@ RSpec.describe Airbrake::Config do
23
23
  its(:timeout) { is_expected.to be_nil }
24
24
  its(:blocklist_keys) { is_expected.to be_empty }
25
25
  its(:allowlist_keys) { is_expected.to be_empty }
26
- its(:performance_stats) { is_expected.to eq(true) }
26
+ its(:performance_stats) { is_expected.to be(true) }
27
27
  its(:performance_stats_flush_period) { is_expected.to eq(15) }
28
- its(:query_stats) { is_expected.to eq(true) }
29
- its(:job_stats) { is_expected.to eq(true) }
30
- its(:error_notifications) { is_expected.to eq(true) }
31
- its(:remote_config) { is_expected.to eq(true) }
28
+ its(:query_stats) { is_expected.to be(true) }
29
+ its(:job_stats) { is_expected.to be(true) }
30
+ its(:error_notifications) { is_expected.to be(true) }
31
+ its(:remote_config) { is_expected.to be(true) }
32
32
 
33
33
  its(:remote_config_host) do
34
34
  is_expected.to eq('https://notifier-configs.airbrake.io')
@@ -127,22 +127,22 @@ RSpec.describe Airbrake::Config do
127
127
 
128
128
  describe "#check_performance_options" do
129
129
  it "returns a promise" do
130
- resource = Airbrake::Query.new(method: '', route: '', query: '', timing: 1)
131
- expect(config.check_performance_options(resource))
130
+ metric = Airbrake::Query.new(method: '', route: '', query: '', timing: 1)
131
+ expect(config.check_performance_options(metric))
132
132
  .to be_an(Airbrake::Promise)
133
133
  end
134
134
 
135
135
  context "when performance stats are disabled" do
136
136
  before { config.performance_stats = false }
137
137
 
138
- let(:resource) do
138
+ let(:metric) do
139
139
  Airbrake::Request.new(
140
140
  method: 'GET', route: '/foo', status_code: 200, timing: 1,
141
141
  )
142
142
  end
143
143
 
144
144
  it "returns a rejected promise" do
145
- promise = config.check_performance_options(resource)
145
+ promise = config.check_performance_options(metric)
146
146
  expect(promise.value).to eq(
147
147
  'error' => "The Performance Stats feature is disabled",
148
148
  )
@@ -152,12 +152,12 @@ RSpec.describe Airbrake::Config do
152
152
  context "when query stats are disabled" do
153
153
  before { config.query_stats = false }
154
154
 
155
- let(:resource) do
155
+ let(:metric) do
156
156
  Airbrake::Query.new(method: 'GET', route: '/foo', query: '', timing: 1)
157
157
  end
158
158
 
159
159
  it "returns a rejected promise" do
160
- promise = config.check_performance_options(resource)
160
+ promise = config.check_performance_options(metric)
161
161
  expect(promise.value).to eq(
162
162
  'error' => "The Query Stats feature is disabled",
163
163
  )
@@ -167,12 +167,12 @@ RSpec.describe Airbrake::Config do
167
167
  context "when job stats are disabled" do
168
168
  before { config.job_stats = false }
169
169
 
170
- let(:resource) do
170
+ let(:metric) do
171
171
  Airbrake::Queue.new(queue: 'foo_queue', error_count: 0, timing: 1)
172
172
  end
173
173
 
174
174
  it "returns a rejected promise" do
175
- promise = config.check_performance_options(resource)
175
+ promise = config.check_performance_options(metric)
176
176
  expect(promise.value).to eq(
177
177
  'error' => "The Job Stats feature is disabled",
178
178
  )
@@ -101,14 +101,14 @@ RSpec.describe Airbrake::FilterChain do
101
101
  klass = Class.new
102
102
 
103
103
  filter_chain.add_filter(klass.new)
104
- expect(filter_chain.includes?(klass)).to eq(true)
104
+ expect(filter_chain.includes?(klass)).to be(true)
105
105
  end
106
106
  end
107
107
 
108
108
  context "when Proc filter class is included in the filter chain" do
109
109
  it "returns true" do
110
110
  filter_chain.add_filter(proc {})
111
- expect(filter_chain.includes?(Proc)).to eq(true)
111
+ expect(filter_chain.includes?(Proc)).to be(true)
112
112
  end
113
113
  end
114
114
 
@@ -117,7 +117,7 @@ RSpec.describe Airbrake::FilterChain do
117
117
  klass = Class.new
118
118
 
119
119
  filter_chain.add_filter(proc {})
120
- expect(filter_chain.includes?(klass)).to eq(false)
120
+ expect(filter_chain.includes?(klass)).to be(false)
121
121
  end
122
122
  end
123
123
  end
@@ -1,9 +1,7 @@
1
1
  RSpec.describe Airbrake::Filters::GitRepositoryFilter do
2
2
  subject(:git_repository_filter) { described_class.new('.') }
3
3
 
4
- let(:notice) do
5
- Airbrake::Notice.new(Airbrake::Config.new, AirbrakeTestError.new)
6
- end
4
+ let(:notice) { Airbrake::Notice.new(AirbrakeTestError.new) }
7
5
 
8
6
  describe "#initialize" do
9
7
  it "parses standard git version" do
@@ -23,6 +21,14 @@ RSpec.describe Airbrake::Filters::GitRepositoryFilter do
23
21
  .to receive(:`).and_return('git version 2.17.2 (Apple Git-113)')
24
22
  expect { git_repository_filter }.not_to raise_error
25
23
  end
24
+
25
+ context "when Errno::EAGAIN is raised when detecting git version" do
26
+ it "doesn't attach anything to context/repository" do
27
+ allow_any_instance_of(Kernel).to receive(:`).and_raise(Errno::EAGAIN)
28
+ git_repository_filter.call(notice)
29
+ expect(notice[:context][:repository]).to be_nil
30
+ end
31
+ end
26
32
  end
27
33
 
28
34
  context "when context/repository is defined" do
@@ -34,7 +40,7 @@ RSpec.describe Airbrake::Filters::GitRepositoryFilter do
34
40
  end
35
41
 
36
42
  context "when .git directory doesn't exist" do
37
- git_repository_filter { described_class.new('root/dir') }
43
+ subject(:git_repository_filter) { described_class.new('root/dir') }
38
44
 
39
45
  it "doesn't attach anything to context/repository" do
40
46
  git_repository_filter.call(notice)
@@ -45,15 +51,20 @@ RSpec.describe Airbrake::Filters::GitRepositoryFilter do
45
51
  context "when .git directory exists" do
46
52
  it "attaches context/repository" do
47
53
  git_repository_filter.call(notice)
48
- expect(notice[:context][:repository]).to eq(
49
- 'ssh://git@github.com/airbrake/airbrake-ruby.git',
54
+ expect(notice[:context][:repository]).to match(
55
+ 'github.com/airbrake/airbrake-ruby',
50
56
  )
51
57
  end
52
58
  end
53
59
 
54
60
  context "when git is not in PATH" do
61
+ let!(:path) { ENV['PATH'] }
62
+
63
+ before { ENV['PATH'] = '' }
64
+
65
+ after { ENV['PATH'] = path }
66
+
55
67
  it "does not attach context/repository" do
56
- ENV['PATH'] = ''
57
68
  git_repository_filter.call(notice)
58
69
  expect(notice[:context][:repository]).to be_nil
59
70
  end
@@ -54,7 +54,7 @@ RSpec.describe Airbrake::Filters::GitRevisionFilter do
54
54
  end
55
55
  end
56
56
 
57
- context "and also when HEAD starts with 'ref: " do
57
+ context "and also when HEAD starts with 'ref: '" do
58
58
  before do
59
59
  allow(File).to(
60
60
  receive(:read).with('root/dir/.git/HEAD').and_return("ref: refs/foo\n"),
@@ -522,8 +522,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
522
522
 
523
523
  context "when a filter that modifies payload was defined" do
524
524
  before do
525
- perf_notifier.add_filter do |resource|
526
- resource.route = '[Filtered]'
525
+ perf_notifier.add_filter do |metric|
526
+ metric.route = '[Filtered]'
527
527
  end
528
528
  end
529
529
 
@@ -621,7 +621,7 @@ RSpec.describe Airbrake::PerformanceNotifier do
621
621
  describe "#delete_filter" do
622
622
  let(:filter) do
623
623
  Class.new do
624
- def call(resource); end
624
+ def call(metric); end
625
625
  end
626
626
  end
627
627
 
@@ -42,13 +42,13 @@ RSpec.describe Airbrake::RemoteSettings::Callback do
42
42
  callback = described_class.new(config)
43
43
 
44
44
  callback.call(data)
45
- expect(config.error_notifications).to eq(false)
45
+ expect(config.error_notifications).to be(false)
46
46
 
47
47
  callback.call(data)
48
- expect(config.error_notifications).to eq(false)
48
+ expect(config.error_notifications).to be(false)
49
49
 
50
50
  callback.call(data)
51
- expect(config.error_notifications).to eq(false)
51
+ expect(config.error_notifications).to be(false)
52
52
  end
53
53
  # rubocop:enable RSpec/MultipleExpectations
54
54
  end
@@ -63,12 +63,12 @@ RSpec.describe Airbrake::RemoteSettings::Callback do
63
63
  allow(data).to receive(:error_notifications?).and_return(false)
64
64
 
65
65
  callback.call(data)
66
- expect(config.error_notifications).to eq(false)
66
+ expect(config.error_notifications).to be(false)
67
67
 
68
68
  allow(data).to receive(:error_notifications?).and_return(true)
69
69
 
70
70
  callback.call(data)
71
- expect(config.error_notifications).to eq(true)
71
+ expect(config.error_notifications).to be(true)
72
72
 
73
73
  expect(data).to have_received(:error_notifications?).twice
74
74
  end
@@ -86,13 +86,13 @@ RSpec.describe Airbrake::RemoteSettings::Callback do
86
86
  callback = described_class.new(config)
87
87
 
88
88
  callback.call(data)
89
- expect(config.performance_stats).to eq(false)
89
+ expect(config.performance_stats).to be(false)
90
90
 
91
91
  callback.call(data)
92
- expect(config.performance_stats).to eq(false)
92
+ expect(config.performance_stats).to be(false)
93
93
 
94
94
  callback.call(data)
95
- expect(config.performance_stats).to eq(false)
95
+ expect(config.performance_stats).to be(false)
96
96
  end
97
97
  # rubocop:enable RSpec/MultipleExpectations
98
98
  end
@@ -107,12 +107,12 @@ RSpec.describe Airbrake::RemoteSettings::Callback do
107
107
  allow(data).to receive(:performance_stats?).and_return(false)
108
108
 
109
109
  callback.call(data)
110
- expect(config.performance_stats).to eq(false)
110
+ expect(config.performance_stats).to be(false)
111
111
 
112
112
  allow(data).to receive(:performance_stats?).and_return(true)
113
113
 
114
114
  callback.call(data)
115
- expect(config.performance_stats).to eq(true)
115
+ expect(config.performance_stats).to be(true)
116
116
 
117
117
  expect(data).to have_received(:performance_stats?).twice
118
118
  end
@@ -123,7 +123,7 @@ RSpec.describe Airbrake::RemoteSettings::SettingsData do
123
123
 
124
124
  it "returns true" do
125
125
  expect(described_class.new(project_id, data).error_notifications?)
126
- .to eq(true)
126
+ .to be(true)
127
127
  end
128
128
  end
129
129
 
@@ -141,7 +141,7 @@ RSpec.describe Airbrake::RemoteSettings::SettingsData do
141
141
 
142
142
  it "returns false" do
143
143
  expect(described_class.new(project_id, data).error_notifications?)
144
- .to eq(false)
144
+ .to be(false)
145
145
  end
146
146
  end
147
147
  end
@@ -153,7 +153,7 @@ RSpec.describe Airbrake::RemoteSettings::SettingsData do
153
153
 
154
154
  it "returns true" do
155
155
  expect(described_class.new(project_id, data).error_notifications?)
156
- .to eq(true)
156
+ .to be(true)
157
157
  end
158
158
  end
159
159
  end
@@ -174,7 +174,7 @@ RSpec.describe Airbrake::RemoteSettings::SettingsData do
174
174
 
175
175
  it "returns true" do
176
176
  expect(described_class.new(project_id, data).performance_stats?)
177
- .to eq(true)
177
+ .to be(true)
178
178
  end
179
179
  end
180
180
 
@@ -192,7 +192,7 @@ RSpec.describe Airbrake::RemoteSettings::SettingsData do
192
192
 
193
193
  it "returns false" do
194
194
  expect(described_class.new(project_id, data).performance_stats?)
195
- .to eq(false)
195
+ .to be(false)
196
196
  end
197
197
  end
198
198
  end
@@ -204,7 +204,7 @@ RSpec.describe Airbrake::RemoteSettings::SettingsData do
204
204
 
205
205
  it "returns true" do
206
206
  expect(described_class.new(project_id, data).performance_stats?)
207
- .to eq(true)
207
+ .to be(true)
208
208
  end
209
209
  end
210
210
  end
@@ -77,16 +77,20 @@ RSpec.describe Airbrake::RemoteSettings do
77
77
  sleep(0.1)
78
78
  remote_settings.stop_polling
79
79
 
80
- expect(settings.error_notifications?).to eq(true)
81
- expect(settings.performance_stats?).to eq(false)
80
+ expect(settings.error_notifications?).to be(true)
81
+ expect(settings.performance_stats?).to be(false)
82
82
  expect(settings.interval).to eq(1)
83
83
  end
84
84
  # rubocop:enable RSpec/MultipleExpectations
85
85
  end
86
86
 
87
87
  context "when an error is raised while making a HTTP request" do
88
+ let(:https) { instance_double(Net::HTTP) }
89
+
88
90
  before do
89
- allow(Net::HTTP).to receive(:get_response).and_raise(StandardError)
91
+ allow(Net::HTTP).to receive(:new).and_return(https)
92
+ allow(https).to receive(:use_ssl=).with(true)
93
+ allow(https).to receive(:request).and_raise(StandardError)
90
94
  end
91
95
 
92
96
  it "doesn't fetch remote settings" do
@@ -15,7 +15,7 @@ RSpec.describe Airbrake::ThreadPool do
15
15
  it "returns true" do
16
16
  retval = thread_pool << 1
17
17
  thread_pool.close
18
- expect(retval).to eq(true)
18
+ expect(retval).to be(true)
19
19
  end
20
20
 
21
21
  it "performs work in background" do
@@ -44,7 +44,7 @@ RSpec.describe Airbrake::ThreadPool do
44
44
  it "returns false" do
45
45
  retval = full_thread_pool << 1
46
46
  full_thread_pool.close
47
- expect(retval).to eq(false)
47
+ expect(retval).to be(false)
48
48
  end
49
49
 
50
50
  it "discards tasks" do
@@ -55,14 +55,13 @@ RSpec.describe Airbrake::ThreadPool do
55
55
  end
56
56
 
57
57
  it "logs discarded tasks" do
58
- allow(Airbrake::Loggable.instance).to receive(:error)
58
+ allow(Airbrake::Loggable.instance).to receive(:info)
59
59
 
60
60
  15.times { full_thread_pool << 1 }
61
61
  full_thread_pool.close
62
62
 
63
- expect(Airbrake::Loggable.instance).to have_received(:error).with(
64
- /reached its capacity/,
65
- ).exactly(15).times
63
+ expect(Airbrake::Loggable.instance)
64
+ .to have_received(:info).exactly(15).times
66
65
  end
67
66
  end
68
67
  end
@@ -1,15 +1,30 @@
1
1
  RSpec.describe Airbrake::TimeTruncate do
2
+ time = Time.new(2018, 1, 1, 0, 0, 20, 0)
3
+ time_with_zone = Time.new(2018, 1, 1, 0, 0, 20, '-05:00')
4
+
2
5
  describe "#utc_truncate_minutes" do
3
- it "truncates time to the floor minute and returns an RFC3339 timestamp" do
4
- time = Time.new(2018, 1, 1, 0, 0, 20, 0)
5
- expect(described_class.utc_truncate_minutes(time))
6
- .to eq('2018-01-01T00:00:00+00:00')
6
+ shared_examples 'time conversion' do |t|
7
+ it "truncates the time to the floor minute and returns an RFC3339 timestamp" do
8
+ expect(described_class.utc_truncate_minutes(t))
9
+ .to eq('2018-01-01T00:00:00+00:00')
10
+ end
11
+
12
+ it "converts time with zone to UTC" do
13
+ expect(described_class.utc_truncate_minutes(time_with_zone))
14
+ .to eq('2018-01-01T05:00:00+00:00')
15
+ end
16
+ end
17
+
18
+ context "when the time argument is a Time object" do
19
+ include_examples 'time conversion', time
20
+ end
21
+
22
+ context "when the time argument is a Float" do
23
+ include_examples 'time conversion', time.to_f
7
24
  end
8
25
 
9
- it "converts time with zone to UTC" do
10
- time = Time.new(2018, 1, 1, 0, 0, 20, '-05:00')
11
- expect(described_class.utc_truncate_minutes(time))
12
- .to eq('2018-01-01T05:00:00+00:00')
26
+ context "when the time argument is an Integer" do
27
+ include_examples 'time conversion', time.to_i
13
28
  end
14
29
  end
15
30
  end
@@ -22,7 +22,7 @@ RSpec.describe Airbrake::TimedTrace do
22
22
  describe "#start_span" do
23
23
  context "when called once" do
24
24
  it "returns true" do
25
- expect(timed_trace.start_span('operation')).to eq(true)
25
+ expect(timed_trace.start_span('operation')).to be(true)
26
26
  end
27
27
  end
28
28
 
@@ -30,7 +30,7 @@ RSpec.describe Airbrake::TimedTrace do
30
30
  before { timed_trace.start_span('operation') }
31
31
 
32
32
  it "returns false" do
33
- expect(timed_trace.start_span('operation')).to eq(false)
33
+ expect(timed_trace.start_span('operation')).to be(false)
34
34
  end
35
35
  end
36
36
 
@@ -38,7 +38,7 @@ RSpec.describe Airbrake::TimedTrace do
38
38
  before { timed_trace.start_span('operation') }
39
39
 
40
40
  it "returns true" do
41
- expect(timed_trace.start_span('another operation')).to eq(true)
41
+ expect(timed_trace.start_span('another operation')).to be(true)
42
42
  end
43
43
  end
44
44
 
@@ -54,7 +54,7 @@ RSpec.describe Airbrake::TimedTrace do
54
54
  describe "#stop_span" do
55
55
  context "when #start_span wasn't invoked" do
56
56
  it "returns false" do
57
- expect(timed_trace.stop_span('operation')).to eq(false)
57
+ expect(timed_trace.stop_span('operation')).to be(false)
58
58
  end
59
59
  end
60
60
 
@@ -62,7 +62,7 @@ RSpec.describe Airbrake::TimedTrace do
62
62
  before { timed_trace.start_span('operation') }
63
63
 
64
64
  it "returns true" do
65
- expect(timed_trace.stop_span('operation')).to eq(true)
65
+ expect(timed_trace.stop_span('operation')).to be(true)
66
66
  end
67
67
  end
68
68
 
@@ -74,15 +74,15 @@ RSpec.describe Airbrake::TimedTrace do
74
74
 
75
75
  context "and when stopping in LIFO order" do
76
76
  it "returns true for all spans" do
77
- expect(timed_trace.stop_span('another operation')).to eq(true)
78
- expect(timed_trace.stop_span('operation')).to eq(true)
77
+ expect(timed_trace.stop_span('another operation')).to be(true)
78
+ expect(timed_trace.stop_span('operation')).to be(true)
79
79
  end
80
80
  end
81
81
 
82
82
  context "and when stopping in FIFO order" do
83
83
  it "returns true for all spans" do
84
- expect(timed_trace.stop_span('operation')).to eq(true)
85
- expect(timed_trace.stop_span('another operation')).to eq(true)
84
+ expect(timed_trace.stop_span('operation')).to be(true)
85
+ expect(timed_trace.stop_span('another operation')).to be(true)
86
86
  end
87
87
  end
88
88
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: airbrake-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.0.0
4
+ version: 6.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Airbrake Technologies, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-09-20 00:00:00.000000000 Z
11
+ date: 2022-04-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rbtree3
@@ -110,7 +110,7 @@ files:
110
110
  - spec/filters/exception_attributes_filter_spec.rb
111
111
  - spec/filters/gem_root_filter_spec.rb
112
112
  - spec/filters/git_last_checkout_filter_spec.rb
113
- - spec/filters/git_repository_filter.rb
113
+ - spec/filters/git_repository_filter_spec.rb
114
114
  - spec/filters/git_revision_filter_spec.rb
115
115
  - spec/filters/keys_allowlist_spec.rb
116
116
  - spec/filters/keys_blocklist_spec.rb
@@ -155,7 +155,8 @@ files:
155
155
  homepage: https://airbrake.io
156
156
  licenses:
157
157
  - MIT
158
- metadata: {}
158
+ metadata:
159
+ rubygems_mfa_required: 'true'
159
160
  post_install_message:
160
161
  rdoc_options: []
161
162
  require_paths:
@@ -171,7 +172,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
171
172
  - !ruby/object:Gem::Version
172
173
  version: '0'
173
174
  requirements: []
174
- rubygems_version: 3.2.15
175
+ rubygems_version: 3.2.32
175
176
  signing_key:
176
177
  specification_version: 4
177
178
  summary: Ruby notifier for https://airbrake.io
@@ -193,7 +194,7 @@ test_files:
193
194
  - spec/filters/exception_attributes_filter_spec.rb
194
195
  - spec/filters/gem_root_filter_spec.rb
195
196
  - spec/filters/git_last_checkout_filter_spec.rb
196
- - spec/filters/git_repository_filter.rb
197
+ - spec/filters/git_repository_filter_spec.rb
197
198
  - spec/filters/git_revision_filter_spec.rb
198
199
  - spec/filters/keys_allowlist_spec.rb
199
200
  - spec/filters/keys_blocklist_spec.rb