opbeat 0.9.1 → 0.9.2
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 +7 -0
- data/.gitignore +5 -0
- data/.rspec +2 -0
- data/.travis.yml +25 -0
- data/Gemfile +2 -0
- data/Makefile +3 -0
- data/README.md +13 -0
- data/Rakefile +19 -0
- data/gemfiles/rails30.gemfile +11 -0
- data/gemfiles/rails31.gemfile +11 -0
- data/gemfiles/rails32.gemfile +11 -0
- data/gemfiles/rails40.gemfile +12 -0
- data/gemfiles/rails41.gemfile +12 -0
- data/gemfiles/ruby192_rails31.gemfile +12 -0
- data/gemfiles/ruby192_rails32.gemfile +12 -0
- data/gemfiles/sidekiq31.gemfile +11 -0
- data/lib/opbeat/better_attr_accessor.rb +44 -0
- data/lib/opbeat/capistrano/capistrano3.rb +7 -19
- data/lib/opbeat/client.rb +5 -5
- data/lib/opbeat/event.rb +3 -3
- data/lib/opbeat/interfaces/exception.rb +3 -3
- data/lib/opbeat/interfaces/http.rb +9 -9
- data/lib/opbeat/interfaces/message.rb +2 -2
- data/lib/opbeat/interfaces/stack_trace.rb +9 -18
- data/lib/opbeat/interfaces.rb +12 -14
- data/lib/opbeat/version.rb +1 -1
- data/opbeat.gemspec +28 -0
- data/spec/opbeat/better_attr_accessor_spec.rb +99 -0
- data/spec/opbeat/client_spec.rb +25 -0
- data/spec/opbeat/configuration_spec.rb +50 -0
- data/spec/opbeat/event_spec.rb +130 -0
- data/spec/opbeat/integrations/delayed_job_spec.rb +38 -0
- data/spec/opbeat/logger_spec.rb +55 -0
- data/spec/opbeat/opbeat_spec.rb +39 -0
- data/spec/opbeat/rack_spec.rb +117 -0
- data/spec/opbeat/sanitizedata_processor_spec.rb +42 -0
- data/spec/spec_helper.rb +10 -0
- metadata +142 -45
@@ -0,0 +1,50 @@
|
|
1
|
+
require File::expand_path('../../spec_helper', __FILE__)
|
2
|
+
require 'opbeat'
|
3
|
+
|
4
|
+
describe Opbeat::Configuration do
|
5
|
+
before do
|
6
|
+
# Make sure we reset the env in case something leaks in
|
7
|
+
ENV.delete('OPBEAT_ORGANIZATION_ID')
|
8
|
+
ENV.delete('OPBEAT_APP_ID')
|
9
|
+
ENV.delete('OPBEAT_SECRET_TOKEN')
|
10
|
+
end
|
11
|
+
|
12
|
+
shared_examples 'a complete configuration' do
|
13
|
+
it 'should have a server' do
|
14
|
+
expect(subject[:server]).to eq('http://opbeat.localdomain/opbeat')
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should have an secret token' do
|
18
|
+
expect(subject[:secret_token]).to eq('67890')
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should have an organization ID' do
|
22
|
+
expect(subject[:organization_id]).to eq('42')
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should have an app ID' do
|
26
|
+
expect(subject[:app_id]).to eq('43')
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'being initialized with options' do
|
31
|
+
before do
|
32
|
+
subject.server = 'http://opbeat.localdomain/opbeat'
|
33
|
+
subject.secret_token = '67890'
|
34
|
+
subject.organization_id = '42'
|
35
|
+
subject.app_id = '43'
|
36
|
+
end
|
37
|
+
it_should_behave_like 'a complete configuration'
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'being initialized with an environment variable' do
|
41
|
+
subject do
|
42
|
+
ENV['OPBEAT_ORGANIZATION_ID'] = '42'
|
43
|
+
ENV['OPBEAT_APP_ID'] = '43'
|
44
|
+
ENV['OPBEAT_SECRET_TOKEN'] = '67890'
|
45
|
+
ENV['OPBEAT_SERVER'] = 'http://opbeat.localdomain/opbeat'
|
46
|
+
Opbeat::Configuration.new
|
47
|
+
end
|
48
|
+
it_should_behave_like 'a complete configuration'
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
require File::expand_path('../../spec_helper', __FILE__)
|
2
|
+
require 'opbeat'
|
3
|
+
|
4
|
+
describe Opbeat::Event do
|
5
|
+
describe '.capture_message' do
|
6
|
+
let(:message) { 'This is a message' }
|
7
|
+
let(:hash) { Opbeat::Event.capture_message(message).to_hash }
|
8
|
+
|
9
|
+
context 'for a Message' do
|
10
|
+
it 'returns an event' do
|
11
|
+
expect(Opbeat::Event.capture_message(message)).to be_a(Opbeat::Event)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "sets the message to the value passed" do
|
15
|
+
expect(hash['message']).to eq(message)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'has level ERROR' do
|
19
|
+
expect(hash['level']).to eq('error')
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '.capture_exception' do
|
25
|
+
let(:message) { 'This is a message' }
|
26
|
+
let(:exception) { Exception.new(message) }
|
27
|
+
let(:hash) { Opbeat::Event.capture_exception(exception).to_hash }
|
28
|
+
|
29
|
+
context 'for an Exception' do
|
30
|
+
it 'returns an event' do
|
31
|
+
expect(Opbeat::Event.capture_exception(exception)).to be_a(Opbeat::Event)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "sets the message to the exception's message and type" do
|
35
|
+
expect(hash['message']).to eq("Exception: #{message}")
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'has level ERROR' do
|
39
|
+
expect(hash['level']).to eq('error')
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'uses the exception class name as the exception type' do
|
43
|
+
expect(hash['exception']['type']).to eq('Exception')
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'uses the exception message as the exception value' do
|
47
|
+
expect(hash['exception']['value']).to eq(message)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'does not belong to a module' do
|
51
|
+
expect(hash['exception']['module']).to eq('')
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'for a nested exception type' do
|
56
|
+
module Opbeat::Test
|
57
|
+
class Exception < Exception; end
|
58
|
+
end
|
59
|
+
let(:exception) { Opbeat::Test::Exception.new(message) }
|
60
|
+
|
61
|
+
it 'sends the module name as part of the exception info' do
|
62
|
+
expect(hash['exception']['module']).to eq('Opbeat::Test')
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'for a Opbeat::Error' do
|
67
|
+
let(:exception) { Opbeat::Error.new }
|
68
|
+
it 'does not create an event' do
|
69
|
+
expect(Opbeat::Event.capture_exception(exception)).to be_nil
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'when the exception has a backtrace' do
|
74
|
+
let(:exception) do
|
75
|
+
e = Exception.new(message)
|
76
|
+
allow(e).to receive(:backtrace).and_return([
|
77
|
+
"/path/to/some/file:22:in `function_name'",
|
78
|
+
"/some/other/path:1412:in `other_function'",
|
79
|
+
])
|
80
|
+
e
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'parses the backtrace' do
|
84
|
+
expect(hash['stacktrace']['frames'].length).to eq(2)
|
85
|
+
expect(hash['stacktrace']['frames'][0]['lineno']).to eq(1412)
|
86
|
+
expect(hash['stacktrace']['frames'][0]['function']).to eq('other_function')
|
87
|
+
expect(hash['stacktrace']['frames'][0]['filename']).to eq('/some/other/path')
|
88
|
+
|
89
|
+
expect(hash['stacktrace']['frames'][1]['lineno']).to eq(22)
|
90
|
+
expect(hash['stacktrace']['frames'][1]['function']).to eq('function_name')
|
91
|
+
expect(hash['stacktrace']['frames'][1]['filename']).to eq('/path/to/some/file')
|
92
|
+
end
|
93
|
+
|
94
|
+
it "sets the culprit" do
|
95
|
+
expect(hash['culprit']).to eq("/some/other/path in other_function")
|
96
|
+
end
|
97
|
+
|
98
|
+
context 'when a path in the stack trace is on the laod path' do
|
99
|
+
before do
|
100
|
+
$LOAD_PATH << '/some'
|
101
|
+
end
|
102
|
+
|
103
|
+
after do
|
104
|
+
$LOAD_PATH.delete('/some')
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'strips prefixes in the load path from frame filenames' do
|
108
|
+
expect(hash['stacktrace']['frames'][0]['filename']).to eq('other/path')
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
context 'when there is user context' do
|
114
|
+
it 'sends the context and is_authenticated' do
|
115
|
+
Opbeat::Event.set_context(:user => {:id => 99})
|
116
|
+
hash = Opbeat::Event.capture_exception(exception).to_hash
|
117
|
+
expect(hash['user']).to eq({:id => 99, :is_authenticated => true})
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
context 'when there is extra context' do
|
122
|
+
it 'sends the context and is_authenticated' do
|
123
|
+
extra_context = {:jobid => 99}
|
124
|
+
Opbeat::Event.set_context(:extra => extra_context)
|
125
|
+
hash = Opbeat::Event.capture_exception(exception).to_hash
|
126
|
+
expect(hash['extra']).to eq(extra_context)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require File::expand_path('../../../spec_helper', __FILE__)
|
2
|
+
require 'time'
|
3
|
+
require 'delayed_job'
|
4
|
+
require 'opbeat/integrations/delayed_job'
|
5
|
+
|
6
|
+
# turtles, all the way down
|
7
|
+
# trying too hard
|
8
|
+
require 'active_support/core_ext/time/calculations.rb'
|
9
|
+
load File.join(
|
10
|
+
Gem::Specification.find_by_name("delayed_job").gem_dir,
|
11
|
+
"spec", "delayed", "backend", "test.rb"
|
12
|
+
)
|
13
|
+
|
14
|
+
|
15
|
+
class Bomb
|
16
|
+
def blow_up ex
|
17
|
+
raise ex
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
Delayed::Worker.backend = Delayed::Backend::Test::Job
|
23
|
+
|
24
|
+
describe Delayed::Plugins::Opbeat do
|
25
|
+
it 'should call Opbeat::captureException on erronous jobs' do
|
26
|
+
test_exception = Exception.new("Test exception")
|
27
|
+
expect(Opbeat).to receive(:captureException).with(test_exception)
|
28
|
+
|
29
|
+
# Queue
|
30
|
+
bomb = Bomb.new
|
31
|
+
bomb.delay.blow_up test_exception
|
32
|
+
|
33
|
+
expect {
|
34
|
+
Delayed::Worker.new.work_off.should == [0, 1]
|
35
|
+
}.to raise_error(Exception)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require File::expand_path('../../spec_helper', __FILE__)
|
2
|
+
require 'opbeat'
|
3
|
+
|
4
|
+
describe Opbeat::Logger do
|
5
|
+
context 'without a backend logger' do
|
6
|
+
before do
|
7
|
+
allow(Opbeat.configuration).to receive(:logger) { nil }
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should not error' do
|
11
|
+
subject.fatal 'fatalmsg'
|
12
|
+
subject.error 'errormsg'
|
13
|
+
subject.warn 'warnmsg'
|
14
|
+
subject.info 'infomsg'
|
15
|
+
subject.debug 'debugmsg'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'with a backend logger' do
|
20
|
+
before do
|
21
|
+
@logger = double('logger')
|
22
|
+
allow(Opbeat.configuration).to receive(:logger) { @logger }
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should log fatal messages' do
|
26
|
+
expect(@logger).to receive(:fatal).with('** [Opbeat] fatalmsg')
|
27
|
+
subject.fatal 'fatalmsg'
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should log error messages' do
|
31
|
+
expect(@logger).to receive(:error).with('** [Opbeat] errormsg')
|
32
|
+
subject.error 'errormsg'
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should log warning messages' do
|
36
|
+
expect(@logger).to receive(:warn).with('** [Opbeat] warnmsg')
|
37
|
+
subject.warn 'warnmsg'
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should log info messages' do
|
41
|
+
expect(@logger).to receive(:info).with('** [Opbeat] infomsg')
|
42
|
+
subject.info 'infomsg'
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should log debug messages' do
|
46
|
+
expect(@logger).to receive(:debug).with('** [Opbeat] debugmsg')
|
47
|
+
subject.debug 'debugmsg'
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should log messages from blocks' do
|
51
|
+
expect(@logger).to receive(:info).with('** [Opbeat] infoblock')
|
52
|
+
subject.info { 'infoblock' }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require File::expand_path('../../spec_helper', __FILE__)
|
2
|
+
require 'opbeat'
|
3
|
+
|
4
|
+
describe Opbeat do
|
5
|
+
before do
|
6
|
+
@send = double("send")
|
7
|
+
@event = double("event")
|
8
|
+
allow(Opbeat).to receive(:send) { @send }
|
9
|
+
allow(Opbeat::Event).to receive(:capture_message) { @event }
|
10
|
+
allow(Opbeat::Event).to receive(:capture_exception) { @event }
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'captureMessage should send result of Event.capture_message' do
|
14
|
+
message = "Test message"
|
15
|
+
expect(Opbeat::Event).to receive(:capture_message).with(message, {})
|
16
|
+
expect(Opbeat).to receive(:send).with(@event)
|
17
|
+
|
18
|
+
Opbeat.captureMessage(message)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'captureMessage with options should send result of Event.capture_message' do
|
22
|
+
message = "Test message"
|
23
|
+
options = {:extra => {:hello => "world"}}
|
24
|
+
expect(Opbeat::Event).to receive(:capture_message).with(message, options)
|
25
|
+
expect(Opbeat).to receive(:send).with(@event)
|
26
|
+
|
27
|
+
Opbeat.captureMessage(message, options)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'captureException should send result of Event.capture_exception' do
|
31
|
+
exception = build_exception()
|
32
|
+
|
33
|
+
expect(Opbeat::Event).to receive(:capture_exception).with(exception, {})
|
34
|
+
expect(Opbeat).to receive(:send).with(@event)
|
35
|
+
|
36
|
+
Opbeat.captureException(exception)
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require File::expand_path('../../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
require 'opbeat'
|
4
|
+
require 'opbeat/interfaces'
|
5
|
+
|
6
|
+
class User
|
7
|
+
attr_accessor :id, :email, :username
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
class TestController
|
12
|
+
def current_user
|
13
|
+
test_user = User.new
|
14
|
+
test_user.id = 99
|
15
|
+
test_user.email = "ron@opbeat.com"
|
16
|
+
test_user.username = "roncohen"
|
17
|
+
|
18
|
+
return test_user
|
19
|
+
end
|
20
|
+
|
21
|
+
def custom_user
|
22
|
+
test_user = User.new
|
23
|
+
test_user.id = 999
|
24
|
+
test_user.email = "custom@opbeat.com"
|
25
|
+
test_user.username = "custom"
|
26
|
+
|
27
|
+
return test_user
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
|
33
|
+
describe Opbeat::Rack do
|
34
|
+
before do
|
35
|
+
@send = double("send")
|
36
|
+
@event = double("event")
|
37
|
+
allow(Opbeat).to receive(:send) { @send }
|
38
|
+
allow(Opbeat::Event).to receive(:capture_rack_exception) { @event }
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should capture exceptions' do
|
42
|
+
exception = build_exception()
|
43
|
+
env = {}
|
44
|
+
|
45
|
+
expect(Opbeat::Event).to receive(:capture_rack_exception).with(exception, env)
|
46
|
+
expect(Opbeat).to receive(:send).with(@event)
|
47
|
+
|
48
|
+
app = lambda do |e|
|
49
|
+
raise exception
|
50
|
+
end
|
51
|
+
|
52
|
+
stack = Opbeat::Rack.new(app)
|
53
|
+
expect(lambda {stack.call(env)}).to raise_error(exception)
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should capture rack.exception' do
|
57
|
+
exception = build_exception()
|
58
|
+
env = {}
|
59
|
+
|
60
|
+
expect(Opbeat::Event).to receive(:capture_rack_exception).with(exception, env)
|
61
|
+
expect(Opbeat).to receive(:send).with(@event)
|
62
|
+
|
63
|
+
app = lambda do |e|
|
64
|
+
e['rack.exception'] = exception
|
65
|
+
[200, {}, ['okay']]
|
66
|
+
end
|
67
|
+
|
68
|
+
stack = Opbeat::Rack.new(app)
|
69
|
+
|
70
|
+
stack.call(env)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
describe Opbeat::Rack do
|
76
|
+
before do
|
77
|
+
@exception = build_exception()
|
78
|
+
@env = {
|
79
|
+
'action_controller.instance' => TestController.new
|
80
|
+
}
|
81
|
+
allow(Opbeat::HttpInterface).to receive(:new) { Opbeat::Interface.new }
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'should extract user info' do
|
85
|
+
expected_user = TestController.new.current_user
|
86
|
+
|
87
|
+
Opbeat::Event.capture_rack_exception(@exception, @env) do |event|
|
88
|
+
user = event.to_hash['user']
|
89
|
+
expect(user[:id]).to eq(expected_user.id)
|
90
|
+
expect(user[:email]).to eq(expected_user.email)
|
91
|
+
expect(user[:username]).to eq(expected_user.username)
|
92
|
+
expect(user[:is_authenticated]).to eq(true)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'should handle custom user method' do
|
97
|
+
Opbeat.configuration.user_controller_method = :custom_user
|
98
|
+
expected_user = TestController.new.custom_user
|
99
|
+
|
100
|
+
Opbeat::Event.capture_rack_exception(@exception, @env) do |event|
|
101
|
+
user = event.to_hash['user']
|
102
|
+
expect(user[:id]).to eq(expected_user.id)
|
103
|
+
expect(user[:email]).to eq(expected_user.email)
|
104
|
+
expect(user[:username]).to eq(expected_user.username)
|
105
|
+
expect(user[:is_authenticated]).to eq(true)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'should handle missing user method' do
|
110
|
+
Opbeat.configuration.user_controller_method = :missing_user_method
|
111
|
+
expected_user = TestController.new.custom_user
|
112
|
+
|
113
|
+
Opbeat::Event.capture_rack_exception(@exception, @env) do |event|
|
114
|
+
expect(event.user).to eq(nil)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require File::expand_path('../../spec_helper', __FILE__)
|
2
|
+
require 'opbeat/processors/sanitizedata'
|
3
|
+
|
4
|
+
describe Opbeat::Processor::SanitizeData do
|
5
|
+
before do
|
6
|
+
@client = double("client")
|
7
|
+
@processor = Opbeat::Processor::SanitizeData.new(@client)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should filter http data' do
|
11
|
+
data = {
|
12
|
+
'http' => {
|
13
|
+
'data' => {
|
14
|
+
'foo' => 'bar',
|
15
|
+
'password' => 'hello',
|
16
|
+
'the_secret' => 'hello',
|
17
|
+
'a_password_here' => 'hello',
|
18
|
+
'mypasswd' => 'hello',
|
19
|
+
}
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
23
|
+
result = @processor.process(data)
|
24
|
+
|
25
|
+
vars = result["http"]["data"]
|
26
|
+
expect(vars["foo"]).to eq("bar")
|
27
|
+
expect(vars["password"]).to eq(Opbeat::Processor::SanitizeData::MASK)
|
28
|
+
expect(vars["the_secret"]).to eq(Opbeat::Processor::SanitizeData::MASK)
|
29
|
+
expect(vars["a_password_here"]).to eq(Opbeat::Processor::SanitizeData::MASK)
|
30
|
+
expect(vars["mypasswd"]).to eq(Opbeat::Processor::SanitizeData::MASK)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should filter credit card values' do
|
34
|
+
data = {
|
35
|
+
'ccnumba' => '4242424242424242'
|
36
|
+
}
|
37
|
+
|
38
|
+
result = @processor.process(data)
|
39
|
+
expect(result["ccnumba"]).to eq(Opbeat::Processor::SanitizeData::MASK)
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|