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,65 @@
1
+ module Opbeat
2
+ # @api private
3
+ module Normalizers
4
+
5
+ class Normalizer
6
+ def self.register name
7
+ Normalizers.register name, self
8
+ end
9
+
10
+ def initialize config
11
+ @config = config
12
+ end
13
+
14
+ attr_reader :config
15
+ end
16
+
17
+ class Default < Normalizer
18
+ def normalize transaction, name, payload
19
+ :skip
20
+ end
21
+ end
22
+
23
+ DEFAULT = Default.new nil
24
+
25
+ def self.register name, cls
26
+ (@registered ||= {})[name] = cls
27
+ end
28
+
29
+ def self.build config
30
+ normalizers = @registered.reduce({}) do |coll, kv|
31
+ name, cls = kv
32
+ coll[name] = cls.new config
33
+ coll
34
+ end
35
+
36
+ Container.new(normalizers)
37
+ end
38
+
39
+ class Container
40
+ def initialize normalizers
41
+ @normalizers = normalizers
42
+ end
43
+
44
+ def keys
45
+ @normalizers.keys
46
+ end
47
+
48
+ def normalizer_for name
49
+ @normalizers[name] || DEFAULT
50
+ end
51
+
52
+ def normalize transaction, name, payload
53
+ normalizer_for(name).normalize transaction, name, payload
54
+ end
55
+ end
56
+
57
+ %w{
58
+ action_controller
59
+ active_record
60
+ action_view
61
+ }.each do |f|
62
+ require "opbeat/normalizers/#{f}"
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,21 @@
1
+ module Opbeat
2
+ module Normalizers
3
+ module ActionController
4
+ class ProcessAction < Normalizer
5
+ register 'process_action.action_controller'
6
+ KIND = 'app.controller.action'.freeze
7
+
8
+ def normalize transaction, name, payload
9
+ transaction.endpoint = endpoint(payload)
10
+ [transaction.endpoint, KIND, nil]
11
+ end
12
+
13
+ private
14
+
15
+ def endpoint payload
16
+ "#{payload[:controller]}##{payload[:action]}"
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,71 @@
1
+ module Opbeat
2
+ module Normalizers
3
+ module ActionView
4
+
5
+ class RenderNormalizer < Normalizer
6
+ def normalize_render payload, kind
7
+ signature = path_for(payload[:identifier])
8
+
9
+ [signature, kind, nil]
10
+ end
11
+
12
+ private
13
+
14
+ def path_for identifier
15
+ return "Unknown template".freeze unless path = identifier
16
+ return path unless path.start_with?("/")
17
+
18
+ path && relative_path(path)
19
+ end
20
+
21
+ def relative_path path
22
+ root = config.view_paths.find { |p| path.start_with? p }
23
+ type = :app
24
+
25
+ unless root
26
+ root = Gem.path.find { |p| path.start_with? p }
27
+ type = :gem
28
+ end
29
+
30
+ return "Absolute path".freeze unless root
31
+
32
+ start = root.length
33
+ start += 1 if path[root.length] == "/".freeze
34
+
35
+ if type == :gem
36
+ "$GEM_PATH/#{path[start, path.length]}"
37
+ else
38
+ path[start, path.length]
39
+ end
40
+ end
41
+ end
42
+
43
+ class RenderTemplate < RenderNormalizer
44
+ register 'render_template.action_view'
45
+ KIND = 'template.view'.freeze
46
+
47
+ def normalize transaction, name, payload
48
+ normalize_render(payload, KIND)
49
+ end
50
+ end
51
+
52
+ class RenderPartial < RenderNormalizer
53
+ register 'render_partial.action_view'
54
+ KIND = 'template.view.partial'.freeze
55
+
56
+ def normalize transaction, name, payload
57
+ normalize_render(payload, KIND)
58
+ end
59
+ end
60
+
61
+ class RenderCollection < RenderNormalizer
62
+ register 'render_collection.action_view'
63
+ KIND = 'template.view.collection'.freeze
64
+
65
+ def normalize transaction, name, payload
66
+ normalize_render(payload, KIND)
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,41 @@
1
+ require 'opbeat/sql_summarizer'
2
+
3
+ module Opbeat
4
+ module Normalizers
5
+ module ActiveRecord
6
+ class SQL < Normalizer
7
+ register 'sql.active_record'
8
+
9
+ def initialize *args
10
+ super(*args)
11
+ adapter = ::ActiveRecord::Base.connection.adapter_name.downcase rescue nil
12
+ @kind = "db.#{adapter || 'unknown'}.sql".freeze
13
+ @sql_parser = SqlSummarizer.new config
14
+ end
15
+
16
+ def normalize transaction, name, payload
17
+ if %w{SCHEMA CACHE}.include? payload[:name]
18
+ return :skip
19
+ end
20
+
21
+ signature =
22
+ signature_for(payload[:sql]) || # SELECT FROM "users"
23
+ payload[:name] || # Users load
24
+ "SQL".freeze
25
+
26
+ if signature == 'SELECT FROM "schema_migrations"'
27
+ return :skip
28
+ end
29
+
30
+ [signature, @kind, { sql: payload[:sql] }]
31
+ end
32
+
33
+ private
34
+
35
+ def signature_for sql
36
+ @sql_parser.signature_for(sql)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,27 @@
1
+ module Opbeat
2
+ # @api private
3
+ class SqlSummarizer
4
+ CACHE = {}
5
+ TBL = "[^ ]+".freeze
6
+ REGEXES = {
7
+ /^SELECT .* FROM (#{TBL})/i => "SELECT FROM ".freeze,
8
+ /^INSERT INTO (#{TBL})/i => "INSERT INTO ".freeze,
9
+ /^UPDATE (#{TBL})/i => "UPDATE ".freeze,
10
+ /^DELETE FROM (#{TBL})/i => "DELETE FROM ".freeze
11
+ }.freeze
12
+
13
+ def initialize config
14
+ @config = config
15
+ end
16
+
17
+ def signature_for sql
18
+ return CACHE[sql] if CACHE[sql]
19
+
20
+ REGEXES.find do |regex, sig|
21
+ if match = sql.match(regex)
22
+ break sig + match[1]
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,80 @@
1
+ require 'active_support/notifications'
2
+ require 'opbeat/normalizers'
3
+
4
+ module Opbeat
5
+ # @api private
6
+ class Subscriber
7
+ include Logging
8
+
9
+ def initialize config, client
10
+ @config = config
11
+ @client = client
12
+ @normalizers = Normalizers.build config
13
+ end
14
+
15
+ attr_reader :config
16
+
17
+ def register!
18
+ unregister! if @subscription
19
+ @subscription = ActiveSupport::Notifications.subscribe actions_regex, self
20
+ end
21
+
22
+ def unregister!
23
+ ActiveSupport::Notifications.unsubscribe @subscription
24
+ @subscription = nil
25
+ end
26
+
27
+ # AS::Notifications API
28
+
29
+ class Notification
30
+ def initialize id, trace
31
+ @id = id
32
+ @trace = trace
33
+ end
34
+ attr_reader :id, :trace
35
+ end
36
+
37
+ def start name, id, payload
38
+ return unless transaction = @client.current_transaction
39
+
40
+ normalized = @normalizers.normalize(transaction, name, payload)
41
+
42
+ trace = nil
43
+
44
+ unless normalized == :skip
45
+ sig, kind, extra = normalized
46
+
47
+ trace = Trace.new(transaction, sig, kind, transaction.running_traces, extra)
48
+ offset = transaction.current_offset
49
+
50
+ transaction.traces << trace
51
+
52
+ trace.start offset
53
+ end
54
+
55
+ transaction.notifications << Notification.new(id, trace)
56
+ end
57
+
58
+ def finish name, id, payload
59
+ return unless transaction = @client.current_transaction
60
+
61
+ while notification = transaction.notifications.pop
62
+ if notification.id == id
63
+ if trace = notification.trace
64
+ trace.done
65
+ end
66
+ return
67
+ end
68
+ end
69
+ end
70
+
71
+ private
72
+
73
+ def actions_regex
74
+ @actions_regex ||= Regexp.new(
75
+ "(".freeze + @normalizers.keys.join("|".freeze) + ")".freeze
76
+ )
77
+ end
78
+
79
+ end
80
+ end
data/lib/opbeat/tasks.rb CHANGED
@@ -1,24 +1,26 @@
1
- # Capistrano tasks for notifying Opbeat of deploys
2
1
  namespace :opbeat do
3
- desc "Notify Opbeat of a new deploy."
4
- task :deployment do
5
- if defined?(::Rails.root)
6
- initializer_file = ::Rails.root.join('config', 'initializers','opbeat.rb')
7
-
8
- if initializer_file.exist?
9
- load initializer_file
10
- else
11
- Rake::Task[:environment].invoke
12
- end
2
+ desc "Notify Opbeat of a release"
3
+ task :release => :environment do
4
+ unless rev = ENV["REV"]
5
+ puts "Please specify a revision in an env variable\n" +
6
+ "eg. REV=abc123 rake opbeat:release"
7
+ exit 1
13
8
  end
14
- rev = ENV['REV']
15
9
 
16
- unless rev
17
- puts "No revision given. Set environment variable REV."
18
- else
19
- data = {'rev' => ENV['REV'], 'branch' => ENV['BRANCH'], 'status' => 'completed'}
20
- Opbeat::client.send_release(data)
10
+ # empty env means dev
11
+ ENV["RAILS_ENV"] ||= 'development'
12
+
13
+ # log to STDOUT
14
+ Opbeat::Client.inst.config.logger = Logger.new STDOUT
15
+
16
+ unless Opbeat.release({
17
+ rev: rev,
18
+ branch: ENV['BRANCH'],
19
+ status: 'completed'
20
+ }, inline: true)
21
+ exit 1 # release returned nil
21
22
  end
22
23
  end
23
- end
24
24
 
25
+ task :deployment => :release
26
+ end
@@ -0,0 +1,47 @@
1
+ require 'opbeat/util'
2
+
3
+ module Opbeat
4
+ class Trace
5
+
6
+ DEFAULT_KIND = 'code.custom'.freeze
7
+
8
+ def initialize transaction, signature, kind = nil, parents = [], extra = nil
9
+ @transaction = transaction
10
+ @signature = signature
11
+ @kind = kind || DEFAULT_KIND
12
+ @parents = parents || []
13
+ @extra = extra
14
+
15
+ @timestamp = Util.nearest_minute.to_i
16
+ end
17
+
18
+ attr_accessor :signature, :kind, :parents, :extra
19
+ attr_reader :transaction, :timestamp, :duration, :relative_start, :start_time
20
+
21
+ def start relative_to
22
+ @start_time = Util.nanos
23
+ @relative_start = start_time - relative_to
24
+
25
+ self
26
+ end
27
+
28
+ def done ms = Util.nanos
29
+ @duration = ms - start_time
30
+
31
+ self
32
+ end
33
+
34
+ def done?
35
+ !!duration
36
+ end
37
+
38
+ def running?
39
+ !done?
40
+ end
41
+
42
+ def inspect
43
+ info = %w{signature kind parents extra timestamp duration relative_start}
44
+ "<Trace #{info.map { |m| "#{m}:#{send(m).inspect}" }.join(' ')}>"
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,29 @@
1
+ module Opbeat
2
+ module TraceHelpers
3
+ module ClassMethods
4
+ def trace_class_method method, signature, kind
5
+ __trace_method_on(singleton_class, method, signature, kind)
6
+ end
7
+
8
+ private
9
+
10
+ def __trace_method_on(klass, method, signature, kind)
11
+ klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
12
+ alias :"__without_opb_#{method}" :"#{method}"
13
+
14
+ def #{method}(*args, &block)
15
+ Opbeat.trace "#{signature}", "#{kind}" do
16
+ __without_opb_#{method}(*args, &block)
17
+ end
18
+ end
19
+ RUBY
20
+ end
21
+ end
22
+
23
+ def self.included(kls)
24
+ kls.class_eval do
25
+ extend ClassMethods
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,99 @@
1
+ require 'opbeat/util'
2
+
3
+ module Opbeat
4
+ class Transaction
5
+
6
+ ROOT_TRACE_NAME = 'transaction'.freeze
7
+
8
+ def initialize client, endpoint, kind = 'code.custom', result = nil
9
+ @client = client
10
+ @endpoint = endpoint
11
+ @kind = kind
12
+ @result = result
13
+
14
+ @timestamp = Util.nearest_minute.to_i
15
+
16
+ @root_trace = Trace.new(self, ROOT_TRACE_NAME, ROOT_TRACE_NAME)
17
+ @traces = [@root_trace]
18
+ @notifications = []
19
+
20
+ @start_time = Util.nanos
21
+ @root_trace.start @start_time
22
+ end
23
+
24
+ attr_accessor :endpoint, :kind, :result, :duration
25
+ attr_reader :timestamp, :start_time, :traces, :notifications, :root_trace
26
+
27
+ def release
28
+ @client.current_transaction = nil
29
+ end
30
+
31
+ def done result = nil
32
+ @result = result
33
+
34
+ @root_trace.done Util.nanos
35
+ @duration = @root_trace.duration
36
+
37
+ self
38
+ end
39
+
40
+ def done?
41
+ @root_trace.done?
42
+ end
43
+
44
+ def submit result = nil
45
+ done result
46
+
47
+ release
48
+
49
+ @client.submit_transaction self
50
+
51
+ self
52
+ end
53
+
54
+ def trace signature, kind = nil, extra = nil, &block
55
+ trace = Trace.new(self, signature, kind, running_traces, extra)
56
+
57
+ rel_time = current_offset
58
+
59
+ traces << trace
60
+
61
+ trace.start rel_time
62
+
63
+ return trace unless block_given?
64
+
65
+ begin
66
+ result = yield trace
67
+ ensure
68
+ trace.done
69
+ end
70
+
71
+ result
72
+ end
73
+
74
+ def running_traces
75
+ traces.select(&:running?)
76
+ end
77
+
78
+ def current_trace
79
+ traces.reverse.find(&:running?)
80
+ end
81
+
82
+ def current_offset
83
+ if curr = current_trace
84
+ return curr.start_time
85
+ end
86
+
87
+ start_time
88
+ end
89
+
90
+ def inspect
91
+ info = %w{endpoint kind result duration timestamp start_time}
92
+ <<-TEXT
93
+ <Transaction #{info.map { |m| "#{m}:#{send(m).inspect}" }.join(' ')}>
94
+ #{traces.map(&:inspect).join("\n ")}"
95
+ TEXT
96
+ end
97
+
98
+ end
99
+ end