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
data/Makefile DELETED
@@ -1,3 +0,0 @@
1
- test:
2
- bundle install
3
- rake spec
@@ -1,9 +0,0 @@
1
- source "http://rubygems.org"
2
-
3
- gem "rails", "~> 3.0.0"
4
- gem "rake"
5
- gem "rspec"
6
-
7
- gem "opbeat", :path => "../"
8
-
9
- gemspec :path => "../"
@@ -1,9 +0,0 @@
1
- source "http://rubygems.org"
2
-
3
- gem "rails", "~> 3.1.0"
4
- gem "rake"
5
- gem "rspec"
6
-
7
- gem "opbeat", :path => "../"
8
-
9
- gemspec :path => "../"
@@ -1,9 +0,0 @@
1
- source "http://rubygems.org"
2
-
3
- gem "rails", "~> 3.2.0"
4
- gem "rake"
5
- gem "rspec"
6
-
7
- gem "opbeat", :path => "../"
8
-
9
- gemspec :path => "../"
@@ -1,9 +0,0 @@
1
- source "http://rubygems.org"
2
-
3
- gem "rails", "~> 4.0.0"
4
- gem "rake"
5
- gem "rspec"
6
-
7
- gem "opbeat", :path => "../"
8
-
9
- gemspec :path => "../"
@@ -1,9 +0,0 @@
1
- source "http://rubygems.org"
2
-
3
- gem "rails", "~> 4.1.0"
4
- gem "rake"
5
- gem "rspec"
6
-
7
- gem "opbeat", :path => "../"
8
-
9
- gemspec :path => "../"
@@ -1,9 +0,0 @@
1
- source "http://rubygems.org"
2
-
3
- gem "rails", "~> 4.2.0"
4
- gem "rake"
5
- gem "rspec"
6
-
7
- gem "opbeat", :path => "../"
8
-
9
- gemspec :path => "../"
@@ -1,10 +0,0 @@
1
- source "http://rubygems.org"
2
-
3
- gem "i18n", "~> 0.6.11" # pin to <0.7 to support ruby 1.9.2
4
- gem "rails", "~> 3.1.0"
5
- gem "rake"
6
- gem "rspec"
7
-
8
- gem "opbeat", :path => "../"
9
-
10
- gemspec :path => "../"
@@ -1,10 +0,0 @@
1
- source "http://rubygems.org"
2
-
3
- gem "i18n", "~> 0.6.11" # pin to <0.7 to support ruby 1.9.2
4
- gem "rails", "~> 3.2.0"
5
- gem "rake"
6
- gem "rspec"
7
-
8
- gem "opbeat", :path => "../"
9
-
10
- gemspec :path => "../"
@@ -1,11 +0,0 @@
1
- source "http://rubygems.org"
2
-
3
- gem "rails", "~> 3.2.6"
4
- gem "rake"
5
- gem "rspec"
6
- gem "simplecov"
7
- gem "delayed_job"
8
- gem "sidekiq", "~> 3.1.0"
9
- gem "opbeat", :path => "../"
10
-
11
- gemspec :path => "../"
@@ -1,44 +0,0 @@
1
- require 'set'
2
-
3
- module Opbeat
4
- module BetterAttrAccessor
5
-
6
- def attributes
7
- Hash[
8
- self.class.attributes.map do |attr|
9
- [attr, send(attr)]
10
- end
11
- ]
12
- end
13
-
14
- def self.included(base)
15
- base.extend ClassMethods
16
- end
17
-
18
- module ClassMethods
19
- def attributes
20
- @attributes ||= Set.new
21
-
22
- if superclass.include? BetterAttrAccessor
23
- @attributes + superclass.attributes
24
- else
25
- @attributes
26
- end
27
- end
28
-
29
- def attr_accessor(attr, options = {})
30
- @attributes ||= Set.new
31
- @attributes << attr.to_s
32
-
33
- define_method attr do
34
- if instance_variable_defined? "@#{attr}"
35
- instance_variable_get "@#{attr}"
36
- elsif options.key? :default
37
- instance_variable_set "@#{attr}", options[:default].dup
38
- end
39
- end
40
- attr_writer attr
41
- end
42
- end
43
- end
44
- end
data/lib/opbeat/event.rb DELETED
@@ -1,223 +0,0 @@
1
- require 'rubygems'
2
- require 'socket'
3
-
4
- require 'opbeat/error'
5
- require 'opbeat/linecache'
6
-
7
- module Opbeat
8
-
9
- class Event
10
-
11
- LOG_LEVELS = {
12
- "debug" => "debug",
13
- "info" => "info",
14
- "warn" => "warn",
15
- "warning" => "warn",
16
- "error" => "error",
17
- }
18
-
19
- BACKTRACE_RE = /^(.+?):(\d+)(?::in `(.+?)')?$/
20
-
21
- attr_reader :id
22
- attr_accessor :organization, :app, :message, :timestamp, :level
23
- attr_accessor :logger, :culprit, :hostname, :modules, :extra, :user
24
- attr_accessor :environment
25
-
26
- def initialize(options={}, configuration=nil, &block)
27
- @configuration = configuration || Opbeat.configuration
28
- @interfaces = {}
29
-
30
- @id = options[:id]
31
- @message = options[:message]
32
- @timestamp = options[:timestamp] || Time.now.utc
33
- @level = options[:level] || :error
34
- @logger = options[:logger] || 'root'
35
- @culprit = options[:culprit]
36
- @environment = @configuration[:current_environment]
37
- @extra = options[:extra]
38
- @user = options[:user]
39
-
40
- # Try to resolve the hostname to an FQDN, but fall back to whatever the load name is
41
- hostname = Socket.gethostname
42
- hostname = Socket.gethostbyname(hostname).first rescue hostname
43
- @hostname = options[:hostname] || hostname
44
-
45
- block.call(self) if block
46
-
47
- # Some type coercion
48
- @timestamp = @timestamp.strftime('%Y-%m-%dT%H:%M:%S') if @timestamp.is_a?(Time)
49
- @level = LOG_LEVELS[@level.to_s.downcase] if @level.is_a?(String) || @level.is_a?(Symbol)
50
-
51
- # Basic sanity checking
52
- raise Error.new('A message is required for all events') unless @message && !@message.empty?
53
- raise Error.new('A timestamp is required for all events') unless @timestamp
54
- end
55
-
56
- def interface(name, value=nil, &block)
57
- int = Opbeat::find_interface(name)
58
- Opbeat.logger.info "Unknown interface: #{name}" unless int
59
- raise Error.new("Unknown interface: #{name}") unless int
60
- @interfaces[int.name] = int.new(value, &block) if value || block
61
- @interfaces[int.name]
62
- end
63
-
64
- def [](key)
65
- interface(key)
66
- end
67
-
68
- def []=(key, value)
69
- interface(key, value)
70
- end
71
-
72
- def to_hash
73
- data = {
74
- 'message' => self.message,
75
- 'timestamp' => self.timestamp,
76
- 'level' => self.level,
77
- 'logger' => self.logger,
78
- }
79
- data['client_supplied_id'] = self.id if self.id
80
- data['culprit'] = self.culprit if self.culprit
81
- data['machine'] = {'hostname' => self.hostname } if self.hostname
82
- data['environment'] = self.environment if self.environment # Future proofing: Environment is currently not used by the Opbeat API
83
- data['extra'] = self.extra || {}
84
- data['extra']['ruby'] = "#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}" unless data['extra']['ruby']
85
- data['extra']['rails'] = ::Rails::VERSION::STRING if defined?(::Rails::VERSION::STRING) && !data['extra']['rails']
86
- if self.user
87
- data['user'] = self.user
88
- if self.user[:id] or self.user[:email] or self.user[:username]
89
- data['user'][:is_authenticated] = true
90
- end
91
- data['user'][:is_authenticated] = false if !data['user'][:is_authenticated]
92
- end
93
- @interfaces.each_pair do |name, int_data|
94
- data[name] = int_data.to_hash
95
- end
96
- data
97
- end
98
-
99
- def self.from_exception(exc, options={}, &block)
100
- configuration = Opbeat.configuration
101
- if exc.is_a?(Opbeat::Error)
102
- # Try to prevent error reporting loops
103
- Opbeat.logger.info "Refusing to capture Opbeat error: #{exc.inspect}"
104
- return nil
105
- end
106
- if configuration[:excluded_exceptions].include? exc.class.name
107
- Opbeat.logger.info "User excluded error: #{exc.inspect}"
108
- return nil
109
- end
110
- options = self.merge_context(options)
111
- self.new(options, configuration) do |evt|
112
- evt.message = "#{exc.class.to_s}: #{exc.message}"
113
- evt.level = :error
114
- evt.parse_exception(exc)
115
- evt.interface :stack_trace do |int|
116
- int.frames = exc.backtrace.reverse.map do |trace_line|
117
- int.frame {|frame| evt.parse_backtrace_line(trace_line, frame) }
118
- end
119
- evt.culprit = evt.get_culprit(int.frames)
120
- end
121
- block.call(evt) if block
122
- end
123
- end
124
-
125
- def self.from_rack_exception(exc, rack_env, options={}, &block)
126
- from_exception(exc, options) do |evt|
127
- evt.interface :http do |int|
128
- int.from_rack(rack_env)
129
- end
130
-
131
- if not evt.user
132
- controller = rack_env["action_controller.instance"]
133
- user_method_name = Opbeat.configuration.user_controller_method
134
- if controller and controller.respond_to? user_method_name
135
- user_obj = controller.send user_method_name
136
- evt.from_user_object(user_obj)
137
- end
138
- end
139
-
140
- block.call(evt) if block
141
- end
142
- end
143
-
144
- def self.from_message(message, stack, options={})
145
- configuration = Opbeat.configuration
146
- options = self.merge_context(options)
147
- self.new(options, configuration) do |evt|
148
- evt.message = message
149
- evt.level = :error
150
- evt.interface :message do |int|
151
- int.message = message
152
- end
153
- evt.interface :stack_trace do |int|
154
- int.frames = stack.reverse.map do |trace_line|
155
- int.frame {|frame| evt.parse_backtrace_line(trace_line, frame) }
156
- end
157
- end
158
- end
159
- end
160
-
161
- def self.set_context(options={})
162
- Thread.current["_opbeat_context"] = options
163
- end
164
-
165
- def get_culprit(frames)
166
- lastframe = frames[-2]
167
- "#{lastframe.filename} in #{lastframe.function}" if lastframe
168
- end
169
-
170
- def parse_exception(exception)
171
- interface(:exception) do |int|
172
- int.type = exception.class.to_s
173
- int.value = exception.message
174
- int.module = exception.class.to_s.split('::')[0...-1].join('::')
175
- end
176
- end
177
-
178
- def parse_backtrace_line(line, frame)
179
- md = BACKTRACE_RE.match(line)
180
- raise Error.new("Unable to parse backtrace line: #{line.inspect}") unless md
181
- frame.abs_path = md[1]
182
- frame.lineno = md[2].to_i
183
- frame.function = md[3] if md[3]
184
- frame.filename = strip_load_path_from(frame.abs_path)
185
- if context_lines = @configuration[:context_lines]
186
- frame.pre_context, frame.context_line, frame.post_context = \
187
- get_contextlines(frame.abs_path, frame.lineno, context_lines)
188
- end
189
- frame
190
- end
191
-
192
- def from_user_object(user_obj)
193
- @user = {} if not @user
194
- @user[:id] = user_obj.send(:id) rescue nil
195
- @user[:email] = user_obj.send(:email) rescue nil
196
- @user[:username] = user_obj.send(:username) rescue nil
197
- end
198
-
199
- private
200
-
201
- def self.merge_context(options={})
202
- context_options = Thread.current["_opbeat_context"] || {}
203
- context_options.merge(options)
204
- end
205
-
206
-
207
- # Because linecache can go to hell
208
- def self._source_lines(path, from, to)
209
- end
210
-
211
- def get_contextlines(path, line, context)
212
- lines = (2 * context + 1).times.map do |i|
213
- Opbeat::LineCache::getline(path, line - context + i)
214
- end
215
- [lines[0..(context-1)], lines[context], lines[(context+1)..-1]]
216
- end
217
-
218
- def strip_load_path_from(path)
219
- prefix = $:.select {|s| path.start_with?(s.to_s)}.sort_by {|s| s.to_s.length}.last
220
- prefix ? path[prefix.to_s.chomp(File::SEPARATOR).length+1..-1] : path
221
- end
222
- end
223
- end
@@ -1,22 +0,0 @@
1
- begin
2
- require 'resque'
3
- rescue LoadError
4
- end
5
-
6
- if defined?(Resque)
7
-
8
- module Resque
9
- module Failure
10
- # Failure backend for Opbeat
11
- class Opbeat < Base
12
- # @override (see Resque::Failure::Base#save)
13
- # @param (see Resque::Failure::Base#save)
14
- # @return (see Resque::Failure::Base#save)
15
- def save
16
- ::Opbeat.capture_exception(exception)
17
- end
18
- end
19
- end
20
- end
21
-
22
- end
@@ -1,32 +0,0 @@
1
- begin
2
- require 'sidekiq'
3
- rescue LoadError
4
- end
5
-
6
- if defined? Sidekiq
7
- module Opbeat
8
- module Integrations
9
- class Sidekiq
10
- def call(worker, msg, queue)
11
- begin
12
- yield
13
- rescue Exception => ex
14
- raise ex if [Interrupt, SystemExit, SignalException].include? ex.class
15
- ::Opbeat.capture_exception(ex)
16
- raise
17
- end
18
- end
19
- end
20
- end
21
- end
22
-
23
- ::Sidekiq.configure_server do |config|
24
- if ::Sidekiq::VERSION < '3'
25
- config.server_middleware do |chain|
26
- chain.add ::Opbeat::Integrations::Sidekiq
27
- end
28
- else
29
- config.error_handlers << Proc.new { |ex, ctx| ::Opbeat.capture_exception(ex) }
30
- end
31
- end
32
- end
@@ -1,35 +0,0 @@
1
- require 'opbeat/better_attr_accessor'
2
-
3
- module Opbeat
4
-
5
- INTERFACES = {}
6
-
7
- class Interface
8
- include BetterAttrAccessor
9
- alias_method :to_hash, :attributes
10
-
11
- def initialize(attributes = nil)
12
- attributes.each do |attr, value|
13
- send "#{attr}=", value
14
- end if attributes
15
-
16
- yield self if block_given?
17
- end
18
-
19
- def self.name(value = nil)
20
- @interface_name ||= value
21
- end
22
- end
23
-
24
- def self.register_interface(mapping)
25
- mapping.each_pair do |key, klass|
26
- INTERFACES[key.to_s] = klass
27
- INTERFACES[klass.name] = klass
28
- end
29
- end
30
-
31
- def self.find_interface(name)
32
- INTERFACES[name.to_s]
33
- end
34
-
35
- end