sentry-raven 2.0.2 → 2.1.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: 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