sentry-raven 2.0.2 → 2.1.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: e464bc91ea975824329dfd86c13edf2d9e75e9cb
4
- data.tar.gz: 31719bdb63d32973a5ea442db84138ad76b84a81
3
+ metadata.gz: ca26b5db2081fdbbdc2d2de7bbd580f1efcbd3f2
4
+ data.tar.gz: b95c0447aa43feb90d16585803a8815e218390c4
5
5
  SHA512:
6
- metadata.gz: 9f1739d86ea78f779bfeccfefe10915cc90239478b034f801c0e4cfe7c00c56751c51daaf6041e4e62ee82f45ab281087c18cf30a6f9234b67958c1181935c0e
7
- data.tar.gz: 04e10bb6c9edf0224e369ff53fc811f133fec59a5a354ac83f70a0ef48ccad6e379b22bc10926d56e0bdef4109b64bd8591a9abe5030ca5bccf8505f14453fdc
6
+ metadata.gz: 49d734c72e306caf5e6a760ee9e76e787eb865f33542929b43ee244b7596607b7f9a13b1d77f531d25de4d09a04d15ca87fab96438379a4fc621b17f8e9c0959
7
+ data.tar.gz: 9c299e76d4f1081225fd7950a09434564bc4a805bc77673efe2a501af4446297c876bc68edd88267d429d35fa1ac20f24903c0193393b7ec0e85e07f3c9b36c5
data/lib/raven/base.rb CHANGED
@@ -90,5 +90,13 @@ module Raven
90
90
  opts[:to].send(:include, opts[:from].const_get("Old" + module_name))
91
91
  end
92
92
  end
93
+
94
+ def sys_command(unix_command, win_command = nil)
95
+ unix_result = `#{unix_command} 2>&1` rescue nil # redirect stderr to stdout
96
+ return unix_result if unix_result != "" && unix_result
97
+ return if win_command.nil?
98
+ win_result = `#{win_command}` rescue nil
99
+ win_result != "" && win_result
100
+ end
93
101
  end
94
102
  end
@@ -267,15 +267,24 @@ module Raven
267
267
  end
268
268
 
269
269
  def detect_release
270
- detect_release_from_heroku ||
270
+ detect_release_from_git ||
271
271
  detect_release_from_capistrano ||
272
- detect_release_from_git
272
+ detect_release_from_heroku
273
273
  end
274
274
 
275
275
  private
276
276
 
277
277
  def detect_release_from_heroku
278
- ENV['HEROKU_SLUG_COMMIT']
278
+ sys_dyno_info = File.read("/etc/heroku/dyno").strip if File.directory?("/etc/heroku") rescue nil
279
+ return unless sys_dyno_info
280
+
281
+ # being overly cautious, because if we raise an error Raven won't start
282
+ begin
283
+ hash = JSON.parse(sys_dyno_info)
284
+ hash && hash["release"] && hash["release"]["commit"]
285
+ rescue JSON::JSONError
286
+ Raven.logger.error "Cannot parse Heroku JSON: #{sys_dyno_info}"
287
+ end
279
288
  end
280
289
 
281
290
  def detect_release_from_capistrano
data/lib/raven/context.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'rbconfig'
2
+
1
3
  module Raven
2
4
  class Context
3
5
  def self.current
@@ -8,14 +10,33 @@ module Raven
8
10
  Thread.current[:sentry_context] = nil
9
11
  end
10
12
 
11
- attr_reader :extra, :tags
12
- attr_accessor :rack_env, :user
13
+ attr_accessor :extra, :os, :rack_env, :runtime, :tags, :user
13
14
 
14
15
  def initialize
15
- @extra = {}
16
- @tags = {}
17
- @user = {}
18
- @rack_env = nil
16
+ self.extra = {}
17
+ self.os = self.class.os_context
18
+ self.rack_env = nil
19
+ self.runtime = self.class.runtime_context
20
+ self.tags = {}
21
+ self.user = {}
22
+ end
23
+
24
+ class << self
25
+ def os_context
26
+ @os_context ||= {
27
+ "name" => Raven.sys_command("uname -s") || RbConfig::CONFIG["host_os"],
28
+ "version" => Raven.sys_command("uname -v"),
29
+ "build" => Raven.sys_command("uname -r"),
30
+ "kernel_version" => Raven.sys_command("uname -a", "ver")
31
+ }
32
+ end
33
+
34
+ def runtime_context
35
+ @runtime_context ||= {
36
+ "name" => RbConfig::CONFIG["ruby_install_name"],
37
+ "version" => Raven.sys_command("ruby -v")
38
+ }
39
+ end
19
40
  end
20
41
  end
21
42
  end
data/lib/raven/event.rb CHANGED
@@ -21,11 +21,12 @@ module Raven
21
21
  BACKTRACE_RE = /^(.+?):(\d+)(?::in `(.+?)')?$/
22
22
 
23
23
  PLATFORM = "ruby".freeze
24
+ SDK = { "name" => "sentry-raven", "version" => Raven::VERSION }.freeze
24
25
 
25
- attr_reader :id
26
- attr_accessor :project, :message, :timestamp, :time_spent, :level, :logger,
27
- :culprit, :server_name, :release, :modules, :extra, :tags, :context, :configuration,
28
- :checksum, :fingerprint, :environment
26
+ attr_accessor :id, :timestamp, :time_spent, :level, :logger,
27
+ :culprit, :server_name, :release, :modules, :extra, :tags,
28
+ :context, :configuration, :checksum, :fingerprint, :environment,
29
+ :os, :runtime, :breadcrumbs, :user, :backtrace
29
30
 
30
31
  def initialize(init = {})
31
32
  @configuration = Raven.configuration
@@ -33,8 +34,6 @@ module Raven
33
34
  @breadcrumbs = Raven.breadcrumbs
34
35
  @context = Raven.context
35
36
  @id = SecureRandom.uuid.delete("-")
36
- @project = nil
37
- @message = nil
38
37
  @timestamp = Time.now.utc
39
38
  @time_spent = nil
40
39
  @level = :error
@@ -43,9 +42,11 @@ module Raven
43
42
  @server_name = @configuration.server_name
44
43
  @release = @configuration.release
45
44
  @modules = list_gem_specs if @configuration.send_modules
46
- @user = {}
47
- @extra = {}
48
- @tags = {}
45
+ @user = {} # TODO: contexts
46
+ @extra = {} # TODO: contexts
47
+ @os = {} # TODO: contexts
48
+ @runtime = {} # TODO: contexts
49
+ @tags = {} # TODO: contexts
49
50
  @checksum = nil
50
51
  @fingerprint = nil
51
52
  @environment = @configuration.current_environment
@@ -58,15 +59,17 @@ module Raven
58
59
  end
59
60
  end
60
61
 
61
- if @context.rack_env
62
+ if @context.rack_env # TODO: contexts
62
63
  @context.user[:ip_address] = calculate_real_ip_from_rack
63
64
  end
64
65
 
65
- init.each_pair { |key, val| instance_variable_set('@' + key.to_s, val) }
66
+ init.each_pair { |key, val| public_send(key.to_s + "=", val) }
66
67
 
67
- @user = @context.user.merge(@user)
68
- @extra = @context.extra.merge(@extra)
69
- @tags = @configuration.tags.merge(@context.tags).merge(@tags)
68
+ @user = @context.user.merge(@user) # TODO: contexts
69
+ @extra = @context.extra.merge(@extra) # TODO: contexts
70
+ @tags = @configuration.tags.merge(@context.tags).merge(@tags) # TODO: contexts
71
+ @os = @context.os # TODO: contexts
72
+ @runtime = @context.runtime # TODO: contexts
70
73
 
71
74
  # Some type coercion
72
75
  @timestamp = @timestamp.strftime('%Y-%m-%dT%H:%M:%S') if @timestamp.is_a?(Time)
@@ -74,6 +77,18 @@ module Raven
74
77
  @level = LOG_LEVELS[@level.to_s.downcase] if @level.is_a?(String) || @level.is_a?(Symbol)
75
78
  end
76
79
 
80
+ def message
81
+ @interfaces[:logentry] && @interfaces[:logentry].unformatted_message
82
+ end
83
+
84
+ def message=(args)
85
+ message, params = *args
86
+ interface(:message) do |int|
87
+ int.message = message
88
+ int.params = params
89
+ end
90
+ end
91
+
77
92
  class << self
78
93
  def from_exception(exc, options = {}, &block)
79
94
  exception_context = get_exception_context(exc) || {}
@@ -107,11 +122,8 @@ module Raven
107
122
 
108
123
  new(options) do |evt|
109
124
  evt.configuration = configuration
110
- evt.message = message
111
125
  evt.level = options[:level] || :error
112
- evt.interface :message do |int|
113
- int.message = message
114
- end
126
+ evt.message = message, options[:message_params] || []
115
127
  if options[:backtrace]
116
128
  evt.interface(:stacktrace) do |int|
117
129
  stacktrace_interface_from(int, evt, options[:backtrace])
@@ -196,10 +208,10 @@ module Raven
196
208
  end
197
209
 
198
210
  def interface(name, value = nil, &block)
199
- int = Raven.find_interface(name)
211
+ int = Interface.registered[name]
200
212
  raise(Error, "Unknown interface: #{name}") unless int
201
- @interfaces[int.name] = int.new(value, &block) if value || block
202
- @interfaces[int.name]
213
+ @interfaces[int.sentry_alias] = int.new(value, &block) if value || block
214
+ @interfaces[int.sentry_alias]
203
215
  end
204
216
 
205
217
  def [](key)
@@ -213,13 +225,17 @@ module Raven
213
225
  def to_hash
214
226
  data = {
215
227
  :event_id => @id,
216
- :message => @message,
217
228
  :timestamp => @timestamp,
218
229
  :time_spent => @time_spent,
219
230
  :level => @level,
220
- :project => @project,
221
- :platform => PLATFORM
231
+ :platform => PLATFORM,
232
+ :sdk => SDK,
233
+ :contexts => {
234
+ :os => @os,
235
+ :runtime => @runtime
236
+ }
222
237
  }
238
+
223
239
  data[:logger] = @logger if @logger
224
240
  data[:culprit] = @culprit if @culprit
225
241
  data[:server_name] = @server_name if @server_name
@@ -232,9 +248,11 @@ module Raven
232
248
  data[:user] = @user if @user
233
249
  data[:breadcrumbs] = @breadcrumbs.to_hash unless @breadcrumbs.empty?
234
250
  data[:checksum] = @checksum if @checksum
251
+
235
252
  @interfaces.each_pair do |name, int_data|
236
253
  data[name.to_sym] = int_data.to_hash
237
254
  end
255
+ data[:message] = message
238
256
  data
239
257
  end
240
258
 
@@ -3,56 +3,62 @@ require 'sidekiq'
3
3
 
4
4
  module Raven
5
5
  class Sidekiq
6
- def call(_worker, msg, _queue)
7
- started_at = Time.now
8
- yield
9
- rescue Exception => ex
10
- Raven.capture_exception(ex, :extra => { :sidekiq => msg },
11
- :time_spent => Time.now - started_at)
12
- raise
6
+ ACTIVEJOB_RESERVED_PREFIX = "_aj_".freeze
7
+
8
+ def call(ex, context)
9
+ context = filter_context(context)
10
+ Raven.capture_exception(
11
+ ex,
12
+ :message => ex.message,
13
+ :extra => { :sidekiq => context },
14
+ :culprit => culprit_from_context(context)
15
+ )
13
16
  ensure
14
17
  Context.clear!
15
18
  BreadcrumbBuffer.clear!
16
19
  end
17
- end
18
- end
19
20
 
20
- if Sidekiq::VERSION < '3'
21
- # old behavior
22
- ::Sidekiq.configure_server do |config|
23
- config.server_middleware do |chain|
24
- chain.add ::Raven::Sidekiq
21
+ private
22
+
23
+ # Once an ActiveJob is queued, ActiveRecord references get serialized into
24
+ # some internal reserved keys, such as _aj_globalid.
25
+ #
26
+ # The problem is, if this job in turn gets queued back into ActiveJob with
27
+ # these magic reserved keys, ActiveJob will throw up and error. We want to
28
+ # capture these and mutate the keys so we can sanely report it.
29
+ def filter_context(context)
30
+ case context
31
+ when Array
32
+ context.map { |arg| filter_context(arg) }
33
+ when Hash
34
+ Hash[context.map { |key, value| filter_context_hash(key, value) }]
35
+ else
36
+ context
37
+ end
25
38
  end
26
- end
27
- else
28
- Sidekiq.configure_server do |config|
29
- config.error_handlers << proc do |ex, context|
30
- Raven.capture_exception(ex, :extra => {
31
- :sidekiq => filter_context(context)
32
- })
39
+
40
+ def filter_context_hash(key, value)
41
+ (key = key[3..-1]) if key [0..3] == ACTIVEJOB_RESERVED_PREFIX
42
+ [key, filter_context(value)]
33
43
  end
34
- end
35
- end
36
44
 
37
- def filter_context(context)
38
- case context
39
- when Array
40
- context.map { |arg| filter_context(arg) }
41
- when Hash
42
- Hash[context.map { |key, value| filter_context_hash(key, value) }]
43
- else
44
- context
45
+ # this will change in the future:
46
+ # https://github.com/mperham/sidekiq/pull/3161
47
+ def culprit_from_context(context)
48
+ classname = (context["class"] || (context["job"] && context["job"]["class"]))
49
+ if classname
50
+ "Sidekiq/#{classname}"
51
+ elsif context["event"]
52
+ "Sidekiq/#{context['event']}"
53
+ else
54
+ "Sidekiq"
55
+ end
56
+ end
45
57
  end
46
58
  end
47
59
 
48
- def filter_context_hash(key, value)
49
- # Strip any `_aj` prefixes from keys.
50
- # These keys come from an internal serialized object from ActiveJob.
51
- # Internally, there are a subset of keys that ActiveJob references, but
52
- # these are declared as private, and I don't think it's wise
53
- # to keep chasing what this list is. But they all use a common prefix, so
54
- # we want to strip this becuase ActiveJob will complain.
55
- # e.g.: _aj_globalid -> _globalid
56
- (key = key[3..-1]) if key [0..3] == "_aj_"
57
- [key, filter_context(value)]
60
+ if Sidekiq::VERSION > '3'
61
+ Sidekiq.configure_server do |config|
62
+ config.error_handlers << Raven::Sidekiq.new
63
+ end
58
64
  end
@@ -1,6 +1,4 @@
1
1
  module Raven
2
- INTERFACES = {} # rubocop:disable Style/MutableConstant
3
-
4
2
  class Interface
5
3
  def initialize(attributes = nil)
6
4
  attributes.each do |attr, value|
@@ -10,23 +8,18 @@ module Raven
10
8
  yield self if block_given?
11
9
  end
12
10
 
13
- def self.name(value = nil)
14
- @interface_name ||= value
11
+ def self.inherited(klass)
12
+ name = klass.name.split("::").last.downcase.gsub("interface", "")
13
+ registered[name.to_sym] = klass
14
+ super
15
15
  end
16
16
 
17
- def to_hash
18
- Hash[instance_variables.map { |name| [name[1..-1].to_sym, instance_variable_get(name)] }]
17
+ def self.registered
18
+ @@registered ||= {} # rubocop:disable Style/ClassVars
19
19
  end
20
- end
21
20
 
22
- def self.register_interface(mapping)
23
- mapping.each_pair do |key, klass|
24
- INTERFACES[key.to_s] = klass
25
- INTERFACES[klass.name] = klass
21
+ def to_hash
22
+ Hash[instance_variables.map { |name| [name[1..-1].to_sym, instance_variable_get(name)] }]
26
23
  end
27
24
  end
28
-
29
- def self.find_interface(name)
30
- INTERFACES[name.to_s]
31
- end
32
25
  end
@@ -1,16 +1,17 @@
1
- require 'raven/interfaces'
1
+ require 'raven/interface'
2
2
 
3
3
  module Raven
4
4
  class ExceptionInterface < Interface
5
- name 'exception'
6
5
  attr_accessor :values
7
6
 
7
+ def self.sentry_alias
8
+ :exception
9
+ end
10
+
8
11
  def to_hash(*args)
9
12
  data = super(*args)
10
13
  data[:values] = data[:values].map(&:to_hash) if data[:values]
11
14
  data
12
15
  end
13
16
  end
14
-
15
- register_interface :exception => ExceptionInterface
16
17
  end
@@ -1,15 +1,8 @@
1
- require 'raven/interfaces'
1
+ require 'raven/interface'
2
2
 
3
3
  module Raven
4
4
  class HttpInterface < Interface
5
- name 'request'
6
- attr_accessor :url
7
- attr_accessor :method
8
- attr_accessor :data
9
- attr_accessor :query_string
10
- attr_accessor :cookies
11
- attr_accessor :headers
12
- attr_accessor :env
5
+ attr_accessor :url, :method, :data, :query_string, :cookies, :headers, :env
13
6
 
14
7
  def initialize(*arguments)
15
8
  self.headers = {}
@@ -17,7 +10,9 @@ module Raven
17
10
  self.cookies = nil
18
11
  super(*arguments)
19
12
  end
20
- end
21
13
 
22
- register_interface :http => HttpInterface
14
+ def self.sentry_alias
15
+ :request
16
+ end
17
+ end
23
18
  end
@@ -1,16 +1,20 @@
1
- require 'raven/interfaces'
1
+ require 'raven/interface'
2
2
 
3
3
  module Raven
4
4
  class MessageInterface < Interface
5
- name 'sentry.interfaces.Message'
6
- attr_accessor :message
7
- attr_accessor :params
5
+ attr_accessor :message, :params
8
6
 
9
7
  def initialize(*arguments)
10
8
  self.params = []
11
9
  super(*arguments)
12
10
  end
13
- end
14
11
 
15
- register_interface :message => MessageInterface
12
+ def unformatted_message
13
+ message % params
14
+ end
15
+
16
+ def self.sentry_alias
17
+ :logentry
18
+ end
19
+ end
16
20
  end
@@ -1,4 +1,4 @@
1
- require 'raven/interfaces'
1
+ require 'raven/interface'
2
2
 
3
3
  module Raven
4
4
  class SingleExceptionInterface < Interface
@@ -1,8 +1,7 @@
1
- require 'raven/interfaces'
1
+ require 'raven/interface'
2
2
 
3
3
  module Raven
4
4
  class StacktraceInterface < Interface
5
- name 'stacktrace'
6
5
  attr_accessor :frames
7
6
 
8
7
  def initialize(*arguments)
@@ -10,6 +9,10 @@ module Raven
10
9
  super(*arguments)
11
10
  end
12
11
 
12
+ def self.sentry_alias
13
+ :stacktrace
14
+ end
15
+
13
16
  def to_hash(*args)
14
17
  data = super(*args)
15
18
  data[:frames] = data[:frames].map(&:to_hash)
@@ -71,6 +74,4 @@ module Raven
71
74
  end
72
75
  end
73
76
  end
74
-
75
- register_interface :stack_trace => StacktraceInterface
76
77
  end
@@ -23,6 +23,8 @@ module Raven
23
23
  req.headers['X-Sentry-Auth'] = auth_header
24
24
  req.body = data
25
25
  end
26
+ rescue Faraday::ClientError => ex
27
+ raise Raven::Error, ex.message
26
28
  end
27
29
 
28
30
  private
data/lib/raven/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
  module Raven
3
3
  # Freezing this constant breaks in 1.9.x
4
- VERSION = "2.0.2" # rubocop:disable Style/MutableConstant
4
+ VERSION = "2.1.0" # rubocop:disable Style/MutableConstant
5
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: 2.0.2
4
+ version: 2.1.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-09-30 00:00:00.000000000 Z
11
+ date: 2016-10-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -149,7 +149,7 @@ files:
149
149
  - lib/raven/integrations/rake.rb
150
150
  - lib/raven/integrations/sidekiq.rb
151
151
  - lib/raven/integrations/tasks.rb
152
- - lib/raven/interfaces.rb
152
+ - lib/raven/interface.rb
153
153
  - lib/raven/interfaces/exception.rb
154
154
  - lib/raven/interfaces/http.rb
155
155
  - lib/raven/interfaces/message.rb