sentry-raven 0.12.3 → 0.13.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f4d1ff44aab9878c7070e85ac6bac6a2573e5332
4
- data.tar.gz: 7668ff7bdc645dc3d77305f0be63bd028696eee5
3
+ metadata.gz: c09fc2d9d439ff50aa3d575716890797ebb81cb6
4
+ data.tar.gz: 834dc9c9d24c2bf004f071b9ec77d3c96edb22e7
5
5
  SHA512:
6
- metadata.gz: ba3fb97a2c6a77adf1e8d5afcf00d7d94f14b3d5bf3851db165e0624afc1aa702efd61d2c3f24cf9195b8b9e2bedf72244219f7bd61a698e8d443732e227efec
7
- data.tar.gz: e96788e536488bed998d179c9c752157044c5a703de5c479c9265966bde529f6d37dcba908478e9a292e4c149256f1ecb67ab748c2e89829ae73c8496c8d7e4a
6
+ metadata.gz: b07c730db8e117c99f3f3e40bbf66863880bb630b2e57de211335994749a930f3f9ea4a86b49eb3f632a88c09184588c0d38b73ce9f0fb3482845c4ccfe4f904
7
+ data.tar.gz: 3e3390603c2835ff88c0644c753a3459f721026adc5bb0f03e207158f65528e861363c571d6a73c7185b0f844fdfdb60190b31fe0ed6e6db3e5bcc7363e69b85
data/README.md CHANGED
@@ -2,13 +2,12 @@
2
2
 
3
3
  [![Gem Version](https://img.shields.io/gem/v/sentry-raven.svg)](https://rubygems.org/gems/sentry-raven)
4
4
  [![Build Status](https://img.shields.io/travis/getsentry/raven-ruby/master.svg)](https://travis-ci.org/getsentry/raven-ruby)
5
- [![Coverage Status](https://img.shields.io/coveralls/getsentry/raven-ruby/master.svg)](https://coveralls.io/r/getsentry/raven-ruby)
6
5
 
7
6
  A client and integration layer for the [Sentry](https://github.com/getsentry/sentry) error reporting API.
8
7
 
9
8
  ## Requirements
10
9
 
11
- We test on Ruby MRI 1.8.7/REE, 1.9.3, 2.0 and 2.1. JRuby support is experimental - check TravisCI to see if the build is passing or failing.
10
+ We test on Ruby MRI 1.8.7/REE, 1.9.3, 2.0, 2.1 and 2.2. JRuby support is experimental - check TravisCI to see if the build is passing or failing.
12
11
 
13
12
  ## Getting Started
14
13
  ### Install
@@ -45,7 +44,7 @@ end
45
44
 
46
45
  ## More Information
47
46
 
48
- Full documentation and more information on advanced configuration, sending more information, scrubbing sensitive data, and more can be found on [the wiki](https://github.com/getsentry/raven-ruby/wiki).
47
+ Full documentation and more information on advanced configuration, sending more information, scrubbing sensitive data, and more can be found on [the wiki](https://github.com/getsentry/raven-ruby/wiki).
49
48
 
50
49
  * [Documentation](https://github.com/getsentry/raven-ruby/wiki)
51
50
  * [Bug Tracker](http://github.com/getsentry/raven-ruby/issues>)
data/lib/raven/base.rb CHANGED
@@ -7,6 +7,7 @@ require 'raven/event'
7
7
  require 'raven/logger'
8
8
  require 'raven/interfaces/message'
9
9
  require 'raven/interfaces/exception'
10
+ require 'raven/interfaces/single_exception'
10
11
  require 'raven/interfaces/stack_trace'
11
12
  require 'raven/interfaces/http'
12
13
  require 'raven/processor'
@@ -49,9 +50,15 @@ module Raven
49
50
  end
50
51
 
51
52
  # Tell the log that the client is good to go
52
- def report_ready
53
- self.logger.info "Raven #{VERSION} ready to catch errors"
53
+ def report_status
54
+ return if client.configuration.silence_ready
55
+ if client.configuration.send_in_current_environment?
56
+ logger.info "Raven #{VERSION} ready to catch errors"
57
+ else
58
+ logger.info "Raven #{VERSION} configured not to send errors."
59
+ end
54
60
  end
61
+ alias_method :report_ready, :report_status
55
62
 
56
63
  # Call this method to modify defaults in your initializers.
57
64
  #
@@ -59,11 +66,11 @@ module Raven
59
66
  # Raven.configure do |config|
60
67
  # config.server = 'http://...'
61
68
  # end
62
- def configure(silent = false)
69
+ def configure
63
70
  yield(configuration) if block_given?
64
71
 
65
72
  self.client = Client.new(configuration)
66
- report_ready unless silent
73
+ report_status
67
74
  self.client
68
75
  end
69
76
 
@@ -83,65 +90,39 @@ module Raven
83
90
  # Raven.capture do
84
91
  # MyApp.run
85
92
  # end
86
- def capture(options = {}, &block)
87
- if block
88
- begin
89
- block.call
90
- rescue Error
91
- raise # Don't capture Raven errors
92
- rescue Exception => e
93
- capture_exception(e, options)
94
- raise
95
- end
96
- else
97
- # Install at_exit hook
98
- at_exit do
99
- if $ERROR_INFO
100
- logger.debug "Caught a post-mortem exception: #{$ERROR_INFO.inspect}"
101
- capture_exception($ERROR_INFO, options)
102
- end
103
- end
93
+ def capture(options = {})
94
+ install_at_exit_hook unless block_given?
95
+ begin
96
+ yield
97
+ rescue Error
98
+ raise # Don't capture Raven errors
99
+ rescue Exception => e
100
+ capture_exception(e, options)
101
+ raise
104
102
  end
105
103
  end
106
104
 
107
- def capture_exception(exception, options = {})
108
- send_or_skip(exception) do
109
- if (evt = Event.from_exception(exception, options))
110
- yield evt if block_given?
111
- if configuration.async?
112
- configuration.async.call(evt)
113
- else
114
- send(evt)
115
- end
105
+ def capture_type(obj, options = {})
106
+ return false unless should_capture?(obj)
107
+ message_or_exc = obj.is_a?(String) ? "message" : "exception"
108
+ if (evt = Event.send("from_" + message_or_exc, obj, options))
109
+ yield evt if block_given?
110
+ if configuration.async?
111
+ configuration.async.call(evt)
112
+ else
113
+ send(evt)
116
114
  end
117
115
  end
118
116
  end
117
+ alias_method :capture_message, :capture_type
118
+ alias_method :capture_exception, :capture_type
119
119
 
120
- def capture_message(message, options = {})
121
- send_or_skip(message) do
122
- if (evt = Event.from_message(message, options))
123
- yield evt if block_given?
124
- if configuration.async?
125
- configuration.async.call(evt)
126
- else
127
- send(evt)
128
- end
129
- end
130
- end
131
- end
132
-
133
- def send_or_skip(exc)
134
- should_send = if configuration.should_send
135
- configuration.should_send.call(*[exc])
120
+ def should_capture?(message_or_exc)
121
+ if configuration.should_capture
122
+ configuration.should_capture.call(*[message_or_exc])
136
123
  else
137
124
  true
138
125
  end
139
-
140
- if configuration.send_in_current_environment? && should_send
141
- yield if block_given?
142
- else
143
- configuration.log_excluded_environment_message
144
- end
145
126
  end
146
127
 
147
128
  # Provides extra context to the exception prior to it being handled by
@@ -231,5 +212,14 @@ module Raven
231
212
  alias :captureMessage :capture_message
232
213
  alias :annotateException :annotate_exception
233
214
  alias :annotate :annotate_exception
215
+
216
+ private
217
+
218
+ def install_at_exit_hook
219
+ at_exit do
220
+ logger.debug "Caught a post-mortem exception: #{$ERROR_INFO.inspect}"
221
+ capture_exception($ERROR_INFO, options)
222
+ end
223
+ end
234
224
  end
235
225
  end
data/lib/raven/client.rb CHANGED
@@ -7,9 +7,8 @@ require 'raven/transports/http'
7
7
  require 'raven/transports/udp'
8
8
 
9
9
  module Raven
10
-
10
+ # Encodes events and sends them to the Sentry server.
11
11
  class Client
12
-
13
12
  PROTOCOL_VERSION = '5'
14
13
  USER_AGENT = "raven-ruby/#{Raven::VERSION}"
15
14
  CONTENT_TYPE = 'application/json'
@@ -23,22 +22,20 @@ module Raven
23
22
  end
24
23
 
25
24
  def send(event)
26
- unless configuration.send_in_current_environment?
27
- configuration.log_excluded_environment_message
28
- return
29
- end
25
+ return false unless configuration_allows_sending
30
26
 
31
- # Set the project ID correctly
32
- event.project = self.configuration.project_id
27
+ # Convert to hash
28
+ event = event.to_hash
33
29
 
34
30
  if !@state.should_try?
35
31
  Raven.logger.error("Not sending event due to previous failure(s): #{get_log_message(event)}")
36
32
  return
37
33
  end
38
34
 
39
- Raven.logger.debug "Sending event #{event.id} to Sentry"
35
+ Raven.logger.debug "Sending event #{event['id']} to Sentry"
40
36
 
41
37
  content_type, encoded_data = encode(event)
38
+
42
39
  begin
43
40
  transport.send(generate_auth_header, encoded_data,
44
41
  :content_type => content_type)
@@ -54,39 +51,40 @@ module Raven
54
51
 
55
52
  private
56
53
 
57
- def encode(event)
58
- hash = event.to_hash
59
-
60
- # apply processors
61
- hash = @processors.reduce(hash) do |memo, processor|
62
- processor.process(memo)
54
+ def configuration_allows_sending
55
+ if configuration.send_in_current_environment?
56
+ true
57
+ else
58
+ configuration.log_excluded_environment_message
59
+ false
63
60
  end
61
+ end
64
62
 
63
+ def encode(event)
64
+ hash = @processors.reduce(event.to_hash) { |memo, p| p.process(memo) }
65
65
  encoded = OkJson.encode(hash)
66
66
 
67
- case self.configuration.encoding
67
+ case configuration.encoding
68
68
  when 'gzip'
69
- gzipped = Zlib::Deflate.deflate(encoded)
70
- b64_encoded = strict_encode64(gzipped)
71
- return 'application/octet-stream', b64_encoded
69
+ ['application/octet-stream', strict_encode64(Zlib::Deflate.deflate(encoded))]
72
70
  else
73
- return 'application/json', encoded
71
+ ['application/json', encoded]
74
72
  end
75
73
  end
76
74
 
77
75
  def get_log_message(event)
78
- (event && event.message) || '<no message value>'
76
+ (event && event['message']) || '<no message value>'
79
77
  end
80
78
 
81
79
  def transport
82
80
  @transport ||=
83
- case self.configuration.scheme
81
+ case configuration.scheme
84
82
  when 'udp'
85
- Transports::UDP.new self.configuration
83
+ Transports::UDP.new(configuration)
86
84
  when 'http', 'https'
87
- Transports::HTTP.new self.configuration
85
+ Transports::HTTP.new(configuration)
88
86
  else
89
- raise Error.new("Unknown transport scheme '#{self.configuration.scheme}'")
87
+ raise Error, "Unknown transport scheme '#{self.configuration.scheme}'"
90
88
  end
91
89
  end
92
90
 
@@ -96,14 +94,12 @@ module Raven
96
94
  'sentry_version' => PROTOCOL_VERSION,
97
95
  'sentry_client' => USER_AGENT,
98
96
  'sentry_timestamp' => now,
99
- 'sentry_key' => self.configuration.public_key,
100
- 'sentry_secret' => self.configuration.secret_key,
97
+ 'sentry_key' => configuration.public_key,
98
+ 'sentry_secret' => configuration.secret_key
101
99
  }
102
100
  'Sentry ' + fields.map { |key, value| "#{key}=#{value}" }.join(', ')
103
101
  end
104
102
 
105
- private
106
-
107
103
  def strict_encode64(string)
108
104
  if Base64.respond_to? :strict_encode64
109
105
  Base64.strict_encode64 string
@@ -31,6 +31,9 @@ module Raven
31
31
  # Logger to use internally
32
32
  attr_accessor :logger
33
33
 
34
+ # Silence ready message
35
+ attr_accessor :silence_ready
36
+
34
37
  # Number of lines of code context to capture, or nil for none
35
38
  attr_accessor :context_lines
36
39
 
@@ -68,6 +71,8 @@ module Raven
68
71
 
69
72
  attr_accessor :server_name
70
73
 
74
+ attr_accessor :release
75
+
71
76
  # DEPRECATED: This option is now ignored as we use our own adapter.
72
77
  attr_accessor :json_adapter
73
78
 
@@ -84,8 +89,8 @@ module Raven
84
89
  # ActionDispatch::ShowExceptions or ActionDispatch::DebugExceptions
85
90
  attr_accessor :catch_debugged_exceptions
86
91
 
87
- # Provide a configurable callback to block or send events
88
- attr_accessor :should_send
92
+ # Provide a configurable callback to determine event capture
93
+ attr_accessor :should_capture
89
94
 
90
95
  # additional fields to sanitize
91
96
  attr_accessor :sanitize_fields
data/lib/raven/event.rb CHANGED
@@ -23,52 +23,46 @@ module Raven
23
23
  PLATFORM = "ruby"
24
24
 
25
25
  attr_reader :id
26
- attr_accessor :project, :message, :timestamp, :time_spent, :level
27
- attr_accessor :logger, :culprit, :server_name, :modules, :extra, :tags
28
-
29
- def initialize(options = {}, &block)
30
- @configuration = options[:configuration] || Raven.configuration
31
- @interfaces = {}
32
-
33
- context = options[:context] || Raven.context
34
-
35
- @id = options[:id] || generate_event_id
36
- @message = options[:message]
37
- @timestamp = options[:timestamp] || Time.now.utc
38
- @time_spent = options[:time_spent]
39
-
40
- @level = options[:level] || :error
41
- @logger = options[:logger] || 'root'
42
- @culprit = options[:culprit]
43
- @server_name = options[:server_name] || @configuration.server_name || get_hostname
44
-
45
- options[:modules] ||= get_modules if @configuration.send_modules
46
-
47
- @modules = options[:modules]
48
-
49
- @user = options[:user] || {}
50
- @user.merge!(context.user)
26
+ attr_accessor :project, :message, :timestamp, :time_spent, :level, :logger,
27
+ :culprit, :server_name, :release, :modules, :extra, :tags, :context, :configuration
28
+
29
+ def initialize(init = {})
30
+ @configuration = Raven.configuration
31
+ @interfaces = {}
32
+ @context = Raven.context
33
+ @id = generate_event_id
34
+ @message = nil
35
+ @timestamp = Time.now.utc
36
+ @time_spent = nil
37
+ @level = :error
38
+ @logger = 'root'
39
+ @culprit = nil
40
+ @server_name = @configuration.server_name || get_hostname
41
+ @release = @configuration.release
42
+ @modules = get_modules if @configuration.send_modules
43
+ @user = {}
44
+ @extra = {}
45
+ @tags = {}
46
+
47
+ yield self if block_given?
48
+
49
+ if !self[:http] && @context.rack_env
50
+ interface :http do |int|
51
+ int.from_rack(@context.rack_env)
52
+ end
53
+ end
51
54
 
52
- @extra = options[:extra] || {}
53
- @extra.merge!(context.extra)
55
+ init.each_pair { |key, val| instance_variable_set('@' + key.to_s, val) }
54
56
 
55
- @tags = {}
57
+ @user.merge!(@context.user)
58
+ @extra.merge!(@context.extra)
56
59
  @tags.merge!(@configuration.tags)
57
- @tags.merge!(options[:tags] || {})
58
- @tags.merge!(context.tags)
59
-
60
- block.call(self) if block
61
-
62
- if !self[:http] && context.rack_env
63
- self.interface :http do |int|
64
- int.from_rack(context.rack_env)
65
- end
66
- end
60
+ @tags.merge!(@context.tags)
67
61
 
68
62
  # Some type coercion
69
- @timestamp = @timestamp.strftime('%Y-%m-%dT%H:%M:%S') if @timestamp.is_a?(Time)
63
+ @timestamp = @timestamp.strftime('%Y-%m-%dT%H:%M:%S') if @timestamp.is_a?(Time)
70
64
  @time_spent = (@time_spent*1000).to_i if @time_spent.is_a?(Float)
71
- @level = LOG_LEVELS[@level.to_s.downcase] if @level.is_a?(String) || @level.is_a?(Symbol)
65
+ @level = LOG_LEVELS[@level.to_s.downcase] if @level.is_a?(String) || @level.is_a?(Symbol)
72
66
  end
73
67
 
74
68
  def get_hostname
@@ -99,23 +93,24 @@ module Raven
99
93
 
100
94
  def to_hash
101
95
  data = {
102
- 'event_id' => @id,
103
- 'message' => @message,
104
- 'timestamp' => @timestamp,
105
- 'time_spent' => @time_spent,
106
- 'level' => @level,
107
- 'project' => @project,
108
- 'logger' => @logger,
109
- 'platform' => PLATFORM,
96
+ :event_id => @id,
97
+ :message => @message,
98
+ :timestamp => @timestamp,
99
+ :time_spent => @time_spent,
100
+ :level => @level,
101
+ :project => @project,
102
+ :logger => @logger,
103
+ :platform => PLATFORM,
110
104
  }
111
- data['culprit'] = @culprit if @culprit
112
- data['server_name'] = @server_name if @server_name
113
- data['modules'] = @modules if @modules
114
- data['extra'] = @extra if @extra
115
- data['tags'] = @tags if @tags
116
- data['user'] = @user if @user
105
+ data[:culprit] = @culprit if @culprit
106
+ data[:server_name] = @server_name if @server_name
107
+ data[:release] = @release if @release
108
+ data[:modules] = @modules if @modules
109
+ data[:extra] = @extra if @extra
110
+ data[:tags] = @tags if @tags
111
+ data[:user] = @user if @user
117
112
  @interfaces.each_pair do |name, int_data|
118
- data[name] = int_data.to_hash
113
+ data[name.to_sym] = int_data.to_hash
119
114
  end
120
115
  data
121
116
  end
@@ -135,54 +130,78 @@ module Raven
135
130
  return nil
136
131
  end
137
132
 
138
- context_lines = configuration[:context_lines]
139
-
140
133
  new(options) do |evt|
134
+ evt.configuration = configuration
141
135
  evt.message = "#{exc.class}: #{exc.message}"
142
136
  evt.level = options[:level] || :error
143
137
 
144
- evt.interface(:exception) do |int|
145
- int.type = exc.class.to_s
146
- int.value = exc.to_s
147
- int.module = exc.class.to_s.split('::')[0...-1].join('::')
148
-
149
- # TODO(dcramer): this needs cleaned up, but I couldn't figure out how to
150
- # work Hashie as a non-Rubyist
151
- if exc.backtrace
152
- int.stacktrace = StacktraceInterface.new do |stacktrace|
153
- backtrace = Backtrace.parse(exc.backtrace)
154
- stacktrace.frames = backtrace.lines.reverse.map do |line|
155
- stacktrace.frame do |frame|
156
- frame.abs_path = line.file
157
- frame.function = line.method
158
- frame.lineno = line.number
159
- frame.in_app = line.in_app
160
- if context_lines && frame.abs_path
161
- frame.pre_context, frame.context_line, frame.post_context = \
162
- evt.get_file_context(frame.abs_path, frame.lineno, context_lines)
163
- end
164
- end
165
- end.select { |f| f.filename }
166
-
167
- evt.culprit = evt.get_culprit(stacktrace.frames)
168
- end
169
- end
170
- end
138
+ add_exception_interface(evt, exc)
171
139
 
172
140
  block.call(evt) if block
173
141
  end
174
142
  end
175
143
 
176
144
  def self.from_message(message, options = {})
145
+ configuration = options[:configuration] || Raven.configuration
177
146
  new(options) do |evt|
147
+ evt.configuration = configuration
178
148
  evt.message = message
179
149
  evt.level = options[:level] || :error
180
150
  evt.interface :message do |int|
181
151
  int.message = message
182
152
  end
153
+ if options[:backtrace]
154
+ evt.interface(:stacktrace) do |int|
155
+ stacktrace_interface_from(int, evt, options[:backtrace])
156
+ end
157
+ end
158
+ end
159
+ end
160
+
161
+ def self.add_exception_interface(evt, exc)
162
+ evt.interface(:exception) do |exc_int|
163
+ exceptions = [exc]
164
+ while exc.respond_to?(:cause) && exc.cause
165
+ exceptions << exc.cause
166
+ exc = exc.cause
167
+ end
168
+ exceptions.reverse!
169
+
170
+ exc_int.values = exceptions.map do |exc|
171
+ SingleExceptionInterface.new do |int|
172
+ int.type = exc.class.to_s
173
+ int.value = exc.to_s
174
+ int.module = exc.class.to_s.split('::')[0...-1].join('::')
175
+
176
+ int.stacktrace = if exc.backtrace
177
+ StacktraceInterface.new do |stacktrace|
178
+ stacktrace_interface_from(stacktrace, evt, exc.backtrace)
179
+ end
180
+ end
181
+ end
182
+ end
183
183
  end
184
184
  end
185
185
 
186
+ def self.stacktrace_interface_from(int, evt, backtrace)
187
+ backtrace = Backtrace.parse(backtrace)
188
+ int.frames = backtrace.lines.reverse.map do |line|
189
+ StacktraceInterface::Frame.new.tap do |frame|
190
+ frame.abs_path = line.file
191
+ frame.function = line.method
192
+ frame.lineno = line.number
193
+ frame.in_app = line.in_app
194
+
195
+ if evt.configuration[:context_lines] && frame.abs_path
196
+ frame.pre_context, frame.context_line, frame.post_context = \
197
+ evt.get_file_context(frame.abs_path, frame.lineno, evt.configuration[:context_lines])
198
+ end
199
+ end
200
+ end.select { |f| f.filename }
201
+
202
+ evt.culprit = evt.get_culprit(int.frames)
203
+ end
204
+
186
205
  # Because linecache can go to hell
187
206
  def self._source_lines(_path, _from, _to)
188
207
  end
@@ -22,26 +22,19 @@ module Raven
22
22
  # Use a standard Raven.configure call to configure your server credentials.
23
23
  class Rack
24
24
 
25
- def self.capture_exception(exception, env, options = {})
25
+ def self.capture_type(exception, env, options = {})
26
26
  if env['requested_at']
27
27
  options[:time_spent] = Time.now - env['requested_at']
28
28
  end
29
- Raven.capture_exception(exception, options) do |evt|
29
+ Raven.capture_type(exception, options) do |evt|
30
30
  evt.interface :http do |int|
31
31
  int.from_rack(env)
32
32
  end
33
33
  end
34
34
  end
35
-
36
- def self.capture_message(message, env, options = {})
37
- if env['requested_at']
38
- options[:time_spent] = Time.now - env['requested_at']
39
- end
40
- Raven.capture_message(message, options) do |evt|
41
- evt.interface :http do |int|
42
- int.from_rack(env)
43
- end
44
- end
35
+ class << self
36
+ alias_method :capture_message, :capture_type
37
+ alias_method :capture_exception, :capture_type
45
38
  end
46
39
 
47
40
  def initialize(app)
@@ -15,7 +15,7 @@ module Raven
15
15
  end
16
16
 
17
17
  config.after_initialize do
18
- Raven.configure(true) do |config|
18
+ Raven.configure do |config|
19
19
  config.logger ||= ::Rails.logger
20
20
  config.project_root ||= ::Rails.root
21
21
  end
@@ -1,16 +1,11 @@
1
- require 'raven/better_attr_accessor'
2
-
3
1
  module Raven
4
2
 
5
3
  INTERFACES = {}
6
4
 
7
5
  class Interface
8
- include BetterAttrAccessor
9
- alias_method :to_hash, :attributes
10
-
11
6
  def initialize(attributes = nil)
12
7
  attributes.each do |attr, value|
13
- send "#{attr}=", value
8
+ public_send "#{attr}=", value
14
9
  end if attributes
15
10
 
16
11
  yield self if block_given?
@@ -19,6 +14,10 @@ module Raven
19
14
  def self.name(value = nil)
20
15
  @interface_name ||= value
21
16
  end
17
+
18
+ def to_hash
19
+ Hash[instance_variables.map { |name| [name[1..-1].to_sym, instance_variable_get(name)] } ]
20
+ end
22
21
  end
23
22
 
24
23
  def self.register_interface(mapping)
@@ -4,15 +4,12 @@ module Raven
4
4
  class ExceptionInterface < Interface
5
5
 
6
6
  name 'exception'
7
- attr_accessor :type
8
- attr_accessor :value
9
- attr_accessor :module
10
- attr_accessor :stacktrace
7
+ attr_accessor :values
11
8
 
12
9
  def to_hash(*args)
13
10
  data = super(*args)
14
- if data['stacktrace']
15
- data['stacktrace'] = data['stacktrace'].to_hash
11
+ if data[:values]
12
+ data[:values] = data[:values].map(&:to_hash)
16
13
  end
17
14
  data
18
15
  end
@@ -15,6 +15,7 @@ module Raven
15
15
  def initialize(*arguments)
16
16
  self.headers = {}
17
17
  self.env = {}
18
+ self.cookies = nil
18
19
  super(*arguments)
19
20
  end
20
21
 
@@ -0,0 +1,19 @@
1
+ require 'raven/interfaces'
2
+
3
+ module Raven
4
+ class SingleExceptionInterface < Interface
5
+
6
+ attr_accessor :type
7
+ attr_accessor :value
8
+ attr_accessor :module
9
+ attr_accessor :stacktrace
10
+
11
+ def to_hash(*args)
12
+ data = super(*args)
13
+ if data[:stacktrace]
14
+ data[:stacktrace] = data[:stacktrace].to_hash
15
+ end
16
+ data
17
+ end
18
+ end
19
+ end
@@ -4,7 +4,7 @@ module Raven
4
4
  class StacktraceInterface < Interface
5
5
 
6
6
  name 'stacktrace'
7
- attr_accessor :frames, :default => []
7
+ attr_accessor :frames
8
8
 
9
9
  def initialize(*arguments)
10
10
  self.frames = []
@@ -13,39 +13,49 @@ module Raven
13
13
 
14
14
  def to_hash(*args)
15
15
  data = super(*args)
16
- data['frames'] = data['frames'].map { |frame| frame.to_hash }
16
+ data[:frames] = data[:frames].map { |frame| frame.to_hash }
17
17
  data
18
18
  end
19
19
 
20
- def frame(attributes = nil, &block)
21
- Frame.new(attributes, &block)
22
- end
23
-
24
20
  # Not actually an interface, but I want to use the same style
25
21
  class Frame < Interface
26
22
  attr_accessor :abs_path
27
23
  attr_accessor :function
28
- attr_accessor :vars, :default => []
29
- attr_accessor :pre_context, :default => []
30
- attr_accessor :post_context, :default => []
24
+ attr_accessor :vars
25
+ attr_accessor :pre_context
26
+ attr_accessor :post_context
31
27
  attr_accessor :context_line
32
28
  attr_accessor :lineno
33
29
  attr_accessor :in_app
34
30
 
31
+ def initialize(*arguments)
32
+ self.vars, self.pre_context, self.post_context = [], [], []
33
+ super(*arguments)
34
+ end
35
+
35
36
  def filename
36
37
  return nil if self.abs_path.nil?
37
38
 
38
- prefix = $LOAD_PATH.select { |s| self.abs_path.start_with?(s.to_s) }.sort_by { |s| s.to_s.length }.last
39
+ prefix = if project_root && self.abs_path.start_with?(project_root)
40
+ project_root
41
+ else
42
+ $LOAD_PATH.select { |s| self.abs_path.start_with?(s.to_s) }.sort_by { |s| s.to_s.length }.last
43
+ end
44
+
39
45
  prefix ? self.abs_path[prefix.to_s.chomp(File::SEPARATOR).length+1..-1] : self.abs_path
40
46
  end
41
47
 
48
+ def project_root
49
+ @project_root ||= Raven.configuration.project_root && Raven.configuration.project_root.to_s
50
+ end
51
+
42
52
  def to_hash(*args)
43
53
  data = super(*args)
44
- data['filename'] = self.filename
45
- data.delete('vars') unless self.vars && !self.vars.empty?
46
- data.delete('pre_context') unless self.pre_context && !self.pre_context.empty?
47
- data.delete('post_context') unless self.post_context && !self.post_context.empty?
48
- data.delete('context_line') unless self.context_line && !self.context_line.empty?
54
+ data[:filename] = self.filename
55
+ data.delete(:vars) unless self.vars && !self.vars.empty?
56
+ data.delete(:pre_context) unless self.pre_context && !self.pre_context.empty?
57
+ data.delete(:post_context) unless self.post_context && !self.post_context.empty?
58
+ data.delete(:context_line) unless self.context_line && !self.context_line.empty?
49
59
  data
50
60
  end
51
61
  end
@@ -1,7 +1,6 @@
1
1
  # A much simpler source line cacher because linecache sucks at platform compat
2
2
 
3
3
  module Raven
4
-
5
4
  class LineCache
6
5
  class << self
7
6
  CACHE = {}
@@ -1,27 +1,11 @@
1
- require 'json'
2
-
3
1
  module Raven
4
2
  class Processor
5
- attr_accessor :sanitize_fields
6
-
7
3
  def initialize(client)
8
4
  @client = client
9
- @sanitize_fields = client.configuration.sanitize_fields
10
5
  end
11
6
 
12
7
  def process(data)
13
- data
14
- end
15
-
16
- private
17
-
18
- def parse_json_or_nil(string)
19
- begin
20
- OkJson.decode(string)
21
- rescue Raven::OkJson::Error
22
- nil
23
- end
8
+ raise NotImplementedError
24
9
  end
25
-
26
10
  end
27
11
  end
@@ -2,7 +2,11 @@ module Raven
2
2
  class Processor::RemoveStacktrace < Processor
3
3
 
4
4
  def process(value)
5
- value['exception'].delete('stacktrace') if value['exception']
5
+ if value[:exception]
6
+ value[:exception][:values].map do |single_exception|
7
+ single_exception.delete(:stacktrace) if single_exception[:stacktrace]
8
+ end
9
+ end
6
10
 
7
11
  value
8
12
  end
@@ -1,3 +1,4 @@
1
+ require 'json'
1
2
  module Raven
2
3
  class Processor::SanitizeData < Processor
3
4
  STRING_MASK = '********'
@@ -5,6 +6,13 @@ module Raven
5
6
  DEFAULT_FIELDS = %w(authorization password passwd secret ssn social(.*)?sec)
6
7
  CREDIT_CARD_RE = /^(?:\d[ -]*?){13,16}$/
7
8
 
9
+ attr_accessor :sanitize_fields
10
+
11
+ def initialize(client)
12
+ super
13
+ self.sanitize_fields = client.configuration.sanitize_fields
14
+ end
15
+
8
16
  def process(value)
9
17
  value.inject(value) { |memo,(k,v)| memo[k] = sanitize(k,v); memo }
10
18
  end
@@ -16,13 +24,17 @@ module Raven
16
24
  v.map{|a| sanitize(k, a)}
17
25
  elsif k == 'query_string'
18
26
  sanitize_query_string(v)
19
- elsif v.is_a?(String) && (json = parse_json_or_nil(v))
20
- #if this string is actually a json obj, convert and sanitize
21
- json.is_a?(Hash) ? process(json).to_json : v
22
- elsif v.is_a?(Integer) && (CREDIT_CARD_RE.match(v.to_s) || fields_re.match(k.to_s))
27
+ elsif v.is_a?(Integer) && matches_regexes?(k,v)
23
28
  INT_MASK
24
- elsif v.is_a?(String) && (CREDIT_CARD_RE.match(v.to_s) || fields_re.match(k.to_s))
25
- STRING_MASK
29
+ elsif v.is_a?(String)
30
+ if fields_re.match(v.to_s) && (json = parse_json_or_nil(v))
31
+ #if this string is actually a json obj, convert and sanitize
32
+ json.is_a?(Hash) ? process(json).to_json : v
33
+ elsif matches_regexes?(k,v)
34
+ STRING_MASK
35
+ else
36
+ v
37
+ end
26
38
  else
27
39
  v
28
40
  end
@@ -36,8 +48,20 @@ module Raven
36
48
  URI.encode_www_form(processed_query_hash)
37
49
  end
38
50
 
51
+ def matches_regexes?(k, v)
52
+ CREDIT_CARD_RE.match(v.to_s) || fields_re.match(k.to_s)
53
+ end
54
+
39
55
  def fields_re
40
- @fields_re ||= /(#{(DEFAULT_FIELDS + @sanitize_fields).join("|")})/i
56
+ @fields_re ||= /(#{(DEFAULT_FIELDS | sanitize_fields).join("|")})/i
57
+ end
58
+
59
+ def parse_json_or_nil(string)
60
+ begin
61
+ OkJson.decode(string)
62
+ rescue Raven::OkJson::Error, NoMethodError
63
+ nil
64
+ end
41
65
  end
42
66
  end
43
67
  end
data/lib/raven/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Raven
2
- VERSION = "0.12.3"
2
+ VERSION = "0.13.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sentry-raven
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.3
4
+ version: 0.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sentry Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-16 00:00:00.000000000 Z
11
+ date: 2015-04-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -66,20 +66,6 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '1.16'
69
- - !ruby/object:Gem::Dependency
70
- name: coveralls
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
69
  - !ruby/object:Gem::Dependency
84
70
  name: rest-client
85
71
  requirement: !ruby/object:Gem::Requirement
@@ -124,7 +110,6 @@ files:
124
110
  - lib/raven/backports/uri.rb
125
111
  - lib/raven/backtrace.rb
126
112
  - lib/raven/base.rb
127
- - lib/raven/better_attr_accessor.rb
128
113
  - lib/raven/cli.rb
129
114
  - lib/raven/client.rb
130
115
  - lib/raven/configuration.rb
@@ -143,6 +128,7 @@ files:
143
128
  - lib/raven/interfaces/exception.rb
144
129
  - lib/raven/interfaces/http.rb
145
130
  - lib/raven/interfaces/message.rb
131
+ - lib/raven/interfaces/single_exception.rb
146
132
  - lib/raven/interfaces/stack_trace.rb
147
133
  - lib/raven/linecache.rb
148
134
  - lib/raven/logger.rb
@@ -1,44 +0,0 @@
1
- require 'set'
2
-
3
- module Raven
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