kuende-opbeat 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +36 -0
  5. data/Gemfile +2 -0
  6. data/LICENSE +205 -0
  7. data/Makefile +3 -0
  8. data/README.md +267 -0
  9. data/Rakefile +19 -0
  10. data/gemfiles/rails30.gemfile +9 -0
  11. data/gemfiles/rails31.gemfile +9 -0
  12. data/gemfiles/rails32.gemfile +9 -0
  13. data/gemfiles/rails40.gemfile +9 -0
  14. data/gemfiles/rails41.gemfile +9 -0
  15. data/gemfiles/rails42.gemfile +9 -0
  16. data/gemfiles/ruby192_rails31.gemfile +10 -0
  17. data/gemfiles/ruby192_rails32.gemfile +10 -0
  18. data/gemfiles/sidekiq31.gemfile +11 -0
  19. data/lib/opbeat.rb +132 -0
  20. data/lib/opbeat/better_attr_accessor.rb +44 -0
  21. data/lib/opbeat/capistrano.rb +9 -0
  22. data/lib/opbeat/capistrano/capistrano2.rb +47 -0
  23. data/lib/opbeat/capistrano/capistrano3.rb +26 -0
  24. data/lib/opbeat/client.rb +122 -0
  25. data/lib/opbeat/configuration.rb +90 -0
  26. data/lib/opbeat/error.rb +6 -0
  27. data/lib/opbeat/event.rb +223 -0
  28. data/lib/opbeat/filter.rb +63 -0
  29. data/lib/opbeat/integrations/delayed_job.rb +32 -0
  30. data/lib/opbeat/integrations/resque.rb +22 -0
  31. data/lib/opbeat/integrations/sidekiq.rb +32 -0
  32. data/lib/opbeat/interfaces.rb +35 -0
  33. data/lib/opbeat/interfaces/exception.rb +16 -0
  34. data/lib/opbeat/interfaces/http.rb +57 -0
  35. data/lib/opbeat/interfaces/message.rb +19 -0
  36. data/lib/opbeat/interfaces/stack_trace.rb +50 -0
  37. data/lib/opbeat/linecache.rb +25 -0
  38. data/lib/opbeat/logger.rb +21 -0
  39. data/lib/opbeat/rack.rb +44 -0
  40. data/lib/opbeat/rails/middleware/debug_exceptions_catcher.rb +22 -0
  41. data/lib/opbeat/railtie.rb +26 -0
  42. data/lib/opbeat/tasks.rb +24 -0
  43. data/lib/opbeat/version.rb +3 -0
  44. data/opbeat.gemspec +28 -0
  45. data/spec/opbeat/better_attr_accessor_spec.rb +99 -0
  46. data/spec/opbeat/client_spec.rb +35 -0
  47. data/spec/opbeat/configuration_spec.rb +50 -0
  48. data/spec/opbeat/event_spec.rb +138 -0
  49. data/spec/opbeat/filter_spec.rb +101 -0
  50. data/spec/opbeat/integrations/delayed_job_spec.rb +38 -0
  51. data/spec/opbeat/logger_spec.rb +55 -0
  52. data/spec/opbeat/opbeat_spec.rb +89 -0
  53. data/spec/opbeat/rack_spec.rb +116 -0
  54. data/spec/spec_helper.rb +22 -0
  55. metadata +218 -0
@@ -0,0 +1,35 @@
1
+ require File::expand_path('../../spec_helper', __FILE__)
2
+ require 'opbeat'
3
+ require 'faraday'
4
+
5
+ http = Faraday.new do |builder|
6
+ builder.adapter :test do |stub|
7
+ stub.get('/') { |env| [ 200, {}, 'foo' ]}
8
+ end
9
+ end
10
+
11
+ describe Opbeat::Client do
12
+ before do
13
+ @configuration = Opbeat::Configuration.new
14
+ @configuration.environments = ["test"]
15
+ @configuration.current_environment = :test
16
+ @configuration.secret_token = 'test'
17
+ @configuration.organization_id = 'test'
18
+ @configuration.app_id = 'test'
19
+ @client = Opbeat::Client.new(@configuration)
20
+ allow(@client).to receive(:send)
21
+ end
22
+
23
+ it 'send_release should send' do
24
+ message = "Test message"
25
+ expect(@client).to receive(:send).with("/releases/", message)
26
+ @client.send_release(message)
27
+ end
28
+
29
+ it 'send_message should send' do
30
+ event = Opbeat::Event.new :message => "my message"
31
+ req = http.get '/'
32
+ expect(@client).to receive(:send).with("/errors/", event).and_return(req)
33
+ @client.send_event(event)
34
+ end
35
+ end
@@ -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,138 @@
1
+ require File::expand_path('../../spec_helper', __FILE__)
2
+ require 'opbeat'
3
+
4
+ describe Opbeat::Event do
5
+ describe '.from_message' do
6
+ let(:message) { 'This is a message' }
7
+ let(:hash) { Opbeat::Event.from_message(message, caller).to_hash }
8
+
9
+ context 'for a Message' do
10
+ it 'returns an event' do
11
+ expect(Opbeat::Event.from_message(message, caller)).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 '.from_exception' do
25
+ let(:message) { 'This is a message' }
26
+ let(:exception) {
27
+ exc = Exception.new(message)
28
+ exc.set_backtrace caller
29
+ exc
30
+ }
31
+ let(:hash) { Opbeat::Event.from_exception(exception).to_hash }
32
+
33
+ context 'for an Exception' do
34
+ it 'returns an event' do
35
+ expect(Opbeat::Event.from_exception(exception)).to be_a(Opbeat::Event)
36
+ end
37
+
38
+ it "sets the message to the exception's message and type" do
39
+ expect(hash['message']).to eq("Exception: #{message}")
40
+ end
41
+
42
+ it 'has level ERROR' do
43
+ expect(hash['level']).to eq('error')
44
+ end
45
+
46
+ it 'uses the exception class name as the exception type' do
47
+ expect(hash['exception']['type']).to eq('Exception')
48
+ end
49
+
50
+ it 'uses the exception message as the exception value' do
51
+ expect(hash['exception']['value']).to eq(message)
52
+ end
53
+
54
+ it 'does not belong to a module' do
55
+ expect(hash['exception']['module']).to eq('')
56
+ end
57
+ end
58
+
59
+ context 'for a nested exception type' do
60
+ module Opbeat::Test
61
+ class Exception < Exception; end
62
+ end
63
+ let(:exception) {
64
+ exc = Opbeat::Test::Exception.new(message)
65
+ exc.set_backtrace caller
66
+ exc
67
+ }
68
+
69
+ it 'sends the module name as part of the exception info' do
70
+ expect(hash['exception']['module']).to eq('Opbeat::Test')
71
+ end
72
+ end
73
+
74
+ context 'for a Opbeat::Error' do
75
+ let(:exception) { Opbeat::Error.new }
76
+ it 'does not create an event' do
77
+ expect(Opbeat::Event.from_exception(exception)).to be_nil
78
+ end
79
+ end
80
+
81
+ context 'when the exception has a backtrace' do
82
+ let(:exception) do
83
+ e = Exception.new(message)
84
+ allow(e).to receive(:backtrace).and_return([
85
+ "/path/to/some/file:22:in `function_name'",
86
+ "/some/other/path:1412:in `other_function'",
87
+ ])
88
+ e
89
+ end
90
+
91
+ it 'parses the backtrace' do
92
+ expect(hash['stacktrace']['frames'].length).to eq(2)
93
+ expect(hash['stacktrace']['frames'][0]['lineno']).to eq(1412)
94
+ expect(hash['stacktrace']['frames'][0]['function']).to eq('other_function')
95
+ expect(hash['stacktrace']['frames'][0]['filename']).to eq('/some/other/path')
96
+
97
+ expect(hash['stacktrace']['frames'][1]['lineno']).to eq(22)
98
+ expect(hash['stacktrace']['frames'][1]['function']).to eq('function_name')
99
+ expect(hash['stacktrace']['frames'][1]['filename']).to eq('/path/to/some/file')
100
+ end
101
+
102
+ it "sets the culprit" do
103
+ expect(hash['culprit']).to eq("/some/other/path in other_function")
104
+ end
105
+
106
+ context 'when a path in the stack trace is on the laod path' do
107
+ before do
108
+ $LOAD_PATH << '/some'
109
+ end
110
+
111
+ after do
112
+ $LOAD_PATH.delete('/some')
113
+ end
114
+
115
+ it 'strips prefixes in the load path from frame filenames' do
116
+ expect(hash['stacktrace']['frames'][0]['filename']).to eq('other/path')
117
+ end
118
+ end
119
+ end
120
+
121
+ context 'when there is user context' do
122
+ it 'sends the context and is_authenticated' do
123
+ Opbeat::Event.set_context(:user => {:id => 99})
124
+ hash = Opbeat::Event.from_exception(exception).to_hash
125
+ expect(hash['user']).to eq({:id => 99, :is_authenticated => true})
126
+ end
127
+ end
128
+
129
+ context 'when there is extra context' do
130
+ it 'sends the context and is_authenticated' do
131
+ extra_context = {:jobid => 99}
132
+ Opbeat::Event.set_context(:extra => extra_context)
133
+ hash = Opbeat::Event.from_exception(exception).to_hash
134
+ expect(hash['extra']).to eq(extra_context)
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,101 @@
1
+ require File::expand_path('../../spec_helper', __FILE__)
2
+ require 'opbeat/filter'
3
+
4
+ describe Opbeat::Filter do
5
+ it 'should filter http data by default' do
6
+ data = {
7
+ 'http' => {
8
+ 'data' => {
9
+ 'foo' => 'bar',
10
+ 'password' => 'hello',
11
+ 'the_secret' => 'hello',
12
+ 'a_password_here' => 'hello',
13
+ 'mypasswd' => 'hello'
14
+ }
15
+ }
16
+ }
17
+
18
+ filter = Opbeat::Filter.new
19
+ result = filter.process_event_hash(data)
20
+
21
+ vars = result["http"]["data"]
22
+ expect(vars["foo"]).to eq("bar")
23
+ expect(vars["password"]).to eq(Opbeat::Filter::MASK)
24
+ expect(vars["the_secret"]).to eq(Opbeat::Filter::MASK)
25
+ expect(vars["a_password_here"]).to eq(Opbeat::Filter::MASK)
26
+ expect(vars["mypasswd"]).to eq(Opbeat::Filter::MASK)
27
+ end
28
+
29
+ it 'should filter http query_string by default' do
30
+ data = {
31
+ 'http' => {
32
+ 'query_string' => 'foo=bar&password=secret'
33
+ }
34
+ }
35
+
36
+ filter = Opbeat::Filter.new
37
+ result = filter.process_event_hash(data)
38
+
39
+ expect(result["http"]["query_string"]).to eq('foo=bar&password=' + Opbeat::Filter::MASK)
40
+ end
41
+
42
+ it 'should filter http cookies by default' do
43
+ data = {
44
+ 'http' => {
45
+ 'cookies' => 'foo=bar;password=secret'
46
+ }
47
+ }
48
+
49
+ filter = Opbeat::Filter.new
50
+ result = filter.process_event_hash(data)
51
+
52
+ expect(result["http"]["cookies"]).to eq('foo=bar;password=' + Opbeat::Filter::MASK)
53
+ end
54
+
55
+ it 'should not filter env, extra or headers' do
56
+ data = {
57
+ 'http' => {
58
+ 'env' => { 'password' => 'hello' },
59
+ 'extra' => { 'password' => 'hello' },
60
+ 'headers' => { 'password' => 'hello' }
61
+ }
62
+ }
63
+
64
+ filter = Opbeat::Filter.new
65
+ result = filter.process_event_hash(data)
66
+
67
+ expect(result).to eq(data)
68
+ end
69
+
70
+ it 'should be configurable' do
71
+ data = {
72
+ 'http' => {
73
+ 'data' => {
74
+ 'foo' => 'secret',
75
+ 'bar' => 'secret',
76
+ '-baz-' => 'secret',
77
+ 'password' => 'public',
78
+ 'the_secret' => 'public',
79
+ 'a_password_here' => 'public',
80
+ 'mypasswd' => 'public'
81
+ },
82
+ 'query_string' => 'foo=secret&password=public',
83
+ 'cookies' => 'foo=secret;password=public'
84
+ }
85
+ }
86
+
87
+ filter = Opbeat::Filter.new [:foo, 'bar', /baz/]
88
+ result = filter.process_event_hash(data)
89
+
90
+ vars = result["http"]["data"]
91
+ expect(vars["foo"]).to eq(Opbeat::Filter::MASK)
92
+ expect(vars["bar"]).to eq(Opbeat::Filter::MASK)
93
+ expect(vars["-baz-"]).to eq(Opbeat::Filter::MASK)
94
+ expect(vars["password"]).to eq("public")
95
+ expect(vars["the_secret"]).to eq("public")
96
+ expect(vars["a_password_here"]).to eq("public")
97
+ expect(vars["mypasswd"]).to eq("public")
98
+ expect(result["http"]["query_string"]).to eq('foo=' + Opbeat::Filter::MASK + '&password=public')
99
+ expect(result["http"]["cookies"]).to eq('foo=' + Opbeat::Filter::MASK + ';password=public')
100
+ end
101
+ 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::capture_exception on erronous jobs' do
26
+ test_exception = Exception.new("Test exception")
27
+ expect(Opbeat).to receive(:capture_exception).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,89 @@
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(:from_message) { @event }
10
+ allow(Opbeat::Event).to receive(:from_exception) { @event }
11
+ allow(Opbeat::Event).to receive(:from_rack_exception) { @event }
12
+ end
13
+
14
+ it 'capture_message should send result of Event.from_message' do
15
+ message = "Test message"
16
+ expect(Opbeat::Event).to receive(:from_message).with(message, an_instance_of(Array), {})
17
+ expect(Opbeat).to receive(:send).with(@event)
18
+
19
+ Opbeat.capture_message(message)
20
+ end
21
+
22
+ it 'capture_message with options should send result of Event.from_message' do
23
+ message = "Test message"
24
+ options = {:extra => {:hello => "world"}}
25
+ expect(Opbeat::Event).to receive(:from_message).with(message, an_instance_of(Array), options)
26
+ expect(Opbeat).to receive(:send).with(@event)
27
+
28
+ Opbeat.capture_message(message, options)
29
+ end
30
+
31
+ it 'capture_exception should send result of Event.from_exception' do
32
+ exception = build_exception()
33
+
34
+ expect(Opbeat::Event).to receive(:from_exception).with(exception, {})
35
+ expect(Opbeat).to receive(:send).with(@event)
36
+
37
+ Opbeat.capture_exception(exception)
38
+ end
39
+
40
+ it 'capture_rack_exception should send result of Event.from_exception built with env and default options' do
41
+ exception = build_exception()
42
+ rack_env = build_rack_env()
43
+
44
+ expect(Opbeat::Event).to receive(:from_rack_exception).with(exception, rack_env, {})
45
+ expect(Opbeat).to receive(:send).with(@event)
46
+
47
+ Opbeat.capture_rack_exception(exception, rack_env)
48
+ end
49
+
50
+ it "capture_rack_exception should send result of Event.from_exception built with env and options" do
51
+ exception = build_exception()
52
+ rack_env = build_rack_env()
53
+
54
+ expect(Opbeat::Event).to receive(:from_rack_exception).with(exception, rack_env, {:custom => :param})
55
+ expect(Opbeat).to receive(:send).with(@event)
56
+
57
+ Opbeat.capture_rack_exception(exception, rack_env, {:custom => :param})
58
+ end
59
+
60
+ context "async" do
61
+ after do
62
+ Opbeat.configuration.async = false
63
+ end
64
+
65
+ it 'capture_message should send result of Event.from_message' do
66
+ async = lambda {}
67
+ message = "Test message"
68
+
69
+ expect(Opbeat::Event).to receive(:from_message).with(message, an_instance_of(Array), {})
70
+ expect(Opbeat).to_not receive(:send)
71
+ expect(async).to receive(:call).with(@event)
72
+
73
+ Opbeat.configuration.async = async
74
+ Opbeat.capture_message(message)
75
+ end
76
+
77
+ it 'capture_exception should send result of Event.from_exception' do
78
+ async = lambda {}
79
+ exception = build_exception()
80
+
81
+ expect(Opbeat::Event).to receive(:from_exception).with(exception, {})
82
+ expect(Opbeat).to_not receive(:send)
83
+ expect(async).to receive(:call).with(@event)
84
+
85
+ Opbeat.configuration.async = async
86
+ Opbeat.capture_exception(exception)
87
+ end
88
+ end
89
+ end