opbeat 2.0.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -3
  3. data/.travis.yml +19 -28
  4. data/.yardopts +3 -0
  5. data/Gemfile +4 -2
  6. data/HISTORY.md +3 -0
  7. data/LICENSE +7 -196
  8. data/README.md +96 -177
  9. data/Rakefile +19 -13
  10. data/gemfiles/Gemfile.base +28 -0
  11. data/gemfiles/Gemfile.rails-3.2.x +3 -0
  12. data/gemfiles/Gemfile.rails-4.0.x +3 -0
  13. data/gemfiles/Gemfile.rails-4.1.x +3 -0
  14. data/gemfiles/Gemfile.rails-4.2.x +3 -0
  15. data/lib/opbeat.rb +113 -93
  16. data/lib/opbeat/capistrano.rb +3 -4
  17. data/lib/opbeat/client.rb +243 -82
  18. data/lib/opbeat/configuration.rb +51 -64
  19. data/lib/opbeat/data_builders.rb +16 -0
  20. data/lib/opbeat/data_builders/error.rb +27 -0
  21. data/lib/opbeat/data_builders/transactions.rb +85 -0
  22. data/lib/opbeat/error.rb +1 -2
  23. data/lib/opbeat/error_message.rb +71 -0
  24. data/lib/opbeat/error_message/exception.rb +12 -0
  25. data/lib/opbeat/error_message/http.rb +62 -0
  26. data/lib/opbeat/error_message/stacktrace.rb +75 -0
  27. data/lib/opbeat/error_message/user.rb +23 -0
  28. data/lib/opbeat/filter.rb +53 -43
  29. data/lib/opbeat/http_client.rb +141 -0
  30. data/lib/opbeat/injections.rb +83 -0
  31. data/lib/opbeat/injections/json.rb +19 -0
  32. data/lib/opbeat/injections/net_http.rb +43 -0
  33. data/lib/opbeat/injections/redis.rb +23 -0
  34. data/lib/opbeat/injections/sequel.rb +32 -0
  35. data/lib/opbeat/injections/sinatra.rb +56 -0
  36. data/lib/opbeat/{capistrano → integration}/capistrano2.rb +6 -6
  37. data/lib/opbeat/{capistrano → integration}/capistrano3.rb +3 -3
  38. data/lib/opbeat/{integrations → integration}/delayed_job.rb +6 -11
  39. data/lib/opbeat/integration/rails/inject_exceptions_catcher.rb +23 -0
  40. data/lib/opbeat/integration/railtie.rb +53 -0
  41. data/lib/opbeat/integration/resque.rb +16 -0
  42. data/lib/opbeat/integration/sidekiq.rb +38 -0
  43. data/lib/opbeat/line_cache.rb +21 -0
  44. data/lib/opbeat/logging.rb +37 -0
  45. data/lib/opbeat/middleware.rb +59 -0
  46. data/lib/opbeat/normalizers.rb +65 -0
  47. data/lib/opbeat/normalizers/action_controller.rb +21 -0
  48. data/lib/opbeat/normalizers/action_view.rb +71 -0
  49. data/lib/opbeat/normalizers/active_record.rb +41 -0
  50. data/lib/opbeat/sql_summarizer.rb +27 -0
  51. data/lib/opbeat/subscriber.rb +80 -0
  52. data/lib/opbeat/tasks.rb +20 -18
  53. data/lib/opbeat/trace.rb +47 -0
  54. data/lib/opbeat/trace_helpers.rb +29 -0
  55. data/lib/opbeat/transaction.rb +99 -0
  56. data/lib/opbeat/util.rb +26 -0
  57. data/lib/opbeat/util/constantize.rb +54 -0
  58. data/lib/opbeat/util/inspector.rb +75 -0
  59. data/lib/opbeat/version.rb +1 -1
  60. data/lib/opbeat/worker.rb +55 -0
  61. data/opbeat.gemspec +6 -14
  62. data/spec/opbeat/client_spec.rb +216 -29
  63. data/spec/opbeat/configuration_spec.rb +34 -38
  64. data/spec/opbeat/data_builders/error_spec.rb +43 -0
  65. data/spec/opbeat/data_builders/transactions_spec.rb +51 -0
  66. data/spec/opbeat/error_message/exception_spec.rb +22 -0
  67. data/spec/opbeat/error_message/http_spec.rb +65 -0
  68. data/spec/opbeat/error_message/stacktrace_spec.rb +56 -0
  69. data/spec/opbeat/error_message/user_spec.rb +28 -0
  70. data/spec/opbeat/error_message_spec.rb +78 -0
  71. data/spec/opbeat/filter_spec.rb +21 -99
  72. data/spec/opbeat/http_client_spec.rb +64 -0
  73. data/spec/opbeat/injections/net_http_spec.rb +37 -0
  74. data/spec/opbeat/injections/sequel_spec.rb +33 -0
  75. data/spec/opbeat/injections/sinatra_spec.rb +13 -0
  76. data/spec/opbeat/injections_spec.rb +49 -0
  77. data/spec/opbeat/integration/delayed_job_spec.rb +35 -0
  78. data/spec/opbeat/integration/json_spec.rb +41 -0
  79. data/spec/opbeat/integration/rails_spec.rb +88 -0
  80. data/spec/opbeat/integration/redis_spec.rb +20 -0
  81. data/spec/opbeat/integration/resque_spec.rb +42 -0
  82. data/spec/opbeat/integration/sidekiq_spec.rb +40 -0
  83. data/spec/opbeat/integration/sinatra_spec.rb +66 -0
  84. data/spec/opbeat/line_cache_spec.rb +38 -0
  85. data/spec/opbeat/logging_spec.rb +47 -0
  86. data/spec/opbeat/middleware_spec.rb +32 -0
  87. data/spec/opbeat/normalizers/action_controller_spec.rb +32 -0
  88. data/spec/opbeat/normalizers/action_view_spec.rb +77 -0
  89. data/spec/opbeat/normalizers/active_record_spec.rb +70 -0
  90. data/spec/opbeat/normalizers_spec.rb +16 -0
  91. data/spec/opbeat/sql_summarizer_spec.rb +6 -0
  92. data/spec/opbeat/subscriber_spec.rb +83 -0
  93. data/spec/opbeat/trace_spec.rb +43 -0
  94. data/spec/opbeat/transaction_spec.rb +98 -0
  95. data/spec/opbeat/util/inspector_spec.rb +40 -0
  96. data/spec/opbeat/util_spec.rb +20 -0
  97. data/spec/opbeat/worker_spec.rb +54 -0
  98. data/spec/opbeat_spec.rb +49 -0
  99. data/spec/spec_helper.rb +79 -6
  100. metadata +89 -149
  101. data/Makefile +0 -3
  102. data/gemfiles/rails30.gemfile +0 -9
  103. data/gemfiles/rails31.gemfile +0 -9
  104. data/gemfiles/rails32.gemfile +0 -9
  105. data/gemfiles/rails40.gemfile +0 -9
  106. data/gemfiles/rails41.gemfile +0 -9
  107. data/gemfiles/rails42.gemfile +0 -9
  108. data/gemfiles/ruby192_rails31.gemfile +0 -10
  109. data/gemfiles/ruby192_rails32.gemfile +0 -10
  110. data/gemfiles/sidekiq31.gemfile +0 -11
  111. data/lib/opbeat/better_attr_accessor.rb +0 -44
  112. data/lib/opbeat/event.rb +0 -223
  113. data/lib/opbeat/integrations/resque.rb +0 -22
  114. data/lib/opbeat/integrations/sidekiq.rb +0 -32
  115. data/lib/opbeat/interfaces.rb +0 -35
  116. data/lib/opbeat/interfaces/exception.rb +0 -16
  117. data/lib/opbeat/interfaces/http.rb +0 -57
  118. data/lib/opbeat/interfaces/message.rb +0 -19
  119. data/lib/opbeat/interfaces/stack_trace.rb +0 -50
  120. data/lib/opbeat/linecache.rb +0 -25
  121. data/lib/opbeat/logger.rb +0 -21
  122. data/lib/opbeat/rack.rb +0 -46
  123. data/lib/opbeat/rails/middleware/debug_exceptions_catcher.rb +0 -22
  124. data/lib/opbeat/railtie.rb +0 -26
  125. data/spec/opbeat/better_attr_accessor_spec.rb +0 -99
  126. data/spec/opbeat/event_spec.rb +0 -138
  127. data/spec/opbeat/integrations/delayed_job_spec.rb +0 -38
  128. data/spec/opbeat/logger_spec.rb +0 -55
  129. data/spec/opbeat/opbeat_spec.rb +0 -64
  130. data/spec/opbeat/rack_spec.rb +0 -117
@@ -0,0 +1,64 @@
1
+ require 'spec_helper'
2
+
3
+ module Opbeat
4
+ describe HttpClient do
5
+
6
+ let(:configuration) do
7
+ Configuration.new do |c|
8
+ c.secret_token = 'TOKEN'
9
+ c.organization_id = 'ORG'
10
+ c.app_id = 'APP'
11
+ end
12
+ end
13
+ let(:http_client) do
14
+ HttpClient.new(configuration)
15
+ end
16
+
17
+ describe "#post" do
18
+ let(:data) { { message: "BEEF" } }
19
+
20
+ subject do
21
+ http_client.post "/events/", data
22
+ end
23
+
24
+ it "makes a post request" do
25
+ subject
26
+
27
+ expect(WebMock).to have_requested(:post, %r{/events/$}).with({
28
+ body: data,
29
+ headers: {
30
+ "Authorization" => 'Bearer TOKEN',
31
+ "Content-Type" => 'application/json',
32
+ "Content-Length" => data.to_json.bytesize,
33
+ "User-Agent" => HttpClient::USER_AGENT
34
+ }
35
+ })
36
+ end
37
+
38
+ it "doesn't post when state is failed" do
39
+ http_client.state.fail!
40
+ subject
41
+ expect(WebMock).to_not have_requested(:any, /.*/)
42
+ end
43
+
44
+ it "raises when server returns error" do
45
+ stub_request(:post, /.*/).and_return(status: 500)
46
+ expect { subject }.to raise_error(Error)
47
+ end
48
+ end
49
+
50
+ describe "#state" do
51
+ subject { http_client.state }
52
+
53
+ it "should try" do
54
+ expect(subject.should_try?).to be true
55
+ end
56
+
57
+ it "shouldn't try when state is failed" do
58
+ subject.fail!
59
+ expect(subject.should_try?).to be false
60
+ end
61
+ end
62
+
63
+ end
64
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ require 'open-uri'
4
+
5
+ module Opbeat
6
+ RSpec.describe 'net/http integration', start_without_worker: true do
7
+
8
+ it "is installed" do
9
+ reg = Opbeat::Injections.installed['Net::HTTP']
10
+ expect(reg).to_not be_nil
11
+ end
12
+
13
+ it "traces http calls" do
14
+ Opbeat::Injections.installed['Net::HTTP'].install
15
+
16
+ WebMock.stub_request :get, 'http://example.com:80'
17
+
18
+ transaction = Opbeat.transaction 'Test'
19
+
20
+ Net::HTTP.start('example.com') do |http|
21
+ http.get '/'
22
+ end
23
+
24
+ expect(WebMock).to have_requested(:get, 'http://example.com')
25
+ expect(transaction.traces.length).to be 2
26
+
27
+ http_trace = transaction.traces.last
28
+ expect(http_trace.signature).to eq 'GET example.com'
29
+ expect(http_trace.extra).to eq({
30
+ scheme: 'http',
31
+ port: 80,
32
+ path: '/'
33
+ })
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+ require 'sequel'
3
+
4
+ module Opbeat
5
+ RSpec.describe Injections::Sequel do
6
+
7
+ it "is installed" do
8
+ reg = Opbeat::Injections.installed['Sequel']
9
+ expect(reg).to_not be_nil
10
+ end
11
+
12
+ before do
13
+ @db = Sequel.sqlite # in-memory db
14
+
15
+ @db.create_table :tests do
16
+ primary_key :id
17
+ String :title
18
+ end
19
+
20
+ @db[:tests].count # warm it up
21
+ end
22
+
23
+ it "traces db calls", start_without_worker: true do
24
+ t = Opbeat.transaction 'Test' do
25
+ @db[:tests].count
26
+ end.done(true)
27
+
28
+ expect(t.traces.length).to be 2
29
+ expect(t.traces.last.signature).to eq 'SELECT FROM `tests`'
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+ require 'sinatra'
3
+
4
+ module Opbeat
5
+ RSpec.describe Injections::Sinatra do
6
+
7
+ it "is installed" do
8
+ reg = Opbeat::Injections.installed['Sinatra::Base']
9
+ expect(reg).to_not be_nil
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+
3
+ module Opbeat
4
+ RSpec.describe Injections do
5
+
6
+ class TestProbe
7
+ def initialize
8
+ @installations = 0
9
+ end
10
+ def install
11
+ @installations += 1
12
+ end
13
+ attr_reader :installations
14
+ end
15
+
16
+ let(:probe) { TestProbe.new }
17
+ subject { Opbeat::Injections }
18
+
19
+ it "installs right away if constant is defined" do
20
+ subject.register 'Opbeat', 'opbeat', probe
21
+ expect(probe.installations).to be 1
22
+ end
23
+
24
+ it "installs a require hook" do
25
+ subject.register 'SomeLib', 'opbeat', probe
26
+
27
+ expect(probe.installations).to be 0
28
+
29
+ class ::SomeLib; end
30
+ require 'opbeat'
31
+ expect(probe.installations).to be 1
32
+
33
+ require 'opbeat'
34
+ expect(probe.installations).to be 1
35
+ end
36
+
37
+ it "doesn't install something that never exists" do
38
+ subject.register 'SomethingElse', 'wut', probe
39
+ expect(probe.installations).to be 0
40
+ end
41
+
42
+ it "doesn't install when required but class is missing" do
43
+ subject.register 'SomethingElse', 'opbeat', probe
44
+ require 'opbeat'
45
+ expect(probe.installations).to be 0
46
+ end
47
+
48
+ end
49
+ end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ # :nocov:
4
+ begin
5
+ require 'delayed_job'
6
+ rescue LoadError
7
+ puts "Skipping delayed_job specs"
8
+ end
9
+ # :nocov:
10
+
11
+ if defined?(Delayed)
12
+ # so nasty
13
+ load File.join(
14
+ Gem::Specification.find_by_name("delayed_job").gem_dir,
15
+ "spec", "delayed", "backend", "test.rb"
16
+ )
17
+ Delayed::Worker.backend = Delayed::Backend::Test::Job
18
+
19
+ describe Delayed::Plugins::Opbeat, start_without_worker: true do
20
+ class MyJob
21
+ def blow_up e
22
+ raise e
23
+ end
24
+ end
25
+
26
+ it "reports exceptions to Opbeat" do
27
+ exception = Exception.new('BOOM')
28
+
29
+ MyJob.new.delay.blow_up exception
30
+
31
+ expect(Delayed::Worker.new.work_off).to eq [0, 1]
32
+ expect(Opbeat::Client.inst.queue.length).to be 1
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+ require 'json'
3
+
4
+ RSpec.describe "JSON integration", start_without_worker: true do
5
+
6
+ if false # turned off for now
7
+ describe "#parse" do
8
+ it "adds a trace to current transaction" do
9
+ transaction = Opbeat.transaction 'JSON' do
10
+ JSON.parse('[{"something":1}]')
11
+ end.done(true)
12
+
13
+ expect(transaction.traces.length).to be 2
14
+ expect(transaction.traces.last.signature).to eq "JSON#parse"
15
+ end
16
+ end
17
+
18
+ describe "#parse" do
19
+ it "adds a trace to current transaction" do
20
+ transaction = Opbeat.transaction 'JSON' do
21
+ JSON.parse!('[{"something":1}]')
22
+ end.done(true)
23
+
24
+ expect(transaction.traces.length).to be 2
25
+ expect(transaction.traces.last.signature).to eq "JSON#parse!"
26
+ end
27
+ end
28
+
29
+ describe "#generate" do
30
+ it "adds a trace to current transaction" do
31
+ transaction = Opbeat.transaction 'JSON' do
32
+ JSON.generate([{something: 1}])
33
+ end.done(true)
34
+
35
+ expect(transaction.traces.length).to be 2
36
+ expect(transaction.traces.last.signature).to eq "JSON#generate"
37
+ end
38
+ end
39
+ end
40
+
41
+ end
@@ -0,0 +1,88 @@
1
+ require 'spec_helper'
2
+
3
+ require 'rails'
4
+ require 'action_controller/railtie'
5
+ require 'opbeat/integration/railtie'
6
+
7
+ describe 'Rails integration' do
8
+ include Rack::Test::Methods
9
+
10
+ def boot
11
+ TinderButForHotDogs.initialize!
12
+ TinderButForHotDogs.routes.draw do
13
+ get 'error', to: 'users#error'
14
+ get 'json', to: 'users#other'
15
+ root to: 'users#index'
16
+ end
17
+ end
18
+
19
+ before :all do
20
+ class TinderButForHotDogs < ::Rails::Application
21
+ config.secret_key_base = '__secret_key_base'
22
+
23
+ config.logger = Logger.new(nil)
24
+ config.logger.level = Logger::DEBUG
25
+
26
+ config.eager_load = false
27
+
28
+ config.opbeat.app_id = 'APP_ID'
29
+ config.opbeat.organization_id = 'ORGANIZATION_ID'
30
+ config.opbeat.secret_token = 'SECRET_TOKEN'
31
+ config.opbeat.disable_worker = true
32
+ end
33
+
34
+ class UsersController < ActionController::Base
35
+ def index
36
+ render text: 'HOT DOGS!'
37
+ end
38
+
39
+ def other
40
+ json = Opbeat.trace('JSON.dump') { sleep 0.1; { result: :ok } }
41
+ render json: json
42
+ end
43
+
44
+ def error
45
+ raise Exception.new("NO KETCHUP!")
46
+ end
47
+ end
48
+
49
+ boot
50
+ end
51
+
52
+ after :all do
53
+ Object.send(:remove_const, :TinderButForHotDogs)
54
+ Object.send(:remove_const, :UsersController)
55
+ Rails.application = nil
56
+ Opbeat.stop!
57
+ end
58
+
59
+ def app
60
+ @app ||= Rails.application
61
+ end
62
+
63
+ before :each do
64
+ Opbeat::Client.inst.queue.clear
65
+ Opbeat::Client.inst.instance_variable_set :@pending_transactions, []
66
+ end
67
+
68
+ it "adds an exception handler and handles exceptions" do
69
+ get '/error'
70
+
71
+ expect(Opbeat::Client.inst.queue.length).to be 1
72
+ end
73
+
74
+ it "traces actions and enqueues transaction" do
75
+ get '/'
76
+
77
+ expect(Opbeat::Client.inst.pending_transactions.length).to be 1
78
+ end
79
+
80
+ it "logs when failing to report error" do
81
+ allow(Opbeat::Client.inst).to receive(:report).and_raise
82
+ allow(Rails.logger).to receive(:error)
83
+
84
+ get '/404'
85
+
86
+ expect(Rails.logger).to have_received(:error).with(/\*\* \[Opbeat\] Error capturing/)
87
+ end
88
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ if defined?(Redis)
4
+ RSpec.describe "Redis integration", start_without_worker: true do
5
+
6
+ let(:redis) { Redis.new }
7
+
8
+ describe "#call" do
9
+ it "adds a trace to current transaction" do
10
+ transaction = Opbeat.transaction 'Redis' do
11
+ redis.lrange("some:where", 0, -1)
12
+ end
13
+
14
+ expect(transaction.traces.length).to be 2
15
+ expect(transaction.traces.last.signature).to eq 'lrange'
16
+ end
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ # :nocov:
4
+ begin
5
+ require 'resque'
6
+ rescue LoadError
7
+ puts 'Skipping Resque specs'
8
+ end
9
+ # :nocov:
10
+
11
+ if defined? Resque
12
+ RSpec.describe 'Resque integration', start_without_worker: true do
13
+
14
+ before do
15
+ # using fakeredis
16
+ Resque.redis = Redis.new
17
+
18
+ require 'resque/failure/multiple'
19
+ Resque::Failure::Multiple.classes = [Opbeat::Integration::Resque]
20
+ Resque::Failure.backend = Resque::Failure::Multiple
21
+ end
22
+
23
+ class MyWorker
24
+ @queue = :default
25
+
26
+ def self.perform txt
27
+ raise Exception.new txt
28
+ end
29
+ end
30
+
31
+ it "captures and reports exceptions" do
32
+ Resque.enqueue MyWorker, "BOOM"
33
+
34
+ worker = Resque::Worker.new(:default)
35
+ job = worker.reserve
36
+ worker.perform job
37
+
38
+ expect(Opbeat::Client.inst.queue.length).to be 1
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ # :nocov:
4
+ begin
5
+ require 'sidekiq'
6
+ rescue LoadError
7
+ puts 'Skipping Sidekiq specs'
8
+ end
9
+ # :nocov:
10
+
11
+ if defined?(Sidekiq)
12
+ require 'sidekiq/testing'
13
+
14
+ Sidekiq::Testing.inline!
15
+ Sidekiq::Testing.server_middleware do |chain|
16
+ chain.add Opbeat::Integration::Sidekiq
17
+ end
18
+
19
+ RSpec.describe Opbeat::Integration::Sidekiq, start_without_worker: true do
20
+
21
+ class MyWorker
22
+ include Sidekiq::Worker
23
+
24
+ def perform ex
25
+ raise ex
26
+ end
27
+ end
28
+
29
+ it "captures and reports exceptions to opbeat" do
30
+ exception = Exception.new("BOOM")
31
+
32
+ expect do
33
+ MyWorker.perform_async exception
34
+ end.to raise_error(Exception)
35
+
36
+ expect(Opbeat::Client.inst.queue.length).to be 1
37
+ end
38
+
39
+ end
40
+ end