airbrake 5.0.5 → 5.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.rb +26 -0
- data/lib/airbrake/capistrano/tasks.rb +1 -1
- data/lib/airbrake/rack/middleware.rb +14 -3
- data/lib/airbrake/rack/notice_builder.rb +52 -44
- data/lib/airbrake/rake/task_ext.rb +1 -1
- data/lib/airbrake/version.rb +1 -1
- data/spec/airbrake_spec.rb +17 -0
- data/spec/unit/rack/middleware_spec.rb +1 -1
- data/spec/unit/rack/notice_builder_spec.rb +48 -0
- metadata +17 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f2c700ad9e90a15de2d6482a6cc9429875fc9606
|
4
|
+
data.tar.gz: 74e37331ad0ebd00f2c3beede67c45480a5e607f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 97c0ca4f52385e44a1512b911e2bfef8d64223916a9d52fafbd630bbdfdbc022f909a1772cfa6883e4d5ce9c1752627856e916e552a7a075db986c9d12da4fa3
|
7
|
+
data.tar.gz: abd13310879565f3aa327a7dd1564b89afe2573ad2ea66394c9c351835ab2855296a15142b1187500a230d71ee6fc784ad24b11ec3734ebe10dfe777372043b8
|
data/lib/airbrake.rb
CHANGED
@@ -19,3 +19,29 @@ require 'airbrake/rake/task_ext' if defined?(Rake::Task)
|
|
19
19
|
require 'airbrake/resque/failure' if defined?(Resque)
|
20
20
|
require 'airbrake/sidekiq/error_handler' if defined?(Sidekiq)
|
21
21
|
require 'airbrake/delayed_job/plugin' if defined?(Delayed)
|
22
|
+
|
23
|
+
##
|
24
|
+
# This module reopens the original Airbrake module from airbrake-ruby and adds
|
25
|
+
# integration specific methods.
|
26
|
+
module Airbrake
|
27
|
+
class << self
|
28
|
+
##
|
29
|
+
# Attaches a callback (builder) that runs every time the Rack integration
|
30
|
+
# reports an error. Can be used to attach additional data from the Rack
|
31
|
+
# request.
|
32
|
+
#
|
33
|
+
# @example Adding remote IP from the Rack environment
|
34
|
+
# Airbrake.add_rack_builder do |notice, request|
|
35
|
+
# notice[:params][:remoteIp] = request.env['REMOTE_IP']
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# @yieldparam notice [Airbrake::Notice] notice that will be sent to Airbrake
|
39
|
+
# @yieldparam request [Rack::Request] current rack request
|
40
|
+
# @yieldreturn [void]
|
41
|
+
# @return [void]
|
42
|
+
# @since 5.1.0
|
43
|
+
def add_rack_builder(&block)
|
44
|
+
Airbrake::Rack::NoticeBuilder.add_builder(&block)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -9,7 +9,7 @@ if defined?(Capistrano::VERSION) &&
|
|
9
9
|
with rails_env: fetch(:rails_env, fetch(:stage)) do
|
10
10
|
execute :rake, <<-CMD
|
11
11
|
airbrake:deploy USERNAME=#{Shellwords.shellescape(local_user)} \
|
12
|
-
ENVIRONMENT=#{fetch(:rails_env, fetch(:stage))} \
|
12
|
+
ENVIRONMENT=#{fetch(:airbrake_env, fetch(:rails_env, fetch(:stage)))} \
|
13
13
|
REVISION=#{fetch(:current_revision)} \
|
14
14
|
REPOSITORY=#{fetch(:repo_url)} \
|
15
15
|
VERSION=#{fetch(:app_version)}
|
@@ -26,9 +26,7 @@ module Airbrake
|
|
26
26
|
end
|
27
27
|
# rubocop:enable Lint/RescueException
|
28
28
|
|
29
|
-
|
30
|
-
# env. See: https://goo.gl/Kd694n
|
31
|
-
exception = env['action_dispatch.exception'] || env['sinatra.error']
|
29
|
+
exception = framework_exception(env)
|
32
30
|
notify_airbrake(exception, env) if exception
|
33
31
|
|
34
32
|
response
|
@@ -40,6 +38,19 @@ module Airbrake
|
|
40
38
|
notice = NoticeBuilder.new(env).build_notice(exception)
|
41
39
|
Airbrake.notify(notice)
|
42
40
|
end
|
41
|
+
|
42
|
+
##
|
43
|
+
# Web framework middlewares often store rescued exceptions inside the
|
44
|
+
# Rack env, but Rack doesn't have a standard key for it:
|
45
|
+
#
|
46
|
+
# - Rails uses action_dispatch.exception: https://goo.gl/Kd694n
|
47
|
+
# - Sinatra uses sinatra.error: https://goo.gl/LLkVL9
|
48
|
+
# - Goliath uses rack.exception: https://goo.gl/i7e1nA
|
49
|
+
def framework_exception(env)
|
50
|
+
env['action_dispatch.exception'] ||
|
51
|
+
env['sinatra.error'] ||
|
52
|
+
env['rack.exception']
|
53
|
+
end
|
43
54
|
end
|
44
55
|
end
|
45
56
|
end
|
@@ -4,6 +4,20 @@ module Airbrake
|
|
4
4
|
# A helper class for filling notices with all sorts of useful information
|
5
5
|
# coming from the Rack environment.
|
6
6
|
class NoticeBuilder
|
7
|
+
@builders = []
|
8
|
+
|
9
|
+
class << self
|
10
|
+
##
|
11
|
+
# @return [Array<#call>] the list of notice's builders
|
12
|
+
attr_reader :builders
|
13
|
+
|
14
|
+
##
|
15
|
+
# Adds user defined builders to the chain.
|
16
|
+
def add_builder(&block)
|
17
|
+
@builders << block
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
7
21
|
##
|
8
22
|
# @return [Array<String>] the prefixes of the majority of HTTP headers in
|
9
23
|
# Rack (some prefixes match the header names for simplicity)
|
@@ -16,20 +30,7 @@ module Airbrake
|
|
16
30
|
##
|
17
31
|
# @param [Hash{String=>Object}] rack_env The Rack environment
|
18
32
|
def initialize(rack_env)
|
19
|
-
@rack_env = rack_env
|
20
33
|
@request = ::Rack::Request.new(rack_env)
|
21
|
-
@controller = rack_env['action_controller.instance']
|
22
|
-
@session = @request.session
|
23
|
-
@user = Airbrake::Rack::User.extract(rack_env)
|
24
|
-
|
25
|
-
@framework_version =
|
26
|
-
if defined?(::Rails)
|
27
|
-
"Rails/#{::Rails.version}"
|
28
|
-
elsif defined?(::Sinatra)
|
29
|
-
"Sinatra/#{Sinatra::VERSION}"
|
30
|
-
else
|
31
|
-
"Rack.version/#{::Rack.version} Rack.release/#{::Rack.release}"
|
32
|
-
end.freeze
|
33
34
|
end
|
34
35
|
|
35
36
|
##
|
@@ -39,64 +40,71 @@ module Airbrake
|
|
39
40
|
# @return [Airbrake::Notice] the notice with extra information
|
40
41
|
def build_notice(exception)
|
41
42
|
notice = Airbrake.build_notice(exception)
|
42
|
-
|
43
|
-
add_context(notice)
|
44
|
-
add_session(notice)
|
45
|
-
add_params(notice)
|
46
|
-
add_environment(notice)
|
47
|
-
|
43
|
+
NoticeBuilder.builders.each { |builder| builder.call(notice, @request) }
|
48
44
|
notice
|
49
45
|
end
|
50
46
|
|
51
|
-
|
52
|
-
|
53
|
-
def add_context(notice)
|
47
|
+
# Adds context (url, user agent, framework version, controller, etc)
|
48
|
+
add_builder do |notice, request|
|
54
49
|
context = notice[:context]
|
55
50
|
|
56
|
-
context[:url] =
|
57
|
-
context[:userAgent] =
|
51
|
+
context[:url] = request.url
|
52
|
+
context[:userAgent] = request.user_agent
|
53
|
+
|
54
|
+
framework_version =
|
55
|
+
if defined?(::Rails)
|
56
|
+
"Rails/#{::Rails.version}"
|
57
|
+
elsif defined?(::Sinatra)
|
58
|
+
"Sinatra/#{Sinatra::VERSION}"
|
59
|
+
else
|
60
|
+
"Rack.version/#{::Rack.version} Rack.release/#{::Rack.release}"
|
61
|
+
end.freeze
|
58
62
|
|
59
63
|
if context.key?(:version)
|
60
|
-
context[:version] += " #{
|
64
|
+
context[:version] += " #{framework_version}"
|
61
65
|
else
|
62
|
-
context[:version] =
|
66
|
+
context[:version] = framework_version
|
63
67
|
end
|
64
68
|
|
65
|
-
|
66
|
-
|
67
|
-
context[:
|
69
|
+
controller = request.env['action_controller.instance']
|
70
|
+
if controller
|
71
|
+
context[:component] = controller.controller_name
|
72
|
+
context[:action] = controller.action_name
|
68
73
|
end
|
69
74
|
|
70
|
-
|
75
|
+
user = Airbrake::Rack::User.extract(request.env)
|
76
|
+
notice[:context].merge!(user.as_json) if user
|
71
77
|
|
72
78
|
nil
|
73
79
|
end
|
74
80
|
|
75
|
-
|
76
|
-
|
81
|
+
# Adds session
|
82
|
+
add_builder do |notice, request|
|
83
|
+
session = request.session
|
84
|
+
notice[:session] = session if session
|
77
85
|
end
|
78
86
|
|
79
|
-
|
80
|
-
|
87
|
+
# Adds request params
|
88
|
+
add_builder do |notice, request|
|
89
|
+
params = request.env['action_dispatch.request.parameters']
|
81
90
|
notice[:params] = params if params
|
82
91
|
end
|
83
92
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
referer: @request.referer,
|
88
|
-
headers: request_headers
|
89
|
-
}
|
90
|
-
end
|
91
|
-
|
92
|
-
def request_headers
|
93
|
-
@rack_env.map.with_object({}) do |(key, value), headers|
|
93
|
+
# Adds http referer, method and headers to the environment
|
94
|
+
add_builder do |notice, request|
|
95
|
+
http_headers = request.env.map.with_object({}) do |(key, value), headers|
|
94
96
|
if HTTP_HEADER_PREFIXES.any? { |prefix| key.to_s.start_with?(prefix) }
|
95
97
|
headers[key] = value
|
96
98
|
end
|
97
99
|
|
98
100
|
headers
|
99
101
|
end
|
102
|
+
|
103
|
+
notice[:environment].merge!(
|
104
|
+
httpMethod: request.request_method,
|
105
|
+
referer: request.referer,
|
106
|
+
headers: http_headers
|
107
|
+
)
|
100
108
|
end
|
101
109
|
end
|
102
110
|
end
|
data/lib/airbrake/version.rb
CHANGED
data/spec/airbrake_spec.rb
CHANGED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Airbrake do
|
4
|
+
describe ".add_rack_builder" do
|
5
|
+
let :builder do
|
6
|
+
proc { |_, _| nil }
|
7
|
+
end
|
8
|
+
|
9
|
+
after { Airbrake::Rack::NoticeBuilder.builders.delete(builder) }
|
10
|
+
|
11
|
+
it "adds new builder to the chain" do
|
12
|
+
expect { Airbrake.add_rack_builder(&builder) }.to change {
|
13
|
+
Airbrake::Rack::NoticeBuilder.builders.count
|
14
|
+
}.by(1)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -57,7 +57,7 @@ RSpec.describe Airbrake::Rack::Middleware do
|
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
|
-
['action_dispatch.exception', 'sinatra.error'].each do |type|
|
60
|
+
['rack.exception', 'action_dispatch.exception', 'sinatra.error'].each do |type|
|
61
61
|
include_examples 'stored exception', type
|
62
62
|
end
|
63
63
|
end
|
@@ -31,5 +31,53 @@ RSpec.describe Airbrake::Rack::NoticeBuilder do
|
|
31
31
|
|
32
32
|
expect(notice[:params]).to eq(params)
|
33
33
|
end
|
34
|
+
|
35
|
+
it "adds CONTENT_TYPE, CONTENT_LENGTH and HTTP_* headers in the environment" do
|
36
|
+
headers = {
|
37
|
+
"HTTP_HOST" => "example.com",
|
38
|
+
"CONTENT_TYPE" => "text/html",
|
39
|
+
"CONTENT_LENGTH" => 100500
|
40
|
+
}
|
41
|
+
notice_builder = described_class.new(headers.dup)
|
42
|
+
notice = notice_builder.build_notice(AirbrakeTestError.new)
|
43
|
+
expect(notice[:environment][:headers]).to eq(headers)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "skips headers that were not selected to be stored in the environment" do
|
47
|
+
headers = {
|
48
|
+
"HTTP_HOST" => "example.com",
|
49
|
+
"CONTENT_TYPE" => "text/html",
|
50
|
+
"CONTENT_LENGTH" => 100500
|
51
|
+
}
|
52
|
+
notice_builder = described_class.new(headers.merge("X-SOME-HEADER" => "value"))
|
53
|
+
notice = notice_builder.build_notice(AirbrakeTestError.new)
|
54
|
+
expect(notice[:environment][:headers]).to eq(headers)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "preserves data that already has been added to the environment" do
|
58
|
+
headers = {
|
59
|
+
"HTTP_HOST" => "example.com",
|
60
|
+
"CONTENT_TYPE" => "text/html",
|
61
|
+
"CONTENT_LENGTH" => 100500
|
62
|
+
}
|
63
|
+
allow(Airbrake).to receive(:build_notice).and_wrap_original do |method, *args|
|
64
|
+
notice = method.call(*args)
|
65
|
+
notice[:environment]["SOME_KEY"] = "SOME_VALUE"
|
66
|
+
notice
|
67
|
+
end
|
68
|
+
notice_builder = described_class.new(headers)
|
69
|
+
notice = notice_builder.build_notice(AirbrakeTestError.new)
|
70
|
+
expect(notice[:environment]["SOME_KEY"]).to eq("SOME_VALUE")
|
71
|
+
end
|
72
|
+
|
73
|
+
it "runs user defined builders against notices" do
|
74
|
+
extended_class = described_class.dup
|
75
|
+
extended_class.add_builder do |notice, request|
|
76
|
+
notice[:params][:remoteIp] = request.env['REMOTE_IP']
|
77
|
+
end
|
78
|
+
notice_builder = extended_class.new('REMOTE_IP' => '127.0.0.1')
|
79
|
+
notice = notice_builder.build_notice(AirbrakeTestError.new)
|
80
|
+
expect(notice[:params][:remoteIp]).to eq("127.0.0.1")
|
81
|
+
end
|
34
82
|
end
|
35
83
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: airbrake
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.0
|
4
|
+
version: 5.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: 2016-02-
|
11
|
+
date: 2016-02-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: airbrake-ruby
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '1.
|
19
|
+
version: '1.1'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '1.
|
26
|
+
version: '1.1'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rspec
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -230,25 +230,25 @@ specification_version: 4
|
|
230
230
|
summary: Airbrake is an online tool that provides robust exception tracking in any
|
231
231
|
of your Ruby applications.
|
232
232
|
test_files:
|
233
|
+
- spec/airbrake_spec.rb
|
234
|
+
- spec/apps/rack/dummy_app.rb
|
235
|
+
- spec/apps/rails/dummy_app.rb
|
236
|
+
- spec/apps/rails/dummy_task.rake
|
237
|
+
- spec/apps/rails/logs/32.log
|
238
|
+
- spec/apps/rails/logs/40.log
|
239
|
+
- spec/apps/rails/logs/41.log
|
240
|
+
- spec/apps/rails/logs/42.log
|
241
|
+
- spec/apps/rails/logs/50.log
|
242
|
+
- spec/apps/sinatra/dummy_app.rb
|
233
243
|
- spec/integration/rack/rack_spec.rb
|
234
|
-
- spec/integration/sinatra/sinatra_spec.rb
|
235
244
|
- spec/integration/rails/rails_spec.rb
|
236
245
|
- spec/integration/rails/rake_spec.rb
|
237
246
|
- spec/integration/shared_examples/rack_examples.rb
|
247
|
+
- spec/integration/sinatra/sinatra_spec.rb
|
238
248
|
- spec/spec_helper.rb
|
239
|
-
- spec/apps/rack/dummy_app.rb
|
240
|
-
- spec/apps/sinatra/dummy_app.rb
|
241
|
-
- spec/apps/rails/logs/40.log
|
242
|
-
- spec/apps/rails/logs/42.log
|
243
|
-
- spec/apps/rails/logs/50.log
|
244
|
-
- spec/apps/rails/logs/32.log
|
245
|
-
- spec/apps/rails/logs/41.log
|
246
|
-
- spec/apps/rails/dummy_app.rb
|
247
|
-
- spec/apps/rails/dummy_task.rake
|
248
|
-
- spec/airbrake_spec.rb
|
249
249
|
- spec/unit/rack/middleware_spec.rb
|
250
|
-
- spec/unit/rack/user_spec.rb
|
251
250
|
- spec/unit/rack/notice_builder_spec.rb
|
252
|
-
- spec/unit/
|
251
|
+
- spec/unit/rack/user_spec.rb
|
253
252
|
- spec/unit/rake/tasks_spec.rb
|
253
|
+
- spec/unit/sidekiq/error_handler_spec.rb
|
254
254
|
has_rdoc:
|