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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 35bfb0236a3a8236cfe5c2ad37592f973c9612be
4
- data.tar.gz: 79ee56bfc0b8243f4dd50111aa253498950548a5
3
+ metadata.gz: bd0a24e20bb50a520df079f36059cb0adb5d7673
4
+ data.tar.gz: c89f6a2a4146c6ac291e527e7ec362f12a2e82eb
5
5
  SHA512:
6
- metadata.gz: d3caa9d91239b8f4bb0355f5a0bf6ea5af48e616e91f43a7abdc62f91f65638f0fca6d73dfeb63be6ba610b40a4c2defa23ca40e2256c1a8f5ad5dfd1ea5d137
7
- data.tar.gz: 1cbeccc7169fba6eef992a6eb11d5c6bd8ec6aef89a780c200cb10f011a4bf970109aac68c870975f44a80849e428316382969d92ea70b300278ebe3485cf310
6
+ metadata.gz: ddb34f4ff56c51af45e4c369f61f9a2a01e24107bc97eca694abbb1a501902cac5254fc912e1eb9e794b8d6c21beff0a49570bb1b114d748676b39cfb7862735
7
+ data.tar.gz: b35f1609019436dd7f42ef6ed976f53bde10a15eab61b5c6a1bc362b99fa571e459913cafb02da7e1281ff366c70ba1a6a06ff8abf326fd455d1824f4a7cfe00
@@ -1,5 +1,6 @@
1
1
  require 'raven/version'
2
2
  require 'raven/backtrace'
3
+ require 'raven/breadcrumbs'
3
4
  require 'raven/processor'
4
5
  require 'raven/processor/sanitizedata'
5
6
  require 'raven/processor/removecircularreferences'
@@ -17,187 +18,33 @@ require 'raven/interfaces/single_exception'
17
18
  require 'raven/interfaces/stack_trace'
18
19
  require 'raven/interfaces/http'
19
20
  require 'raven/utils/deep_merge'
21
+ require 'raven/instance'
22
+
23
+ require 'forwardable'
20
24
 
21
25
  module Raven
22
26
  AVAILABLE_INTEGRATIONS = %w[delayed_job railties sidekiq rack rake].freeze
23
27
 
24
28
  class << self
25
- # The client object is responsible for delivering formatted data to the Sentry server.
26
- # 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 context
34
- Context.current
35
- end
36
-
37
- def logger
38
- @logger ||= Logger.new
39
- end
40
-
41
- # The configuration object.
42
- # @see Raven.configure
43
- def configuration
44
- @configuration ||= Configuration.new
45
- end
46
-
47
- # The client object is responsible for delivering formatted data to the Sentry server.
48
- def client
49
- @client ||= Client.new(configuration)
50
- end
51
-
52
- # Tell the log that the client is good to go
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
60
- end
61
- alias_method :report_ready, :report_status
62
-
63
- # Call this method to modify defaults in your initializers.
64
- #
65
- # @example
66
- # Raven.configure do |config|
67
- # config.server = 'http://...'
68
- # end
69
- def configure
70
- yield(configuration) if block_given?
71
-
72
- self.client = Client.new(configuration)
73
- report_status
74
- self.client
75
- end
76
-
77
- # Send an event to the configured Sentry server
78
- #
79
- # @example
80
- # evt = Raven::Event.new(:message => "An error")
81
- # Raven.send_event(evt)
82
- def send_event(event)
83
- client.send_event(event)
84
- end
85
-
86
- # Capture and process any exceptions from the given block, or globally if
87
- # no block is given
88
- #
89
- # @example
90
- # Raven.capture do
91
- # MyApp.run
92
- # end
93
- def capture(options = {})
94
- if 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
102
- end
103
- else
104
- install_at_exit_hook(options)
105
- end
106
- end
107
-
108
- def capture_type(obj, options = {})
109
- return false unless should_capture?(obj)
110
- message_or_exc = obj.is_a?(String) ? "message" : "exception"
111
- if (evt = Event.send("from_" + message_or_exc, obj, options))
112
- yield evt if block_given?
113
- if configuration.async?
114
- configuration.async.call(evt)
115
- else
116
- send_event(evt)
117
- end
118
- Thread.current[:sentry_last_event_id] = evt.id
119
- evt
120
- end
121
- end
122
- alias_method :capture_message, :capture_type
123
- alias_method :capture_exception, :capture_type
124
-
125
- def last_event_id
126
- Thread.current[:sentry_last_event_id]
127
- end
128
-
129
- def should_capture?(message_or_exc)
130
- if configuration.should_capture
131
- configuration.should_capture.call(*[message_or_exc])
132
- else
133
- true
134
- end
135
- end
136
-
137
- # Provides extra context to the exception prior to it being handled by
138
- # Raven. An exception can have multiple annotations, which are merged
139
- # together.
140
- #
141
- # The options (annotation) is treated the same as the ``options``
142
- # parameter to ``capture_exception`` or ``Event.from_exception``, and
143
- # can contain the same ``:user``, ``:tags``, etc. options as these
144
- # methods.
145
- #
146
- # These will be merged with the ``options`` parameter to
147
- # ``Event.from_exception`` at the top of execution.
148
- #
149
- # @example
150
- # begin
151
- # raise "Hello"
152
- # rescue => exc
153
- # Raven.annotate_exception(exc, :user => { 'id' => 1,
154
- # 'email' => 'foo@example.com' })
155
- # end
156
- def annotate_exception(exc, options = {})
157
- notes = (exc.instance_variable_defined?(:@__raven_context) && exc.instance_variable_get(:@__raven_context)) || {}
158
- notes.merge!(options)
159
- exc.instance_variable_set(:@__raven_context, notes)
160
- exc
161
- end
162
-
163
- # Bind user context. Merges with existing context (if any).
164
- #
165
- # It is recommending that you send at least the ``id`` and ``email``
166
- # values. All other values are arbitrary.
167
- #
168
- # @example
169
- # Raven.user_context('id' => 1, 'email' => 'foo@example.com')
170
- def user_context(options = nil)
171
- self.context.user = options || {}
172
- end
29
+ extend Forwardable
173
30
 
174
- # Bind tags context. Merges with existing context (if any).
175
- #
176
- # Tags are key / value pairs which generally represent things like application version,
177
- # environment, role, and server names.
178
- #
179
- # @example
180
- # Raven.tags_context('my_custom_tag' => 'tag_value')
181
- def tags_context(options = nil)
182
- self.context.tags.merge!(options || {})
31
+ def instance
32
+ @instance ||= Raven::Instance.new
183
33
  end
184
34
 
185
- # Bind extra context. Merges with existing context (if any).
186
- #
187
- # Extra context shows up as Additional Data within Sentry, and is completely arbitrary.
188
- #
189
- # @example
190
- # Raven.extra_context('my_custom_data' => 'value')
191
- def extra_context(options = nil)
192
- self.context.extra.merge!(options || {})
193
- end
35
+ def_delegators :instance, :client=, :configuration=, :context, :logger, :configuration,
36
+ :client, :report_status, :configure, :send_event, :capture, :capture_type,
37
+ :last_event_id, :should_capture?, :annotate_exception, :user_context,
38
+ :tags_context, :extra_context, :rack_context, :breadcrumbs
194
39
 
195
- def rack_context(env)
196
- if env.empty?
197
- env = nil
198
- end
199
- self.context.rack_env = env
200
- end
40
+ def_delegator :instance, :report_status, :report_ready
41
+ def_delegator :instance, :capture_type, :capture_message
42
+ def_delegator :instance, :capture_type, :capture_exception
43
+ # For cross-language compatibility
44
+ def_delegator :instance, :capture_type, :captureException
45
+ def_delegator :instance, :capture_type, :captureMessage
46
+ def_delegator :instance, :annotate_exception, :annotateException
47
+ def_delegator :instance, :annotate_exception, :annotate
201
48
 
202
49
  # Injects various integrations. Default behavior: inject all available integrations
203
50
  def inject
@@ -232,29 +79,12 @@ module Raven
232
79
  self.logger.warn "Unable to load raven/integrations/#{integration}: #{error}"
233
80
  end
234
81
 
235
- def rails_safely_prepend(module_name, opts = {})
236
- return if opts[:to].nil?
82
+ def safely_prepend(module_name, opts = {})
83
+ return if opts[:to].nil? || opts[:from].nil?
237
84
  if opts[:to].respond_to?(:prepend, true)
238
- opts[:to].send(:prepend, Raven::Rails::Overrides.const_get(module_name))
85
+ opts[:to].send(:prepend, opts[:from].const_get(module_name))
239
86
  else
240
- opts[:to].send(:include, Raven::Rails::Overrides.const_get("Old" + module_name))
241
- end
242
- end
243
-
244
- # For cross-language compat
245
- alias :captureException :capture_exception
246
- alias :captureMessage :capture_message
247
- alias :annotateException :annotate_exception
248
- alias :annotate :annotate_exception
249
-
250
- private
251
-
252
- def install_at_exit_hook(options)
253
- at_exit do
254
- if $!
255
- logger.debug "Caught a post-mortem exception: #{$!.inspect}"
256
- capture_exception($!, options)
257
- end
87
+ opts[:to].send(:include, opts[:from].const_get("Old" + module_name))
258
88
  end
259
89
  end
260
90
  end
@@ -0,0 +1,74 @@
1
+ module Raven
2
+ class Breadcrumb
3
+ attr_accessor :category, :data, :message, :level, :timestamp, :type
4
+
5
+ def initialize
6
+ @category = nil
7
+ @data = {}
8
+ @level = nil
9
+ @message = nil
10
+ @timestamp = Time.now.to_i
11
+ @type = nil
12
+ end
13
+
14
+ def to_hash
15
+ {
16
+ :category => @category,
17
+ :data => @data,
18
+ :level => @level,
19
+ :message => @message,
20
+ :timestamp => @timestamp,
21
+ :type => @type
22
+ }
23
+ end
24
+ end
25
+ end
26
+
27
+ module Raven
28
+ class BreadcrumbBuffer
29
+ include Enumerable
30
+
31
+ def self.current
32
+ Thread.current[:sentry_breadcrumbs] ||= new
33
+ end
34
+
35
+ def self.clear!
36
+ Thread.current[:sentry_breadcrumbs] = nil
37
+ end
38
+
39
+ def initialize(size = 100)
40
+ @buffer = Array.new(size)
41
+ end
42
+
43
+ def record(crumb = nil)
44
+ if block_given?
45
+ crumb = Breadcrumb.new if crumb.nil?
46
+ yield(crumb)
47
+ end
48
+ @buffer.slice!(0)
49
+ @buffer << crumb
50
+ end
51
+
52
+ def members
53
+ @buffer.compact
54
+ end
55
+
56
+ def peek
57
+ members.last
58
+ end
59
+
60
+ def each(&block)
61
+ members.each(&block)
62
+ end
63
+
64
+ def empty?
65
+ !members.any?
66
+ end
67
+
68
+ def to_hash
69
+ {
70
+ :values => members.map(&:to_hash)
71
+ }
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,19 @@
1
+ module Raven
2
+ module ActiveSupportBreadcrumbs
3
+ class << self
4
+ def add(name, started, _finished, _unique_id, data)
5
+ Raven.breadcrumbs.record do |crumb|
6
+ crumb.data = data
7
+ crumb.category = name
8
+ crumb.timestamp = started.to_i
9
+ end
10
+ end
11
+
12
+ def inject
13
+ ActiveSupport::Notifications.subscribe(/.*/) do |name, started, finished, unique_id, data|
14
+ add(name, started, finished, unique_id, data)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,93 @@
1
+ require 'logger'
2
+
3
+ module Raven
4
+ module BreadcrumbLogger
5
+ LEVELS = {
6
+ ::Logger::DEBUG => 'debug',
7
+ ::Logger::INFO => 'info',
8
+ ::Logger::WARN => 'warn',
9
+ ::Logger::ERROR => 'error',
10
+ ::Logger::FATAL => 'fatal'
11
+ }.freeze
12
+
13
+ EXC_FORMAT = /^([a-zA-Z0-9]+)\:\s(.*)$/
14
+
15
+ def self.parse_exception(message)
16
+ lines = message.split(/\n\s*/)
17
+ # TODO: wat
18
+ return nil unless lines.length > 2
19
+
20
+ match = lines[0].match(EXC_FORMAT)
21
+ return nil unless match
22
+
23
+ _, type, value = match.to_a
24
+ [type, value]
25
+ end
26
+
27
+ def add(*args)
28
+ add_breadcrumb(*args)
29
+ super
30
+ end
31
+
32
+ def add_breadcrumb(severity, message = nil, progname = nil)
33
+ message = progname if message.nil? # see Ruby's Logger docs for why
34
+ return if ignored_logger?(progname)
35
+ return if message.nil? || message == ""
36
+
37
+ # some loggers will add leading/trailing space as they (incorrectly, mind you)
38
+ # think of logging as a shortcut to std{out,err}
39
+ message = message.strip
40
+
41
+ last_crumb = Raven.breadcrumbs.peek
42
+ # try to avoid dupes from logger broadcasts
43
+ if last_crumb.nil? || last_crumb.message != message
44
+ error = Raven::BreadcrumbLogger.parse_exception(message)
45
+ # TODO(dcramer): we need to filter out the "currently captured error"
46
+ if error
47
+ Raven.breadcrumbs.record do |crumb|
48
+ crumb.level = Raven::BreadcrumbLogger::LEVELS.fetch(severity, nil)
49
+ crumb.category = progname || 'error'
50
+ crumb.type = 'error'
51
+ crumb.data = {
52
+ :type => error[0],
53
+ :value => error[1]
54
+ }
55
+ end
56
+ else
57
+ Raven.breadcrumbs.record do |crumb|
58
+ crumb.level = Raven::BreadcrumbLogger::LEVELS.fetch(severity, nil)
59
+ crumb.category = progname || 'logger'
60
+ crumb.message = message
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ private
67
+
68
+ def ignored_logger?(progname)
69
+ progname == "sentry" ||
70
+ Raven.configuration.exclude_loggers.include?(progname)
71
+ end
72
+ end
73
+ module OldBreadcrumbLogger
74
+ def self.included(base)
75
+ base.class_eval do
76
+ include Raven::BreadcrumbLogger
77
+ alias_method :add_without_raven, :add
78
+ alias_method :add, :add_with_raven
79
+ end
80
+ end
81
+
82
+ def add_with_raven(*args)
83
+ add_breadcrumb(*args)
84
+ add_without_raven(*args)
85
+ end
86
+ end
87
+ end
88
+
89
+ Raven.safely_prepend(
90
+ "BreadcrumbLogger",
91
+ :from => Raven,
92
+ :to => ::Logger
93
+ )
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
- require 'zlib'
3
2
  require 'base64'
3
+ require 'json'
4
+ require 'zlib'
4
5
 
5
6
  require 'raven/version'
6
- require 'raven/okjson'
7
7
  require 'raven/transports/http'
8
8
 
9
9
  module Raven
@@ -73,7 +73,7 @@ module Raven
73
73
 
74
74
  def encode(event)
75
75
  hash = @processors.reduce(event.to_hash) { |memo, p| p.process(memo) }
76
- encoded = OkJson.encode(hash)
76
+ encoded = JSON.generate(hash)
77
77
 
78
78
  case configuration.encoding
79
79
  when 'gzip'