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,32 @@
1
+ module Opbeat
2
+ module Injections
3
+ module Sequel
4
+ class Injector
5
+ KIND = 'db.sequel.sql'.freeze
6
+
7
+ def self.sql_parser
8
+ @sql_parser ||= SqlSummarizer.new(nil)
9
+ end
10
+
11
+ def install
12
+ require 'sequel/database/logging'
13
+
14
+ ::Sequel::Database.class_eval do
15
+ alias log_yield_without_opb log_yield
16
+
17
+ def log_yield sql, args = nil, &block
18
+ log_yield_without_opb(sql, *args) do
19
+ sig = Opbeat::Injections::Sequel::Injector.sql_parser.signature_for(sql)
20
+ Opbeat.trace(sig, KIND, sql: sql) do
21
+ block.call
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ register 'Sequel', 'sequel', Sequel::Injector.new
31
+ end
32
+ end
@@ -0,0 +1,56 @@
1
+ module Opbeat
2
+ module Injections
3
+ module Sinatra
4
+ class Injector
5
+ def install
6
+ ::Sinatra::Base.class_eval do
7
+ alias dispatch_without_opb! dispatch!
8
+ alias compile_template_with_opb compile_template
9
+
10
+ def dispatch!(*args, &block)
11
+ dispatch_without_opb!(*args, &block).tap do
12
+ if route = env['sinatra.route']
13
+ Opbeat.transaction(nil).endpoint = route
14
+ end
15
+ end
16
+ end
17
+
18
+ def compile_template engine, data, opts, *args, &block
19
+ case data
20
+ when Symbol
21
+ opts[:__opbeat_template_sig] = data.to_s
22
+ else
23
+ opts[:__opbeat_template_sig] = "Inline #{engine}"
24
+ end
25
+
26
+ compile_template_with_opb(engine, data, opts, *args, &block)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ module Tilt
34
+ class Injector
35
+ KIND = 'template.view'
36
+
37
+ def install
38
+ ::Tilt::Template.class_eval do
39
+ alias render_without_opb render
40
+
41
+ def render(*args, &block)
42
+ sig = options[:__opbeat_template_sig] || 'Uknown template'.freeze
43
+
44
+ Opbeat.trace sig, KIND do
45
+ render_without_opb(*args, &block)
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ register 'Sinatra::Base', 'sinatra/base', Sinatra::Injector.new
54
+ register 'Tilt::Template', 'tilt/template', Tilt::Injector.new
55
+ end
56
+ end
@@ -1,6 +1,5 @@
1
- require 'capistrano'
2
-
3
1
  module Opbeat
2
+ # @api private
4
3
  module Capistrano
5
4
  def self.load_into(configuration)
6
5
 
@@ -17,13 +16,13 @@ module Opbeat
17
16
  puts "Skipping Opbeat deployment notification because scm is not git."
18
17
  next
19
18
  end
20
-
19
+
21
20
  branches = capture("cd #{current_release}; /usr/bin/env git branch --contains #{current_revision}").split
22
21
  if branches.length == 1
23
22
  branch = branch[0].sub("* ")
24
23
  else
25
24
  branch = nil
26
- end
25
+ end
27
26
 
28
27
  notify_command = "cd #{current_release}; REV=#{current_revision} "
29
28
  notify_command << "BRANCH=#{branch} " if branch
@@ -32,9 +31,9 @@ module Opbeat
32
31
  notify_command << "RAILS_ENV=#{rails_env} "
33
32
 
34
33
  executable = fetch(:rake, 'bundle exec rake ')
35
- notify_command << "#{executable} opbeat:deployment"
34
+ notify_command << "#{executable} opbeat:release"
36
35
  capture notify_command, :once => true
37
-
36
+
38
37
  end
39
38
  end
40
39
  end
@@ -45,3 +44,4 @@ end
45
44
  if Capistrano::Configuration.instance
46
45
  Opbeat::Capistrano.load_into(Capistrano::Configuration.instance)
47
46
  end
47
+
@@ -1,11 +1,11 @@
1
1
  namespace :opbeat do
2
- desc "Notifies Opbeat of new deployments"
2
+ desc "Notifies Opbeat of new releases"
3
3
  task :notify do
4
4
  on roles(:app) do
5
5
 
6
6
  scm = fetch(:scm)
7
7
  if scm.to_s != "git"
8
- info "Skipping Opbeat deployment because scm is not git."
8
+ info "Skipping Opbeat release because scm is not git."
9
9
  next
10
10
  end
11
11
 
@@ -14,7 +14,7 @@ namespace :opbeat do
14
14
 
15
15
  within release_path do
16
16
  with rails_env: fetch(:rails_env), rev: rev, branch: branch do
17
- capture :rake, 'opbeat:deployment'
17
+ capture :rake, 'opbeat:release'
18
18
  end
19
19
  end
20
20
  end
@@ -3,23 +3,19 @@ begin
3
3
  rescue LoadError
4
4
  end
5
5
 
6
- # Based on the Sentry equivalent.
7
6
  if defined?(Delayed)
8
-
9
7
  module Delayed
10
8
  module Plugins
11
- class Opbeat < ::Delayed::Plugin
9
+ class Opbeat < Delayed::Plugin
12
10
  callbacks do |lifecycle|
13
11
  lifecycle.around(:invoke_job) do |job, *args, &block|
14
12
  begin
15
- # Forward the call to the next callback in the callback chain
16
13
  block.call(job, *args)
17
-
14
+ rescue ::Opbeat::Error
15
+ raise # don't report Opbeat errors
18
16
  rescue Exception => exception
19
- # Log error to Opbeat
20
- ::Opbeat.capture_exception(exception)
21
- # Make sure we propagate the failure!
22
- raise exception
17
+ ::Opbeat.report exception
18
+ raise
23
19
  end
24
20
  end
25
21
  end
@@ -27,6 +23,5 @@ if defined?(Delayed)
27
23
  end
28
24
  end
29
25
 
30
- # Register DelayedJob Opbeat plugin
31
26
  Delayed::Worker.plugins << Delayed::Plugins::Opbeat
32
- end
27
+ end
@@ -0,0 +1,23 @@
1
+ module Opbeat
2
+ module Integration
3
+ module Rails
4
+ module InjectExceptionsCatcher
5
+ def self.included(cls)
6
+ cls.send(:alias_method_chain, :render_exception, :opbeat)
7
+ end
8
+
9
+ def render_exception_with_opbeat(env, exception)
10
+ begin
11
+ Opbeat.report(exception, rack_env: env) if Opbeat.started?
12
+ rescue
13
+ ::Rails::logger.error "** [Opbeat] Error capturing or sending exception #{$!}"
14
+ ::Rails::logger.debug $!.backtrace.join("\n")
15
+ end
16
+
17
+ render_exception_without_opbeat(env, exception)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+
@@ -0,0 +1,53 @@
1
+ require 'opbeat'
2
+ require 'rails'
3
+
4
+ module Opbeat
5
+ class Railtie < Rails::Railtie
6
+
7
+ config.opbeat = ActiveSupport::OrderedOptions.new
8
+ # bootstrap options with the defaults
9
+ Configuration::DEFAULTS.each { |k,v| config.opbeat[k] = v }
10
+
11
+ initializer "opbeat.configure" do |app|
12
+ config = Configuration.new app.config.opbeat do |conf|
13
+ conf.logger = Rails.logger
14
+ conf.view_paths = app.config.paths['app/views'].existent
15
+ end
16
+
17
+ if config.enabled_environments.include?(Rails.env)
18
+ if Opbeat.start!(config)
19
+ app.config.middleware.insert 0, Middleware
20
+ Rails.logger.info "** [Opbeat] Client running"
21
+ else
22
+ # :nocov:
23
+ Rails.logger.info "** [Opbeat] Failed to start"
24
+ # :nocov:
25
+ end
26
+ else
27
+ # :nocov:
28
+ Rails.logger.info "** [Opbeat] Disabled in #{Rails.env} environment"
29
+ # :nocov:
30
+ end
31
+ end
32
+
33
+ config.after_initialize do
34
+ # :nocov:
35
+ require 'opbeat/integration/rails/inject_exceptions_catcher'
36
+ if defined?(ActionDispatch::DebugExceptions)
37
+ ActionDispatch::DebugExceptions.send(
38
+ :include, Opbeat::Integration::Rails::InjectExceptionsCatcher)
39
+ elsif defined?(::ActionDispatch::ShowExceptions)
40
+ ::ActionDispatch::ShowExceptions.send(
41
+ :include, Opbeat::Integration::Rails::InjectExceptionsCatcher)
42
+ end
43
+ # :nocov:
44
+ end
45
+
46
+ rake_tasks do
47
+ # :nocov:
48
+ require 'opbeat/tasks'
49
+ # :nocov:
50
+ end
51
+
52
+ end
53
+ end
@@ -0,0 +1,16 @@
1
+ begin
2
+ require 'resque'
3
+ rescue LoadError
4
+ end
5
+
6
+ if defined? Resque
7
+ module Opbeat
8
+ module Integration
9
+ class Resque < Resque::Failure::Base
10
+ def save
11
+ Opbeat.report exception
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,38 @@
1
+ begin
2
+ require 'sidekiq'
3
+ rescue LoadError
4
+ end
5
+
6
+ if defined? Sidekiq
7
+ module Opbeat
8
+ module Integration
9
+ class Sidekiq
10
+ def call worker, msg, queue
11
+ begin
12
+ yield
13
+ rescue Exception => exception
14
+ if [Interrupt, SystemExit, SignalException].include? exception.class
15
+ raise exception
16
+ end
17
+
18
+ Opbeat.report exception
19
+
20
+ raise
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ Sidekiq.configure_server do |config|
28
+ if Sidekiq::VERSION.to_i < 3
29
+ config.server_middleware do |chain|
30
+ chain.add Opbeat::Integration::Sidekiq
31
+ end
32
+ else
33
+ config.error_handlers << lambda do |exception|
34
+ Opbeat.report exception
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,21 @@
1
+ module Opbeat
2
+ # @api private
3
+ class LineCache
4
+
5
+ CACHE = {}
6
+
7
+ def self.all path
8
+ CACHE[path] ||= begin
9
+ File.readlines(path)
10
+ rescue
11
+ []
12
+ end
13
+ end
14
+
15
+ def self.find path, line
16
+ return nil if line < 1
17
+ all(path)[line - 1]
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,37 @@
1
+ module Opbeat
2
+ # @api private
3
+ module Logging
4
+ PREFIX = "** [Opbeat] ".freeze
5
+
6
+ def debug *args, &block
7
+ config.logger.debug(log_message(*args, &block)) if has_logger?
8
+ end
9
+
10
+ def info *args, &block
11
+ config.logger.info(log_message(*args, &block)) if has_logger?
12
+ end
13
+
14
+ def warn *args, &block
15
+ config.logger.warn(log_message(*args, &block)) if has_logger?
16
+ end
17
+
18
+ def error *args, &block
19
+ config.logger.error(log_message(*args, &block)) if has_logger?
20
+ end
21
+
22
+ def fatal *args, &block
23
+ config.logger.fatal(log_message(*args, &block)) if has_logger?
24
+ end
25
+
26
+ private
27
+
28
+ def has_logger?
29
+ respond_to?(:config) && config && config.logger
30
+ end
31
+
32
+ def log_message *args, &block
33
+ msg = block_given? && block.call || args.first
34
+ "#{PREFIX}#{msg}"
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,59 @@
1
+ module Opbeat
2
+ class Middleware
3
+ def initialize app
4
+ @app = app
5
+ end
6
+
7
+ def call env
8
+ begin
9
+ transaction = Opbeat.transaction "Rack", "app.rack.request"
10
+ resp = @app.call env
11
+ resp[2] = BodyProxy.new(resp[2]) { transaction.submit(resp[0]) } if transaction
12
+ rescue Error
13
+ raise # Don't report Opbeat errors
14
+ rescue Exception => e
15
+ Opbeat.report e, rack_env: env
16
+ transaction.submit(500) if transaction
17
+ raise
18
+ ensure
19
+ transaction.release if transaction
20
+ end
21
+
22
+ if error = env['rack.exception'] || env['sinatra.error']
23
+ Opbeat.report error, rack_env: env
24
+ end
25
+
26
+ resp
27
+ end
28
+ end
29
+
30
+ class BodyProxy
31
+ def initialize body, &block
32
+ @body, @block, @closed = body, block, false
33
+ end
34
+
35
+ def respond_to? *args
36
+ super || @body.respond_to?(*args)
37
+ end
38
+
39
+ def close
40
+ return if closed?
41
+
42
+ @closed = true
43
+
44
+ begin
45
+ @body.close if @body.respond_to?(:close)
46
+ ensure
47
+ @block.call
48
+ end
49
+ end
50
+
51
+ def closed?
52
+ @closed
53
+ end
54
+
55
+ def method_missing *args, &block
56
+ @body.__send__(*args, &block)
57
+ end
58
+ end
59
+ end