sentry-raven 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -100,6 +100,9 @@ module Raven
100
100
  # Deprecated accessor
101
101
  attr_accessor :catch_debugged_exceptions
102
102
 
103
+ # Turns on ActiveSupport breadcrumbs integration
104
+ attr_accessor :rails_activesupport_breadcrumbs
105
+
103
106
  # Provide a configurable callback to determine event capture
104
107
  attr_accessor :should_capture
105
108
 
@@ -109,6 +112,9 @@ module Raven
109
112
  # Sanitize values that look like credit card numbers
110
113
  attr_accessor :sanitize_credit_cards
111
114
 
115
+ # Logger 'progname's to exclude from breadcrumbs
116
+ attr_accessor :exclude_loggers
117
+
112
118
  IGNORE_DEFAULT = [
113
119
  'AbstractController::ActionNotFound',
114
120
  'ActionController::InvalidAuthenticityToken',
@@ -137,16 +143,18 @@ module Raven
137
143
  self.processors = DEFAULT_PROCESSORS.dup
138
144
  self.ssl_verification = true
139
145
  self.encoding = 'gzip'
140
- self.timeout = 1
146
+ self.timeout = 2
141
147
  self.open_timeout = 1
142
148
  self.proxy = nil
143
149
  self.tags = {}
144
150
  self.async = false
145
151
  self.rails_report_rescued_exceptions = true
152
+ self.rails_activesupport_breadcrumbs = false
146
153
  self.transport_failure_callback = false
147
154
  self.sanitize_fields = []
148
155
  self.sanitize_credit_cards = true
149
156
  self.environments = []
157
+ self.exclude_loggers = []
150
158
 
151
159
  self.release = detect_release
152
160
 
@@ -31,6 +31,7 @@ module Raven
31
31
  def initialize(init = {})
32
32
  @configuration = Raven.configuration
33
33
  @interfaces = {}
34
+ @breadcrumbs = Raven.breadcrumbs
34
35
  @context = Raven.context
35
36
  @id = generate_event_id
36
37
  @project = nil
@@ -224,6 +225,7 @@ module Raven
224
225
  data[:extra] = @extra if @extra
225
226
  data[:tags] = @tags if @tags
226
227
  data[:user] = @user if @user
228
+ data[:breadcrumbs] = @breadcrumbs.to_hash unless @breadcrumbs.empty?
227
229
  data[:checksum] = @checksum if @checksum
228
230
  @interfaces.each_pair do |name, int_data|
229
231
  data[name.to_sym] = int_data.to_hash
@@ -0,0 +1,223 @@
1
+ require 'raven/base'
2
+ require 'English'
3
+
4
+ module Raven
5
+ # A copy of Raven's base module class methods, minus some of the integration
6
+ # and global hooks since it's meant to be used explicitly. Useful for
7
+ # sending errors to multiple sentry projects in a large application.
8
+ #
9
+ # @example
10
+ # class Foo
11
+ # def initialize
12
+ # @other_raven = Raven::Instance.new
13
+ # @other_raven.configure do |config|
14
+ # config.server = 'http://...'
15
+ # end
16
+ # end
17
+ #
18
+ # def foo
19
+ # # ...
20
+ # rescue => e
21
+ # @other_raven.capture_exception(e)
22
+ # end
23
+ # end
24
+ class Instance
25
+ # The client object is responsible for delivering formatted data to the
26
+ # Sentry server. Must respond to #send. See Raven::Client.
27
+ attr_writer :client
28
+
29
+ # A Raven configuration object. Must act like a hash and return sensible
30
+ # values for all Raven configuration options. See Raven::Configuration.
31
+ attr_writer :configuration
32
+
33
+ def initialize(context = nil)
34
+ @context = @explicit_context = context
35
+ end
36
+
37
+ def context
38
+ if @explicit_context
39
+ @context ||= Context.new
40
+ else
41
+ Context.current
42
+ end
43
+ end
44
+
45
+ def logger
46
+ @logger ||= Logger.new
47
+ end
48
+
49
+ # The configuration object.
50
+ # @see Raven.configure
51
+ def configuration
52
+ @configuration ||= Configuration.new
53
+ end
54
+
55
+ # The client object is responsible for delivering formatted data to the
56
+ # Sentry server.
57
+ def client
58
+ @client ||= Client.new(configuration)
59
+ end
60
+
61
+ # Tell the log that the client is good to go
62
+ def report_status
63
+ return if client.configuration.silence_ready
64
+ if client.configuration.send_in_current_environment?
65
+ logger.info "Raven #{VERSION} ready to catch errors"
66
+ else
67
+ logger.info "Raven #{VERSION} configured not to send errors."
68
+ end
69
+ end
70
+
71
+ # Call this method to modify defaults in your initializers.
72
+ #
73
+ # @example
74
+ # Raven.configure do |config|
75
+ # config.server = 'http://...'
76
+ # end
77
+ def configure
78
+ yield(configuration) if block_given?
79
+
80
+ self.client = Client.new(configuration)
81
+ report_status
82
+ client
83
+ end
84
+
85
+ # Send an event to the configured Sentry server
86
+ #
87
+ # @example
88
+ # evt = Raven::Event.new(:message => "An error")
89
+ # Raven.send_event(evt)
90
+ def send_event(event)
91
+ client.send_event(event)
92
+ end
93
+
94
+ # Capture and process any exceptions from the given block.
95
+ #
96
+ # @example
97
+ # Raven.capture do
98
+ # MyApp.run
99
+ # end
100
+ def capture(options = {})
101
+ if block_given?
102
+ begin
103
+ yield
104
+ rescue Error
105
+ raise # Don't capture Raven errors
106
+ rescue Exception => e
107
+ capture_type(e, options)
108
+ raise
109
+ end
110
+ else
111
+ install_at_exit_hook(options)
112
+ end
113
+ end
114
+
115
+ def capture_type(obj, options = {})
116
+ return false unless should_capture?(obj)
117
+ message_or_exc = obj.is_a?(String) ? "message" : "exception"
118
+ if (evt = Event.send("from_" + message_or_exc, obj, options))
119
+ yield evt if block_given?
120
+ if configuration.async?
121
+ configuration.async.call(evt)
122
+ else
123
+ send_event(evt)
124
+ end
125
+ Thread.current["sentry_#{object_id}_last_event_id".to_sym] = evt.id
126
+ evt
127
+ end
128
+ end
129
+
130
+ def last_event_id
131
+ Thread.current["sentry_#{object_id}_last_event_id".to_sym]
132
+ end
133
+
134
+ def should_capture?(message_or_exc)
135
+ if configuration.should_capture
136
+ configuration.should_capture.call(*[message_or_exc])
137
+ else
138
+ true
139
+ end
140
+ end
141
+
142
+ # Provides extra context to the exception prior to it being handled by
143
+ # Raven. An exception can have multiple annotations, which are merged
144
+ # together.
145
+ #
146
+ # The options (annotation) is treated the same as the ``options``
147
+ # parameter to ``capture_exception`` or ``Event.from_exception``, and
148
+ # can contain the same ``:user``, ``:tags``, etc. options as these
149
+ # methods.
150
+ #
151
+ # These will be merged with the ``options`` parameter to
152
+ # ``Event.from_exception`` at the top of execution.
153
+ #
154
+ # @example
155
+ # begin
156
+ # raise "Hello"
157
+ # rescue => exc
158
+ # Raven.annotate_exception(exc, :user => { 'id' => 1,
159
+ # 'email' => 'foo@example.com' })
160
+ # end
161
+ def annotate_exception(exc, options = {})
162
+ notes = (exc.instance_variable_defined?(:@__raven_context) && exc.instance_variable_get(:@__raven_context)) || {}
163
+ notes.merge!(options)
164
+ exc.instance_variable_set(:@__raven_context, notes)
165
+ exc
166
+ end
167
+
168
+ # Bind user context. Merges with existing context (if any).
169
+ #
170
+ # It is recommending that you send at least the ``id`` and ``email``
171
+ # values. All other values are arbitrary.
172
+ #
173
+ # @example
174
+ # Raven.user_context('id' => 1, 'email' => 'foo@example.com')
175
+ def user_context(options = nil)
176
+ context.user = options || {}
177
+ end
178
+
179
+ # Bind tags context. Merges with existing context (if any).
180
+ #
181
+ # Tags are key / value pairs which generally represent things like
182
+ # application version, environment, role, and server names.
183
+ #
184
+ # @example
185
+ # Raven.tags_context('my_custom_tag' => 'tag_value')
186
+ def tags_context(options = nil)
187
+ context.tags.merge!(options || {})
188
+ end
189
+
190
+ # Bind extra context. Merges with existing context (if any).
191
+ #
192
+ # Extra context shows up as Additional Data within Sentry, and is
193
+ # completely arbitrary.
194
+ #
195
+ # @example
196
+ # Raven.extra_context('my_custom_data' => 'value')
197
+ def extra_context(options = nil)
198
+ context.extra.merge!(options || {})
199
+ end
200
+
201
+ def rack_context(env)
202
+ env = nil if env.empty?
203
+
204
+ context.rack_env = env
205
+ end
206
+
207
+ def breadcrumbs
208
+ BreadcrumbBuffer.current
209
+ end
210
+
211
+ private
212
+
213
+ def install_at_exit_hook(options)
214
+ at_exit do
215
+ exception = $ERROR_INFO
216
+ if exception
217
+ logger.debug "Caught a post-mortem exception: #{exception.inspect}"
218
+ capture_type(exception, options)
219
+ end
220
+ end
221
+ end
222
+ end
223
+ end
@@ -43,6 +43,7 @@ module Raven
43
43
  def call(env)
44
44
  # clear context at the beginning of the request to ensure a clean slate
45
45
  Context.clear!
46
+ BreadcrumbBuffer.clear!
46
47
 
47
48
  # store the current environment in our local context for arbitrary
48
49
  # callers
@@ -13,26 +13,37 @@ module Raven
13
13
  ActiveSupport.on_load :action_controller do
14
14
  include Raven::Rails::ControllerMethods
15
15
  if ::Rails::VERSION::STRING >= "4.0.0"
16
- Raven.rails_safely_prepend("StreamingReporter", :to => ActionController::Live)
16
+ Raven.safely_prepend(
17
+ "StreamingReporter",
18
+ :from => Raven::Rails::Overrides,
19
+ :to => ActionController::Live
20
+ )
17
21
  end
18
22
  end
19
23
  end
20
24
 
21
25
  initializer 'raven.action_view' do
22
26
  ActiveSupport.on_load :action_view do
23
- Raven.rails_safely_prepend("StreamingReporter", :to => ActionView::StreamingTemplateRenderer::Body)
27
+ Raven.safely_prepend(
28
+ "StreamingReporter",
29
+ :from => Raven::Rails::Overrides,
30
+ :to => ActionView::StreamingTemplateRenderer::Body
31
+ )
24
32
  end
25
33
  end
26
34
 
27
- config.before_initialize do
35
+ config.after_initialize do
28
36
  Raven.configure do |config|
29
37
  config.logger ||= ::Rails.logger
30
38
  config.project_root ||= ::Rails.root
31
- config.release = config.detect_release # if project_root has changed, need to re-check
39
+ config.release ||= config.detect_release # if project_root has changed, need to re-check
40
+ end
41
+
42
+ if Raven.configuration.rails_activesupport_breadcrumbs
43
+ require 'raven/breadcrumbs/activesupport'
44
+ Raven::ActiveSupportBreadcrumbs.inject
32
45
  end
33
- end
34
46
 
35
- config.after_initialize do
36
47
  if Raven.configuration.rails_report_rescued_exceptions
37
48
  require 'raven/integrations/rails/overrides/debug_exceptions_catcher'
38
49
  if defined?(::ActionDispatch::DebugExceptions)
@@ -40,7 +51,12 @@ module Raven
40
51
  elsif defined?(::ActionDispatch::ShowExceptions)
41
52
  exceptions_class = ::ActionDispatch::ShowExceptions
42
53
  end
43
- Raven.rails_safely_prepend("DebugExceptionsCatcher", :to => exceptions_class)
54
+
55
+ Raven.safely_prepend(
56
+ "DebugExceptionsCatcher",
57
+ :from => Raven::Rails::Overrides,
58
+ :to => exceptions_class
59
+ )
44
60
  end
45
61
  end
46
62
 
@@ -1,8 +1,18 @@
1
1
  # frozen_string_literal: true
2
+ require 'logger'
3
+
2
4
  module Raven
3
5
  class Logger
4
6
  LOG_PREFIX = "** [Raven] ".freeze
5
7
 
8
+ LEVELS = {
9
+ :debug => ::Logger::DEBUG,
10
+ :info => ::Logger::INFO,
11
+ :warn => ::Logger::WARN,
12
+ :error => ::Logger::ERROR,
13
+ :fatal => ::Logger::FATAL
14
+ }.freeze
15
+
6
16
  [
7
17
  :fatal,
8
18
  :error,
@@ -16,7 +26,7 @@ module Raven
16
26
  logger = Raven.configuration[:logger]
17
27
  logger = ::Logger.new(STDOUT) if logger.nil?
18
28
 
19
- logger.send(level, "#{LOG_PREFIX}#{msg}") if logger
29
+ logger.add(LEVELS[level], "#{LOG_PREFIX}#{msg}", "sentry") if logger
20
30
  end
21
31
  end
22
32
  end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  require 'json'
3
+
3
4
  module Raven
4
5
  class Processor::SanitizeData < Processor
5
6
  STRING_MASK = '********'.freeze
@@ -72,8 +73,8 @@ module Raven
72
73
 
73
74
  def parse_json_or_nil(string)
74
75
  begin
75
- OkJson.decode(string)
76
- rescue Raven::OkJson::Error, NoMethodError
76
+ JSON.parse(string)
77
+ rescue JSON::ParserError, NoMethodError
77
78
  nil
78
79
  end
79
80
  end
@@ -18,13 +18,11 @@ module Raven
18
18
  project_id = configuration[:project_id]
19
19
  path = configuration[:path] + "/"
20
20
 
21
- response = conn.post "#{path}api/#{project_id}/store/" do |req|
21
+ conn.post "#{path}api/#{project_id}/store/" do |req|
22
22
  req.headers['Content-Type'] = options[:content_type]
23
23
  req.headers['X-Sentry-Auth'] = auth_header
24
24
  req.body = data
25
25
  end
26
- Raven.logger.warn "Error from Sentry server (#{response.status}): #{response.body}" unless response.status == 200
27
- response
28
26
  end
29
27
 
30
28
  private
@@ -42,6 +40,7 @@ module Raven
42
40
  :url => configuration[:server],
43
41
  :ssl => ssl_configuration
44
42
  ) do |builder|
43
+ builder.response :raise_error
45
44
  builder.adapter(*adapter)
46
45
  end
47
46
 
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
  module Raven
3
- VERSION = "1.1.0".freeze
3
+ # Freezing this constant breaks in 1.9.x
4
+ VERSION = "1.2.0" # rubocop:disable Style/MutableConstant
4
5
  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: 1.1.0
4
+ version: 1.2.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: 2016-06-07 00:00:00.000000000 Z
11
+ date: 2016-07-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -17,6 +17,9 @@ dependencies:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: 0.7.6
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: 0.10.x
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -24,6 +27,9 @@ dependencies:
24
27
  - - ">="
25
28
  - !ruby/object:Gem::Version
26
29
  version: 0.7.6
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: 0.10.x
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: rake
29
35
  requirement: !ruby/object:Gem::Requirement
@@ -42,16 +48,16 @@ dependencies:
42
48
  name: rubocop
43
49
  requirement: !ruby/object:Gem::Requirement
44
50
  requirements:
45
- - - ">="
51
+ - - "~>"
46
52
  - !ruby/object:Gem::Version
47
- version: '0'
53
+ version: 0.41.1
48
54
  type: :development
49
55
  prerelease: false
50
56
  version_requirements: !ruby/object:Gem::Requirement
51
57
  requirements:
52
- - - ">="
58
+ - - "~>"
53
59
  - !ruby/object:Gem::Version
54
- version: '0'
60
+ version: 0.41.1
55
61
  - !ruby/object:Gem::Dependency
56
62
  name: rspec
57
63
  requirement: !ruby/object:Gem::Requirement
@@ -80,34 +86,6 @@ dependencies:
80
86
  - - ">="
81
87
  - !ruby/object:Gem::Version
82
88
  version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: mime-types
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
- - !ruby/object:Gem::Dependency
98
- name: rest-client
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: '0'
111
89
  - !ruby/object:Gem::Dependency
112
90
  name: timecop
113
91
  requirement: !ruby/object:Gem::Requirement
@@ -149,12 +127,16 @@ files:
149
127
  - lib/raven.rb
150
128
  - lib/raven/backtrace.rb
151
129
  - lib/raven/base.rb
130
+ - lib/raven/breadcrumbs.rb
131
+ - lib/raven/breadcrumbs/activesupport.rb
132
+ - lib/raven/breadcrumbs/logger.rb
152
133
  - lib/raven/cli.rb
153
134
  - lib/raven/client.rb
154
135
  - lib/raven/configuration.rb
155
136
  - lib/raven/context.rb
156
137
  - lib/raven/error.rb
157
138
  - lib/raven/event.rb
139
+ - lib/raven/instance.rb
158
140
  - lib/raven/integrations/delayed_job.rb
159
141
  - lib/raven/integrations/rack.rb
160
142
  - lib/raven/integrations/rails.rb
@@ -174,7 +156,6 @@ files:
174
156
  - lib/raven/interfaces/stack_trace.rb
175
157
  - lib/raven/linecache.rb
176
158
  - lib/raven/logger.rb
177
- - lib/raven/okjson.rb
178
159
  - lib/raven/processor.rb
179
160
  - lib/raven/processor/cookies.rb
180
161
  - lib/raven/processor/post_data.rb
@@ -214,4 +195,3 @@ signing_key:
214
195
  specification_version: 4
215
196
  summary: A gem that provides a client interface for the Sentry error logger
216
197
  test_files: []
217
- has_rdoc: true