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,66 @@
1
+ require 'spec_helper'
2
+ require 'sinatra'
3
+
4
+ module Opbeat
5
+ RSpec.describe "sinatra integration" do
6
+ include Rack::Test::Methods
7
+
8
+ def config
9
+ @config ||= Opbeat::Configuration.new do |c|
10
+ c.app_id = 'X'
11
+ c.organization_id = 'Y'
12
+ c.secret_token = 'Z'
13
+ c.disable_worker = true
14
+ end
15
+ end
16
+
17
+ around do |example|
18
+ Opbeat.start! config
19
+ example.call
20
+ Opbeat.stop!
21
+ end
22
+
23
+ class TestApp < ::Sinatra::Base
24
+ disable :show_exceptions
25
+ use Opbeat::Middleware
26
+
27
+ get '/' do
28
+ erb "I am an inline template!"
29
+ end
30
+
31
+ template :tmpl do
32
+ "I am a template!"
33
+ end
34
+
35
+ get '/tmpl' do
36
+ erb :tmpl
37
+ end
38
+ end
39
+
40
+ def app
41
+ TestApp
42
+ end
43
+
44
+ it "wraps routes in transactions" do
45
+ get '/'
46
+
47
+ transaction = Opbeat::Client.inst.pending_transactions.last
48
+ expect(transaction.endpoint).to eq 'GET /'
49
+ end
50
+
51
+ it "traces templates" do
52
+ get '/tmpl'
53
+
54
+ transaction = Opbeat::Client.inst.pending_transactions.last
55
+ expect(transaction.traces.last.signature).to eq 'tmpl'
56
+ end
57
+
58
+ it "traces inline templates" do
59
+ get '/'
60
+
61
+ transaction = Opbeat::Client.inst.pending_transactions.last
62
+ expect(transaction.traces.last.signature).to eq 'Inline erb'
63
+ end
64
+
65
+ end
66
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ module Opbeat
4
+ RSpec.describe LineCache do
5
+
6
+ let(:path) { "some/file.rb" }
7
+ let(:lines) { %w{these are the lines} }
8
+
9
+ describe ".all" do
10
+ it "returns the lines of the file at path" do
11
+ allow(File).to receive(:readlines) { lines }
12
+ expect(LineCache.all path).to eq lines
13
+ end
14
+ it "rescues any exception" do
15
+ allow(LineCache::CACHE).to receive(:[]) { nil }
16
+ allow(File).to receive(:readlines).and_raise "BOOM"
17
+ expect(LineCache.all path).to eq []
18
+ end
19
+ it "caches results" do
20
+ allow(File).to receive(:readlines) { lines }.once
21
+ LineCache.all path
22
+ LineCache.all path
23
+ end
24
+ end
25
+
26
+ describe ".find" do
27
+ it "returns one line of the file at path" do
28
+ allow(File).to receive(:readlines) { lines }.once
29
+ allow(LineCache::CACHE).to receive(:[]) { nil }
30
+ expect(LineCache.find path, 2).to eq "are"
31
+ end
32
+ it "is nil when less than 1" do
33
+ expect(LineCache.find path, 0).to be_nil
34
+ end
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+ require 'opbeat'
3
+
4
+ module Opbeat
5
+ describe Logging do
6
+ class FakeLogger
7
+ def method_missing name, *args, &block
8
+ @calls ||= []
9
+ @calls << [name, *args]
10
+ end
11
+ attr_reader :calls
12
+ end
13
+
14
+ let(:logger) { FakeLogger.new }
15
+ let(:config) { Struct.new(:logger).new(logger) }
16
+
17
+ before :each do
18
+ extend Logging
19
+ end
20
+
21
+ %w{fatal error info debug warn}.map(&:to_sym).each do |level|
22
+ it "does #{level} with args" do
23
+ self.send level, "msg"
24
+ expect(logger.calls.last).to eq [level, "** [Opbeat] msg"]
25
+ end
26
+ it "does #{level} with block" do
27
+ blck = lambda { "msg" }
28
+ self.send level, &blck
29
+ expect(logger.calls.last).to eq [level, "** [Opbeat] msg"]
30
+ end
31
+ end
32
+
33
+ context 'without a backend logger' do
34
+ before do
35
+ config.logger = nil
36
+ end
37
+
38
+ it 'should not error' do
39
+ fatal 'fatalmsg'
40
+ error 'errormsg'
41
+ warn 'warnmsg'
42
+ info 'infomsg'
43
+ debug 'debugmsg'
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+ require 'opbeat'
3
+
4
+ module Opbeat
5
+ describe Middleware, start_without_worker: true do
6
+
7
+ it "surrounds the request in a transaction" do
8
+ app = Middleware.new(lambda do |env|
9
+ [200, {}, ['']]
10
+ end)
11
+ status, _, body = app.call(Rack::MockRequest.env_for '/')
12
+ body.close
13
+
14
+ expect(status).to eq 200
15
+ expect(Opbeat::Client.inst.pending_transactions.length).to be 1
16
+ expect(Opbeat::Client.inst.current_transaction).to be_nil
17
+ end
18
+
19
+ it "submits on exceptions" do
20
+ app = Middleware.new(lambda do |env|
21
+ raise Exception, "BOOM"
22
+ end)
23
+
24
+ expect { app.call(Rack::MockRequest.env_for '/') }.to raise_error(Exception)
25
+ expect(Opbeat::Client.inst.queue.length).to be 1
26
+ expect(Opbeat::Client.inst.current_transaction).to be_nil
27
+
28
+ expect(Opbeat::Client.inst.queue.length).to be 1
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ module Opbeat
4
+ RSpec.describe Normalizers::ActionController do
5
+
6
+ let(:config) { Configuration.new }
7
+ let(:normalizers) { Normalizers.build config }
8
+
9
+ describe Normalizers::ActionController::ProcessAction do
10
+ subject do
11
+ normalizers.normalizer_for('process_action.action_controller')
12
+ end
13
+
14
+ it "registers" do
15
+ expect(subject).to be_a Normalizers::ActionController::ProcessAction
16
+ end
17
+
18
+ describe "#normalize" do
19
+ it "normalizes input and updates transaction" do
20
+ transaction = Struct.new(:endpoint).new(nil)
21
+
22
+ result = subject.normalize(transaction, 'process_action.action_controller', {
23
+ controller: 'SomeController', action: 'index'
24
+ })
25
+
26
+ expect(transaction.endpoint).to eq 'SomeController#index'
27
+ expect(result).to match ['SomeController#index', 'app.controller.action', nil]
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,77 @@
1
+ require 'spec_helper'
2
+
3
+ module Opbeat
4
+ RSpec.describe Normalizers::ActionView do
5
+
6
+ let(:config) { Configuration.new view_paths: ['/var/www/app/views'] }
7
+ let(:normalizers) { Normalizers.build config }
8
+
9
+ shared_examples_for :a_render_normalizer do |key|
10
+ describe "#normalize" do
11
+ it "normalizes an unknown template" do
12
+ expect(normalize key, {}).to eq ['Unknown template', described_class.const_get(:KIND), nil]
13
+ end
14
+
15
+ it "returns a local template" do
16
+ path = 'somewhere/local.html.erb'
17
+ expect(normalize(key, identifier: path)[0]).to eq 'somewhere/local.html.erb'
18
+ end
19
+
20
+ it "looks up a template in config.view_paths" do
21
+ path = '/var/www/app/views/users/index.html.erb'
22
+ expect(normalize(key, identifier: path)[0]).to eq 'users/index.html.erb'
23
+ end
24
+
25
+ it "truncates gem path" do
26
+ path = Gem.path[0] + '/some/template.html.erb'
27
+ expect(normalize(key, identifier: path)[0]).to eq '$GEM_PATH/some/template.html.erb'
28
+ end
29
+
30
+ it "returns absolute if not found in known dirs" do
31
+ path = '/somewhere/else.html.erb'
32
+ expect(normalize(key, identifier: path)[0]).to eq 'Absolute path'
33
+ end
34
+
35
+ def normalize key, payload
36
+ subject.normalize nil, key, payload
37
+ end
38
+ end
39
+ end
40
+
41
+ describe Normalizers::ActionView::RenderTemplate do
42
+ subject do
43
+ normalizers.normalizer_for 'render_template.action_view'
44
+ end
45
+
46
+ it "registers" do
47
+ expect(subject).to be_a Normalizers::ActionView::RenderTemplate
48
+ end
49
+
50
+ it_should_behave_like :a_render_normalizer
51
+ end
52
+
53
+ describe Normalizers::ActionView::RenderPartial do
54
+ subject do
55
+ normalizers.normalizer_for 'render_partial.action_view'
56
+ end
57
+
58
+ it "registers" do
59
+ expect(subject).to be_a Normalizers::ActionView::RenderPartial
60
+ end
61
+
62
+ it_should_behave_like :a_render_normalizer
63
+ end
64
+
65
+ describe Normalizers::ActionView::RenderCollection do
66
+ subject do
67
+ normalizers.normalizer_for 'render_collection.action_view'
68
+ end
69
+
70
+ it "registers" do
71
+ expect(subject).to be_a Normalizers::ActionView::RenderCollection
72
+ end
73
+
74
+ it_should_behave_like :a_render_normalizer
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,70 @@
1
+ require 'spec_helper'
2
+
3
+ module Opbeat
4
+ RSpec.describe Normalizers::ActionView do
5
+
6
+ let(:config) { Configuration.new view_paths: ['/var/www/app/views'] }
7
+ let(:normalizers) { Normalizers.build config }
8
+
9
+ describe Normalizers::ActiveRecord::SQL do
10
+ subject { normalizers.normalizer_for 'sql.active_record' }
11
+
12
+ it "registers" do
13
+ expect(subject).to be_a Normalizers::ActiveRecord::SQL
14
+ end
15
+
16
+ describe "#normalize" do
17
+ it "skips SCHEMA queries" do
18
+ expect(normalize(name: 'SCHEMA')).to be :skip
19
+ end
20
+
21
+ it "skips CACHE queries" do
22
+ expect(normalize(name: 'CACHE', sql: 'select * from tables')).to be :skip
23
+ end
24
+
25
+ it "normalizes SELECT queries" do
26
+ sql = 'SELECT "hotdogs".* FROM "hotdogs" WHERE "hotdogs"."topping" = $1 LIMIT 1'
27
+ signature, kind, extra = normalize(name: 'Hotdogs load', sql: sql)
28
+ expect(signature).to eq 'SELECT FROM "hotdogs"'
29
+ expect(kind).to eq 'db.unknown.sql'
30
+ expect(extra).to eq sql: sql
31
+ end
32
+
33
+ it "normalizes INSERT queries" do
34
+ sig, _, _ = normalize(name: 'Hotdogs create',
35
+ sql: 'insert into "hotdogs" (kind, topping) values ($1, $2)')
36
+ expect(sig).to eq 'INSERT INTO "hotdogs"'
37
+ end
38
+
39
+ it "normalizes UPDATE queries" do
40
+ sig, _, _ = normalize(name: 'Hotdogs update',
41
+ sql: 'update "hotdogs" (topping) values ($1) where id=1')
42
+ expect(sig).to eq 'UPDATE "hotdogs"'
43
+ end
44
+
45
+ it "normalizes DELETE queries" do
46
+ sig, _, _ = normalize(name: 'Hotdogs delete',
47
+ sql: 'delete from "hotdogs" where id=1')
48
+ expect(sig).to eq 'DELETE FROM "hotdogs"'
49
+ end
50
+
51
+ context "inside AR" do
52
+ before do
53
+ module ::ActiveRecord; class Base; end; end unless defined? ActiveRecord
54
+ allow(::ActiveRecord::Base).to receive(:connection) { double(adapter_name: 'MySQL') }
55
+ end
56
+ it "knows the ar adapter" do
57
+ _, kind, _ = normalize(name: 'Hotdogs load',
58
+ sql: 'select * from "hotdogs"')
59
+ expect(kind).to eq 'db.mysql.sql'
60
+ end
61
+ end
62
+
63
+ def normalize payload
64
+ subject.normalize nil, 'sql.active_record', payload
65
+ end
66
+ end
67
+ end
68
+
69
+ end
70
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ module Opbeat
4
+ RSpec.describe Normalizers do
5
+
6
+ let(:config) { Configuration.new }
7
+
8
+ describe Normalizers::Default do
9
+ it "skips" do
10
+ normalizer = Normalizers::Default.new config
11
+ expect(normalizer.normalize 1, 2, 3).to eq :skip
12
+ end
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,6 @@
1
+ require 'spec_helper'
2
+
3
+ module Opbeat
4
+ RSpec.describe SqlSummarizer do
5
+ end
6
+ end
@@ -0,0 +1,83 @@
1
+ require 'spec_helper'
2
+
3
+ module Opbeat
4
+ RSpec.describe Subscriber do
5
+
6
+ let(:config) { Configuration.new }
7
+ let(:client) { Client.new config }
8
+
9
+ subject do
10
+ Subscriber.new config, client
11
+ end
12
+
13
+ describe "#register!" do
14
+ it "subscribes to ActiveSupport::Notifications" do
15
+ expect(ActiveSupport::Notifications).to receive(:subscribe)
16
+ subject.register!
17
+ end
18
+ it "unregisters first if already registered" do
19
+ subject.register!
20
+ expect(subject).to receive(:unregister!)
21
+ expect(ActiveSupport::Notifications).to receive(:subscribe)
22
+ subject.register!
23
+ end
24
+ end
25
+
26
+ describe "#unregister" do
27
+ it "unsubscribes to AS::Notifications" do
28
+ expect(ActiveSupport::Notifications).to receive(:unsubscribe)
29
+ subject.register!
30
+ subject.unregister!
31
+ end
32
+ end
33
+
34
+ describe "ActiveSupport::Notifications API", start_without_worker: true do
35
+ let(:message_args) do
36
+ [
37
+ 'process_action.action_controller',
38
+ nil,
39
+ { controller: 'Controller', action: 'index' }
40
+ ]
41
+ end
42
+ describe "#start" do
43
+ it "adds a new notification to current transaction" do
44
+ transaction = Opbeat.transaction 'Test'
45
+
46
+ expect do
47
+ subject.start(*message_args)
48
+ end.to change(transaction.notifications, :length).by 1
49
+
50
+ transaction.release
51
+ end
52
+ end
53
+
54
+ describe "#finish" do
55
+ it "adds a trace to current transaction" do
56
+ transaction = Opbeat.transaction 'Test'
57
+
58
+ expect do
59
+ subject.start(*message_args)
60
+ subject.finish(*message_args)
61
+ end.to change(transaction.traces, :length).by 1
62
+
63
+ transaction.release
64
+ end
65
+ it "adds a stack of parents", mock_time: true do
66
+ transaction = Opbeat.transaction 'Rack' do
67
+ subject.start(*message_args)
68
+ travel 100
69
+ Opbeat.trace('thing-1') do
70
+ travel 100
71
+ end
72
+ travel 100
73
+ subject.finish(*message_args)
74
+ end.done(200)
75
+
76
+ expect(transaction.traces.length).to eq 3
77
+ expect(transaction.traces.last.parents.map(&:signature)).to eq ['transaction', 'Controller#index']
78
+ end
79
+ end
80
+ end
81
+
82
+ end
83
+ end