honeybadger 1.12.0.beta3 → 1.13.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Appraisals +45 -60
- data/CHANGELOG.md +3 -28
- data/Gemfile.lock +1 -1
- data/MIT-LICENSE +1 -2
- data/Rakefile +4 -8
- data/features/step_definitions/rack_steps.rb +2 -1
- data/features/support/env.rb +0 -2
- data/gemfiles/rack.gemfile.lock +125 -0
- data/gemfiles/rails2.3.gemfile.lock +141 -0
- data/gemfiles/rails3.0.gemfile.lock +193 -0
- data/gemfiles/rails3.1.gemfile.lock +203 -0
- data/gemfiles/rails3.2.gemfile.lock +201 -0
- data/gemfiles/rails4.0.gemfile.lock +197 -0
- data/gemfiles/rails4.1.gemfile.lock +202 -0
- data/gemfiles/rake.gemfile +1 -1
- data/gemfiles/rake.gemfile.lock +124 -0
- data/gemfiles/sinatra.gemfile.lock +124 -0
- data/honeybadger.gemspec +11 -27
- data/lib/honeybadger.rb +10 -15
- data/lib/honeybadger/configuration.rb +4 -9
- data/lib/honeybadger/integrations/sidekiq.rb +9 -17
- data/lib/honeybadger/notice.rb +10 -45
- data/lib/honeybadger/rack.rb +54 -8
- data/lib/honeybadger/rails.rb +4 -5
- data/lib/honeybadger/railtie.rb +3 -4
- data/lib/honeybadger/user_feedback.rb +67 -3
- data/lib/honeybadger/user_informer.rb +21 -3
- data/spec/honeybadger/configuration_spec.rb +1 -5
- data/spec/honeybadger/notice_spec.rb +1 -126
- data/spec/honeybadger/rails_spec.rb +2 -4
- metadata +15 -31
- data/features/standalone.feature +0 -73
- data/features/step_definitions/standalone_steps.rb +0 -12
- data/features/step_definitions/thor_steps.rb +0 -4
- data/features/support/test.thor +0 -22
- data/features/thor.feature +0 -5
- data/gemfiles/binding_of_caller.gemfile +0 -8
- data/gemfiles/rails.gemfile +0 -11
- data/gemfiles/standalone.gemfile +0 -7
- data/gemfiles/thor.gemfile +0 -8
- data/lib/honeybadger/dependency.rb +0 -65
- data/lib/honeybadger/exception_extensions.rb +0 -35
- data/lib/honeybadger/integrations.rb +0 -5
- data/lib/honeybadger/integrations/delayed_job.rb +0 -20
- data/lib/honeybadger/integrations/delayed_job/plugin.rb +0 -31
- data/lib/honeybadger/integrations/thor.rb +0 -29
- data/lib/honeybadger/payload.rb +0 -29
- data/lib/honeybadger/rack/error_notifier.rb +0 -60
- data/lib/honeybadger/rack/user_feedback.rb +0 -74
- data/lib/honeybadger/rack/user_informer.rb +0 -28
- data/spec/honeybadger/dependency_spec.rb +0 -134
- data/spec/honeybadger/exception_extensions_spec.rb +0 -40
- data/spec/honeybadger/integrations/delayed_job_spec.rb +0 -48
- data/spec/honeybadger/integrations/sidekiq_spec.rb +0 -60
- data/spec/honeybadger/integrations/thor_spec.rb +0 -29
- data/spec/honeybadger/payload_spec.rb +0 -27
@@ -1,74 +0,0 @@
|
|
1
|
-
require 'erb'
|
2
|
-
require 'uri'
|
3
|
-
|
4
|
-
begin
|
5
|
-
require 'i18n'
|
6
|
-
rescue LoadError
|
7
|
-
module Honeybadger
|
8
|
-
module I18n
|
9
|
-
def self.t(key, options={})
|
10
|
-
options[:default]
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
module Honeybadger
|
17
|
-
module Rack
|
18
|
-
class UserFeedback
|
19
|
-
def initialize(app)
|
20
|
-
@app = app
|
21
|
-
end
|
22
|
-
|
23
|
-
def call(env)
|
24
|
-
status, headers, body = @app.call(env)
|
25
|
-
if enabled? && env['honeybadger.error_id'] && form = render_form(env['honeybadger.error_id'])
|
26
|
-
new_body = []
|
27
|
-
body.each do |chunk|
|
28
|
-
new_body << chunk.gsub("<!-- HONEYBADGER FEEDBACK -->", form)
|
29
|
-
end
|
30
|
-
body.close if body.respond_to?(:close)
|
31
|
-
headers['Content-Length'] = new_body.reduce(0) { |a,e| a += e.bytesize }.to_s
|
32
|
-
body = new_body
|
33
|
-
end
|
34
|
-
[status, headers, body]
|
35
|
-
end
|
36
|
-
|
37
|
-
def config
|
38
|
-
Honeybadger.configuration
|
39
|
-
end
|
40
|
-
|
41
|
-
def enabled?
|
42
|
-
config.feedback && config.features['feedback']
|
43
|
-
end
|
44
|
-
|
45
|
-
def action
|
46
|
-
URI.parse("#{config.protocol}://#{config.host}:#{config.port}/v1/feedback/").to_s
|
47
|
-
rescue URI::InvalidURIError
|
48
|
-
nil
|
49
|
-
end
|
50
|
-
|
51
|
-
def render_form(error_id, action = action)
|
52
|
-
return unless action
|
53
|
-
ERB.new(@template ||= File.read(template_file)).result(binding)
|
54
|
-
end
|
55
|
-
|
56
|
-
def custom_template_file
|
57
|
-
@custom_template_file ||= config.project_root &&
|
58
|
-
File.join(config.project_root, 'lib', 'honeybadger', 'templates', 'feedback_form.erb')
|
59
|
-
end
|
60
|
-
|
61
|
-
def custom_template_file?
|
62
|
-
custom_template_file && File.exists?(custom_template_file)
|
63
|
-
end
|
64
|
-
|
65
|
-
def template_file
|
66
|
-
if custom_template_file?
|
67
|
-
custom_template_file
|
68
|
-
else
|
69
|
-
File.expand_path('../../templates/feedback_form.erb', __FILE__)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
@@ -1,28 +0,0 @@
|
|
1
|
-
module Honeybadger
|
2
|
-
module Rack
|
3
|
-
class UserInformer
|
4
|
-
def initialize(app)
|
5
|
-
@app = app
|
6
|
-
end
|
7
|
-
|
8
|
-
def replacement(with)
|
9
|
-
Honeybadger.configuration.user_information.gsub(/\{\{\s*error_id\s*\}\}/, with.to_s)
|
10
|
-
end
|
11
|
-
|
12
|
-
def call(env)
|
13
|
-
status, headers, body = @app.call(env)
|
14
|
-
if env['honeybadger.error_id'] && Honeybadger.configuration.user_information
|
15
|
-
new_body = []
|
16
|
-
replace = replacement(env['honeybadger.error_id'])
|
17
|
-
body.each do |chunk|
|
18
|
-
new_body << chunk.gsub("<!-- HONEYBADGER ERROR -->", replace)
|
19
|
-
end
|
20
|
-
body.close if body.respond_to?(:close)
|
21
|
-
headers['Content-Length'] = new_body.reduce(0) { |a,e| a += e.bytesize }.to_s
|
22
|
-
body = new_body
|
23
|
-
end
|
24
|
-
[status, headers, body]
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
@@ -1,134 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Honeybadger::Dependency do
|
4
|
-
let(:dependency) { Honeybadger::Dependency.new }
|
5
|
-
subject { dependency }
|
6
|
-
|
7
|
-
before { Honeybadger::Dependency.stub(:instances).and_return([]) }
|
8
|
-
|
9
|
-
describe ".register" do
|
10
|
-
it "returns a new dependency" do
|
11
|
-
instance = double()
|
12
|
-
Honeybadger::Dependency.stub(:new).and_return(instance)
|
13
|
-
expect(Honeybadger::Dependency.register {}).to eq [instance]
|
14
|
-
end
|
15
|
-
|
16
|
-
it "registers a new dependency" do
|
17
|
-
expect { Honeybadger::Dependency.register {} }.to change(described_class, :instances).from([]).to([kind_of(Honeybadger::Dependency)])
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
describe ".inject!" do
|
22
|
-
it "injects all satisfied instances" do
|
23
|
-
Honeybadger::Dependency.instances.replace([mock_dependency, mock_dependency])
|
24
|
-
Honeybadger::Dependency.inject!
|
25
|
-
end
|
26
|
-
|
27
|
-
it "skips all unsatisfied instances" do
|
28
|
-
Honeybadger::Dependency.instances.replace([mock_dependency(false), mock_dependency(false)])
|
29
|
-
Honeybadger::Dependency.inject!
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
describe "#requirement" do
|
34
|
-
let(:block) { Proc.new {} }
|
35
|
-
|
36
|
-
it "returns and Array of requirements" do
|
37
|
-
expect(subject.requirement(&block)).to eq [block]
|
38
|
-
end
|
39
|
-
|
40
|
-
it "registers a new requirement" do
|
41
|
-
expect { subject.requirement(&block) }.to change(subject, :requirements).from([]).to([block])
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
describe "#injection" do
|
46
|
-
let(:block) { Proc.new {} }
|
47
|
-
|
48
|
-
it "returns an Array of injections" do
|
49
|
-
expect(subject.injection(&block)).to eq [block]
|
50
|
-
end
|
51
|
-
|
52
|
-
it "registers a new injection" do
|
53
|
-
expect { subject.injection(&block) }.to change(subject, :injections).from([]).to([block])
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
describe "#ok?" do
|
58
|
-
subject { dependency.ok? }
|
59
|
-
|
60
|
-
context "when not injected yet" do
|
61
|
-
it { should be_true }
|
62
|
-
end
|
63
|
-
|
64
|
-
context "when already injected" do
|
65
|
-
before { dependency.inject! }
|
66
|
-
|
67
|
-
it { should be_false }
|
68
|
-
end
|
69
|
-
|
70
|
-
context "all requirements are met" do
|
71
|
-
before do
|
72
|
-
3.times { dependency.requirement { true } }
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
context "some requirements fail" do
|
77
|
-
before do
|
78
|
-
3.times { dependency.requirement { true } }
|
79
|
-
dependency.requirement { false }
|
80
|
-
end
|
81
|
-
|
82
|
-
it { should be_false }
|
83
|
-
end
|
84
|
-
|
85
|
-
context "some requirements error" do
|
86
|
-
before do
|
87
|
-
dependency.requirement { true }
|
88
|
-
dependency.requirement { fail 'oops!' }
|
89
|
-
end
|
90
|
-
|
91
|
-
it { should be_false }
|
92
|
-
|
93
|
-
it "logs the failure" do
|
94
|
-
Honeybadger.should_receive(:write_verbose_log).with(/oops!/, :error).once
|
95
|
-
dependency.ok?
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
describe "#inject!" do
|
101
|
-
it "calls injections" do
|
102
|
-
dependency.injections.replace([mock_injection, mock_injection])
|
103
|
-
dependency.inject!
|
104
|
-
end
|
105
|
-
|
106
|
-
context "some injections fail" do
|
107
|
-
before do
|
108
|
-
failing_injection = Proc.new { fail 'oh noes!' }
|
109
|
-
dependency.injections.replace([mock_injection, failing_injection, mock_injection(false)])
|
110
|
-
end
|
111
|
-
|
112
|
-
it "halts injection silently" do
|
113
|
-
expect { dependency.inject! }.not_to raise_error
|
114
|
-
end
|
115
|
-
|
116
|
-
it "logs the failure" do
|
117
|
-
Honeybadger.should_receive(:write_verbose_log).with(/oh noes!/, :error).once
|
118
|
-
dependency.inject!
|
119
|
-
end
|
120
|
-
|
121
|
-
it "marks the dependency as injected" do
|
122
|
-
expect { dependency.inject!}.to change(dependency, :injected?).from(false).to(true)
|
123
|
-
end
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
def mock_dependency(ok = true)
|
128
|
-
double(:ok? => ok).tap { |d| d.send(ok ? :should_receive : :should_not_receive, :inject!) }
|
129
|
-
end
|
130
|
-
|
131
|
-
def mock_injection(positive = true)
|
132
|
-
double().tap { |d| d.send(positive ? :should_receive : :should_not_receive, :call) }
|
133
|
-
end
|
134
|
-
end
|
@@ -1,40 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Exception, :unless => defined?(BindingOfCaller) do
|
4
|
-
should { respond_to :__honeybadger_bindings_stack }
|
5
|
-
its(:__honeybadger_bindings_stack) { should eq([]) }
|
6
|
-
end
|
7
|
-
|
8
|
-
describe Exception, :if => defined?(BindingOfCaller) do
|
9
|
-
describe "#set_backtrace" do
|
10
|
-
context "call stack does not match current file" do
|
11
|
-
it "changes the bindings stack" do
|
12
|
-
expect { subject.set_backtrace(['foo.rb:1']) }.to change(subject, :__honeybadger_bindings_stack).from([])
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
context "call stack includes current file" do
|
17
|
-
before do
|
18
|
-
subject.stub(:caller).and_return(["#{File.expand_path('../../../lib/honeybadger/exception_extensions.rb', __FILE__)}:1"])
|
19
|
-
end
|
20
|
-
|
21
|
-
it "does not change the bindings stack" do
|
22
|
-
expect { subject.set_backtrace(['foo.rb:1']) }.not_to change(subject, :__honeybadger_bindings_stack).from([])
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
context "call stack includes a non-matching line" do
|
27
|
-
before do
|
28
|
-
subject.stub(:caller).and_return(['(foo)'])
|
29
|
-
end
|
30
|
-
|
31
|
-
it "skips the non-matching line" do
|
32
|
-
expect { subject.set_backtrace(['foo.rb:1']) }.not_to raise_error
|
33
|
-
end
|
34
|
-
|
35
|
-
it "changes the bindings stack" do
|
36
|
-
expect { subject.set_backtrace(['foo.rb:1']) }.to change(subject, :__honeybadger_bindings_stack).from([])
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
@@ -1,48 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe "DelayedJob Dependency" do
|
4
|
-
before do
|
5
|
-
Honeybadger::Dependency.reset!
|
6
|
-
end
|
7
|
-
|
8
|
-
context "when delayed_job is not installed" do
|
9
|
-
it "fails quietly" do
|
10
|
-
expect { Honeybadger::Dependency.inject! }.not_to raise_error
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
context "when delayed_job is installed" do
|
15
|
-
let(:plugins_array) { [] }
|
16
|
-
let(:plugin_class) do
|
17
|
-
Class.new do
|
18
|
-
def self.callbacks(&block)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
before do
|
24
|
-
Object.const_set(:Delayed, Module.new)
|
25
|
-
::Delayed.const_set(:Plugins, Module.new)
|
26
|
-
::Delayed::Plugins.const_set(:Plugin, plugin_class)
|
27
|
-
::Delayed.const_set(:Worker, double(:plugins => plugins_array))
|
28
|
-
end
|
29
|
-
|
30
|
-
after { Object.send(:remove_const, :Delayed) }
|
31
|
-
|
32
|
-
it "adds the plugin to DelayedJob" do
|
33
|
-
Honeybadger::Dependency.inject!
|
34
|
-
expect(plugins_array).to include(Honeybadger::Integrations::DelayedJob::Plugin)
|
35
|
-
end
|
36
|
-
|
37
|
-
context "and delayed_job_honeybadger is installed" do
|
38
|
-
before do
|
39
|
-
::Delayed::Plugins.const_set(:Honeybadger, Class.new(plugin_class))
|
40
|
-
end
|
41
|
-
|
42
|
-
it "warns the user of the conflict" do
|
43
|
-
Honeybadger.should_receive(:write_verbose_log).with(/Support for Delayed Job has been moved/, :warn).once
|
44
|
-
Honeybadger::Dependency.inject!
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
@@ -1,60 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe "Sidekiq Dependency" do
|
4
|
-
before do
|
5
|
-
Honeybadger::Dependency.reset!
|
6
|
-
end
|
7
|
-
|
8
|
-
context "when sidekiq is not installed" do
|
9
|
-
it "fails quietly" do
|
10
|
-
expect { Honeybadger::Dependency.inject! }.not_to raise_error
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
context "when sidekiq is installed" do
|
15
|
-
let(:shim) do
|
16
|
-
Class.new do
|
17
|
-
def self.configure_server
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
let(:config) { double('config', :error_handlers => []) }
|
23
|
-
let(:chain) { double('chain', :add => true) }
|
24
|
-
|
25
|
-
before do
|
26
|
-
Object.const_set(:Sidekiq, shim)
|
27
|
-
::Sidekiq.stub(:configure_server).and_yield(config)
|
28
|
-
config.stub(:server_middleware).and_yield(chain)
|
29
|
-
end
|
30
|
-
|
31
|
-
after { Object.send(:remove_const, :Sidekiq) }
|
32
|
-
|
33
|
-
context "when version is less than 3" do
|
34
|
-
before do
|
35
|
-
::Sidekiq.const_set(:VERSION, '2.17.7')
|
36
|
-
end
|
37
|
-
|
38
|
-
it "adds the server middleware" do
|
39
|
-
chain.should_receive(:add).with(Honeybadger::Integrations::Sidekiq::Middleware)
|
40
|
-
Honeybadger::Dependency.inject!
|
41
|
-
end
|
42
|
-
|
43
|
-
it "doesn't add the error handler" do
|
44
|
-
Honeybadger::Dependency.inject!
|
45
|
-
expect(config.error_handlers).to be_empty
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
context "when version is 3 or greater" do
|
50
|
-
before do
|
51
|
-
::Sidekiq.const_set(:VERSION, '3.0.0')
|
52
|
-
end
|
53
|
-
|
54
|
-
it "adds the error handler" do
|
55
|
-
Honeybadger::Dependency.inject!
|
56
|
-
expect(config.error_handlers).not_to be_empty
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe "Thor Dependency" do
|
4
|
-
before do
|
5
|
-
Honeybadger::Dependency.reset!
|
6
|
-
end
|
7
|
-
|
8
|
-
context "when thor is not installed" do
|
9
|
-
it "fails quietly" do
|
10
|
-
expect { Honeybadger::Dependency.inject! }.not_to raise_error
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
context "when thor is installed" do
|
15
|
-
let(:shim) do
|
16
|
-
double('fake thor')
|
17
|
-
end
|
18
|
-
|
19
|
-
before do
|
20
|
-
Object.const_set(:Thor, shim)
|
21
|
-
end
|
22
|
-
after { Object.send(:remove_const, :Thor) }
|
23
|
-
|
24
|
-
it "includes integration module into Thor" do
|
25
|
-
shim.should_receive(:send).with(:include, Honeybadger::Integrations::Thor)
|
26
|
-
Honeybadger::Dependency.inject!
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Honeybadger::Payload do
|
4
|
-
its(:max_depth) { should eq 20 }
|
5
|
-
|
6
|
-
context "when max_depth option is passed to #initialize" do
|
7
|
-
subject { described_class.new({}, :max_depth => 5) }
|
8
|
-
its(:max_depth) { should eq 5 }
|
9
|
-
|
10
|
-
context "when initialized with a bad object" do
|
11
|
-
it "raises ArgumentError" do
|
12
|
-
expect { described_class.new([], :max_depth => 5) }.to raise_error(ArgumentError)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
describe "#sanitize" do
|
18
|
-
let(:deep_hash) { {}.tap {|h| 30.times.each {|i| h = h[i.to_s] = {:string => 'string'} }} }
|
19
|
-
let(:expected_hash) { {}.tap {|h| max_depth.times.each {|i| h = h[i.to_s] = {:string => 'string'} }} }
|
20
|
-
let(:sanitized_hash) { described_class.new(deep_hash, :max_depth => max_depth) }
|
21
|
-
let(:max_depth) { 10 }
|
22
|
-
|
23
|
-
it "truncates nested hashes to max_depth" do
|
24
|
-
expect(sanitized_hash).to eq(expected_hash)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|