airbrake-ruby 2.8.3 → 2.9.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
  SHA1:
3
- metadata.gz: 3f2a54611d3b5e6242dafa75f513058acf49d48b
4
- data.tar.gz: 14871f5c3d358fbfa75718c8e1f88f3905657904
3
+ metadata.gz: 5a9ac80f76081013e1f710824cbe72291d26bda5
4
+ data.tar.gz: a665035c27cdbbdea9cb7bef43b43931be5266f9
5
5
  SHA512:
6
- metadata.gz: e849545f4261e4d1136f3de74a2f0179709c5895f2ab52446c64538e4bcf0201b2d747d3d1e5df7730849148f13748dc6f4b6d227a0b30c548359013d58dd7e3
7
- data.tar.gz: bf4085ed3db6b3e355a3cbc3b375d47dc74090fa70e20718fb9dac3e701ce3b9d05bf53840193b6fc5b4f75cdbd71916354b0ac0e09a872357bf7b3d5492be9c
6
+ metadata.gz: bc673d309a343d6b15d533e1feb4e202fcc1bb3ca31f2ef79e9af257fedd831614874c0efcfd32b88155a28448cd04affa4117567843972f594fe7a4dda77a80
7
+ data.tar.gz: 9e92da2e216c266de65d35c309eed96791eadd6f7e89aca0ebd9e643e49630970b0c41e7da94f15e31cafd65c7f6131668b1a7b41174a44caad94a15eaf665a9
@@ -23,6 +23,7 @@ require 'airbrake-ruby/filters/gem_root_filter'
23
23
  require 'airbrake-ruby/filters/system_exit_filter'
24
24
  require 'airbrake-ruby/filters/root_directory_filter'
25
25
  require 'airbrake-ruby/filters/thread_filter'
26
+ require 'airbrake-ruby/filters/context_filter'
26
27
  require 'airbrake-ruby/filter_chain'
27
28
  require 'airbrake-ruby/notifier'
28
29
  require 'airbrake-ruby/code_hunk'
@@ -268,5 +269,54 @@ module Airbrake
268
269
  def create_deploy(deploy_params)
269
270
  @notifiers[:default].create_deploy(deploy_params)
270
271
  end
272
+
273
+ ##
274
+ # Merges +context+ with the current context.
275
+ #
276
+ # The context will be attached to the notice object upon a notify call and
277
+ # cleared after it's attached. The context data is attached to the
278
+ # `params/airbrake_context` key.
279
+ #
280
+ # @example
281
+ # class MerryGrocer
282
+ # def load_fruits(fruits)
283
+ # Airbrake.merge_context(fruits: fruits)
284
+ # end
285
+ #
286
+ # def deliver_fruits
287
+ # Airbrake.notify('fruitception')
288
+ # end
289
+ #
290
+ # def load_veggies
291
+ # Airbrake.merge_context(veggies: veggies)
292
+ # end
293
+ #
294
+ # def deliver_veggies
295
+ # Airbrake.notify('veggieboom!')
296
+ # end
297
+ # end
298
+ #
299
+ # grocer = MerryGrocer.new
300
+ #
301
+ # # Load some fruits to the context.
302
+ # grocer.load_fruits(%w(mango banana apple))
303
+ #
304
+ # # Deliver the fruits. Note that we are not passing anything,
305
+ # # `deliver_fruits` knows that we loaded something.
306
+ # grocer.deliver_fruits
307
+ #
308
+ # # Load some vegetables and deliver them to Airbrake. Note that the
309
+ # # fruits have been delivered and therefore the grocer doesn't have them
310
+ # # anymore. We merge veggies with the new context.
311
+ # grocer.load_veggies(%w(cabbage carrot onion))
312
+ # grocer.deliver_veggies
313
+ #
314
+ # # The context is empty again, feel free to load more.
315
+ #
316
+ # @param [Hash{Symbol=>Object}] context
317
+ # @return [void]
318
+ def merge_context(context)
319
+ @notifiers[:default].merge_context(context)
320
+ end
271
321
  end
272
322
  end
@@ -80,14 +80,16 @@ module Airbrake
80
80
  # @return [Boolean] true if an instance wasn't closed, but has no workers
81
81
  # @see https://goo.gl/oydz8h Example of at_exit that prevents exit
82
82
  def has_workers?
83
- return false if @closed
83
+ @mutex.synchronize do
84
+ return false if @closed
84
85
 
85
- if @pid != Process.pid && @workers.list.empty?
86
- @pid = Process.pid
87
- spawn_workers
88
- end
86
+ if @pid != Process.pid && @workers.list.empty?
87
+ @pid = Process.pid
88
+ spawn_workers
89
+ end
89
90
 
90
- !@closed && @workers.list.any?
91
+ !@closed && @workers.list.any?
92
+ end
91
93
  end
92
94
 
93
95
  private
@@ -0,0 +1,28 @@
1
+ module Airbrake
2
+ module Filters
3
+ # Adds user context to the notice object. Clears the context after it's
4
+ # attached.
5
+ #
6
+ # @api private
7
+ # @since v2.9.0
8
+ class ContextFilter
9
+ # @return [Integer]
10
+ attr_reader :weight
11
+
12
+ def initialize(context)
13
+ @context = context
14
+ @weight = 119
15
+ @mutex = Mutex.new
16
+ end
17
+
18
+ def call(notice)
19
+ @mutex.synchronize do
20
+ return if @context.empty?
21
+
22
+ notice[:params][:airbrake_context] = @context.dup
23
+ @context.clear
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -5,7 +5,7 @@ module Airbrake
5
5
  class GemRootFilter
6
6
  ##
7
7
  # @return [String]
8
- GEM_ROOT_LABEL = '[GEM_ROOT]'.freeze
8
+ GEM_ROOT_LABEL = '/GEM_ROOT'.freeze
9
9
 
10
10
  ##
11
11
  # @return [Integer]
@@ -5,7 +5,7 @@ module Airbrake
5
5
  class RootDirectoryFilter
6
6
  ##
7
7
  # @return [String]
8
- PROJECT_ROOT_LABEL = '[PROJECT_ROOT]'.freeze
8
+ PROJECT_ROOT_LABEL = '/PROJECT_ROOT'.freeze
9
9
 
10
10
  ##
11
11
  # @return [Integer]
@@ -31,6 +31,8 @@ module Airbrake
31
31
 
32
32
  raise Airbrake::Error, @config.validation_error_message unless @config.valid?
33
33
 
34
+ @context = {}
35
+
34
36
  @filter_chain = FilterChain.new
35
37
  add_default_filters
36
38
 
@@ -98,6 +100,12 @@ module Airbrake
98
100
  @config.valid?
99
101
  end
100
102
 
103
+ ##
104
+ # @macro see_public_api_method
105
+ def merge_context(context)
106
+ @context.merge!(context)
107
+ end
108
+
101
109
  private
102
110
 
103
111
  def convert_to_exception(ex)
@@ -162,6 +170,8 @@ module Airbrake
162
170
  )
163
171
  end
164
172
 
173
+ @filter_chain.add_filter(Airbrake::Filters::ContextFilter.new(@context))
174
+
165
175
  return unless (root_directory = @config.root_directory)
166
176
  @filter_chain.add_filter(
167
177
  Airbrake::Filters::RootDirectoryFilter.new(root_directory)
@@ -190,5 +200,7 @@ module Airbrake
190
200
  def configured?
191
201
  false
192
202
  end
203
+
204
+ def merge_context(_context); end
193
205
  end
194
206
  end
@@ -4,5 +4,5 @@
4
4
  module Airbrake
5
5
  ##
6
6
  # @return [String] the library version
7
- AIRBRAKE_RUBY_VERSION = '2.8.3'.freeze
7
+ AIRBRAKE_RUBY_VERSION = '2.9.0'.freeze
8
8
  end
@@ -81,8 +81,8 @@ RSpec.describe Airbrake do
81
81
  # rubocop:disable Metrics/LineLength
82
82
  expected_body = %r|
83
83
  {"errors":\[{"type":"RuntimeError","message":"bingo","backtrace":\[
84
- {"file":"\[PROJECT_ROOT\]/spec/airbrake_spec.rb","line":\d+,"function":"[\w/\s\(\)<>]+","code".+},
85
- {"file":"\[GEM_ROOT\]/gems/rspec-core-.+/.+","line":\d+,"function":"[\w/\s\(\)<>]+".+
84
+ {"file":"/PROJECT_ROOT/spec/airbrake_spec.rb","line":\d+,"function":"[\w/\s\(\)<>]+","code".+},
85
+ {"file":"/GEM_ROOT/gems/rspec-core-.+/.+","line":\d+,"function":"[\w/\s\(\)<>]+".+
86
86
  |x
87
87
  # rubocop:enable Metrics/LineLength
88
88
 
@@ -163,11 +163,11 @@ RSpec.describe Airbrake do
163
163
  filter_chain = notifier.instance_variable_get(:@filter_chain)
164
164
  filters = filter_chain.instance_variable_get(:@filters)
165
165
 
166
- expect(filters.size).to eq(3)
166
+ expect(filters.size).to eq(4)
167
167
 
168
168
  described_class.add_filter {}
169
169
 
170
- expect(filters.size).to eq(4)
170
+ expect(filters.size).to eq(5)
171
171
  expect(filters.last).to be_a(Proc)
172
172
  end
173
173
  end
@@ -175,4 +175,8 @@ RSpec.describe Airbrake do
175
175
  describe ".build_notice" do
176
176
  include_examples 'non-configured notifier handling', :build_notice
177
177
  end
178
+
179
+ describe ".merge_context" do
180
+ include_examples 'non-configured notifier handling', :merge_context
181
+ end
178
182
  end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Airbrake::Filters::ContextFilter do
4
+ let(:notice) do
5
+ Airbrake::Notice.new(Airbrake::Config.new, AirbrakeTestError.new)
6
+ end
7
+
8
+ context "when the current context is empty" do
9
+ it "doesn't merge anything with params" do
10
+ described_class.new({}).call(notice)
11
+ expect(notice[:params]).to be_empty
12
+ end
13
+ end
14
+
15
+ context "when the current context has some data" do
16
+ it "merges the data with params" do
17
+ described_class.new(apples: 'oranges').call(notice)
18
+ expect(notice[:params]).to eq(airbrake_context: { apples: 'oranges' })
19
+ end
20
+
21
+ it "clears the data from the provided context" do
22
+ context = { apples: 'oranges' }
23
+ described_class.new(context).call(notice)
24
+ expect(context).to be_empty
25
+ end
26
+ end
27
+ end
@@ -28,9 +28,9 @@ RSpec.describe Airbrake::Filters::GemRootFilter do
28
28
  eq(
29
29
  [
30
30
  { file: "/home/kyrylo/code/airbrake/ruby/spec/spec_helper.rb" },
31
- { file: "[GEM_ROOT]/gems/rspec-core-3.3.2/lib/rspec/core/configuration.rb" },
31
+ { file: "/GEM_ROOT/gems/rspec-core-3.3.2/lib/rspec/core/configuration.rb" },
32
32
  { file: "/opt/rubies/ruby-2.2.2/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb" },
33
- { file: "[GEM_ROOT]/gems/rspec-core-3.3.2/exe/rspec" }
33
+ { file: "/GEM_ROOT/gems/rspec-core-3.3.2/exe/rspec" }
34
34
  ]
35
35
  )
36
36
  )
@@ -26,9 +26,9 @@ RSpec.describe Airbrake::Filters::RootDirectoryFilter do
26
26
  eq(
27
27
  [
28
28
  { file: "/home/kyrylo/code/airbrake/ruby/spec/spec_helper.rb" },
29
- { file: "[PROJECT_ROOT]/gems/rspec-core-3.3.2/lib/rspec/core/configuration.rb " },
29
+ { file: "/PROJECT_ROOT/gems/rspec-core-3.3.2/lib/rspec/core/configuration.rb " },
30
30
  { file: "/opt/rubies/ruby-2.2.2/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb" },
31
- { file: "[PROJECT_ROOT]/gems/rspec-core-3.3.2/exe/rspec" }
31
+ { file: "/PROJECT_ROOT/gems/rspec-core-3.3.2/exe/rspec" }
32
32
  ]
33
33
  )
34
34
  )
@@ -614,4 +614,15 @@ RSpec.describe Airbrake::Notifier do
614
614
  subject { described_class.new(airbrake_params) }
615
615
  it { is_expected.to be_configured }
616
616
  end
617
+
618
+ describe "#merge_context" do
619
+ it "merges the provided context with the notice object" do
620
+ @airbrake.merge_context(apples: 'oranges')
621
+ @airbrake.notify_sync('oops')
622
+ expect(
623
+ a_request(:post, endpoint).
624
+ with(body: /"params":{"airbrake_context":{"apples":"oranges"}/)
625
+ ).to have_been_made.once
626
+ end
627
+ end
617
628
  end
@@ -75,7 +75,7 @@ RSpec.describe Airbrake::Notifier do
75
75
 
76
76
  expect(
77
77
  a_request(:post, endpoint).
78
- with(body: %r|{"file":"\[PROJECT_ROOT\]/airbrake/ruby/spec/airbrake_spec.+|)
78
+ with(body: %r|{"file":"/PROJECT_ROOT/airbrake/ruby/spec/airbrake_spec.+|)
79
79
  ).to have_been_made.once
80
80
  end
81
81
 
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: 2.8.3
4
+ version: 2.9.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: 2018-03-12 00:00:00.000000000 Z
11
+ date: 2018-04-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -123,6 +123,7 @@ files:
123
123
  - lib/airbrake-ruby/config/validator.rb
124
124
  - lib/airbrake-ruby/file_cache.rb
125
125
  - lib/airbrake-ruby/filter_chain.rb
126
+ - lib/airbrake-ruby/filters/context_filter.rb
126
127
  - lib/airbrake-ruby/filters/gem_root_filter.rb
127
128
  - lib/airbrake-ruby/filters/keys_blacklist.rb
128
129
  - lib/airbrake-ruby/filters/keys_filter.rb
@@ -146,6 +147,7 @@ files:
146
147
  - spec/config_spec.rb
147
148
  - spec/file_cache.rb
148
149
  - spec/filter_chain_spec.rb
150
+ - spec/filters/context_filter_spec.rb
149
151
  - spec/filters/gem_root_filter_spec.rb
150
152
  - spec/filters/keys_blacklist_spec.rb
151
153
  - spec/filters/keys_whitelist_spec.rb
@@ -198,6 +200,7 @@ test_files:
198
200
  - spec/filters/keys_whitelist_spec.rb
199
201
  - spec/filters/system_exit_filter_spec.rb
200
202
  - spec/filters/thread_filter_spec.rb
203
+ - spec/filters/context_filter_spec.rb
201
204
  - spec/filters/keys_blacklist_spec.rb
202
205
  - spec/filters/gem_root_filter_spec.rb
203
206
  - spec/spec_helper.rb