opbeat 2.0.0 → 3.0.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.
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