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,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