sentry-raven 0.4.1 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of sentry-raven might be problematic. Click here for more details.

@@ -19,7 +19,7 @@ module Raven
19
19
  class << self
20
20
  # The client object is responsible for delivering formatted data to the Sentry server.
21
21
  # Must respond to #send. See Raven::Client.
22
- attr_accessor :client
22
+ attr_writer :client
23
23
 
24
24
  # A Raven configuration object. Must act like a hash and return sensible
25
25
  # values for all Raven configuration options. See Raven::Configuration.
@@ -40,6 +40,11 @@ module Raven
40
40
  @configuration ||= Configuration.new
41
41
  end
42
42
 
43
+ # The client object is responsible for delivering formatted data to the Sentry server.
44
+ def client
45
+ @client ||= Client.new(configuration)
46
+ end
47
+
43
48
  # Call this method to modify defaults in your initializers.
44
49
  #
45
50
  # @example
@@ -47,7 +52,10 @@ module Raven
47
52
  # config.server = 'http://...'
48
53
  # end
49
54
  def configure(silent = false)
50
- yield(configuration)
55
+ if block_given?
56
+ yield(configuration)
57
+ end
58
+
51
59
  self.client = Client.new(configuration)
52
60
  report_ready unless silent
53
61
  self.client
@@ -59,7 +67,7 @@ module Raven
59
67
  # evt = Raven::Event.new(:message => "An error")
60
68
  # Raven.send(evt)
61
69
  def send(evt)
62
- @client.send(evt) if @client
70
+ client.send(evt)
63
71
  end
64
72
 
65
73
  # Capture and process any exceptions from the given block, or globally if
@@ -100,6 +108,24 @@ module Raven
100
108
  send(evt) if evt
101
109
  end
102
110
 
111
+ # Bind context for any future events
112
+ #
113
+ # @example
114
+ # Raven.context({
115
+ # :tags => {
116
+ # 'key' => 'value',
117
+ # }
118
+ # })
119
+ def context(hash = {})
120
+ Thread.current[:sentry_context] ||= {}
121
+ Thread.current[:sentry_context].merge!(hash)
122
+ self
123
+ end
124
+
125
+ def clear!
126
+ Thread.current[:sentry_context] = nil
127
+ end
128
+
103
129
  # For cross-language compat
104
130
  alias :captureException :capture_exception
105
131
  alias :captureMessage :capture_message
@@ -1,4 +1,3 @@
1
- require 'openssl'
2
1
  require 'multi_json'
3
2
  require 'zlib'
4
3
  require 'base64'
@@ -11,7 +10,7 @@ module Raven
11
10
 
12
11
  class Client
13
12
 
14
- PROTOCOL_VERSION = '2.0'
13
+ PROTOCOL_VERSION = '3.0'
15
14
  USER_AGENT = "raven-ruby/#{Raven::VERSION}"
16
15
  CONTENT_TYPE = 'application/json'
17
16
 
@@ -57,10 +56,6 @@ module Raven
57
56
  end
58
57
  end
59
58
 
60
- def generate_signature(timestamp, data)
61
- OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new('sha1'), self.configuration.secret_key, "#{timestamp} #{data}")
62
- end
63
-
64
59
  def generate_auth_header(data)
65
60
  now = Time.now.to_i.to_s
66
61
  fields = {
@@ -68,7 +63,7 @@ module Raven
68
63
  'sentry_client' => USER_AGENT,
69
64
  'sentry_timestamp' => now,
70
65
  'sentry_key' => self.configuration.public_key,
71
- 'sentry_signature' => generate_signature(now, data)
66
+ 'sentry_secret' => self.configuration.secret_key,
72
67
  }
73
68
  'Sentry ' + fields.map{|key, value| "#{key}=#{value}"}.join(', ')
74
69
  end
@@ -23,42 +23,57 @@ module Raven
23
23
  PLATFORM = "ruby"
24
24
 
25
25
  attr_reader :id
26
- attr_accessor :project, :message, :timestamp, :level
26
+ attr_accessor :project, :message, :timestamp, :level, :context
27
27
  attr_accessor :logger, :culprit, :server_name, :modules, :extra, :tags
28
28
 
29
29
  def initialize(options={}, &block)
30
30
  @configuration = options[:configuration] || Raven.configuration
31
31
  @interfaces = {}
32
32
 
33
+ @context = Thread.current[:sentry_context] || {}
34
+
33
35
  @id = options[:id] || UUIDTools::UUID.random_create.hexdigest
34
36
  @message = options[:message]
35
37
  @timestamp = options[:timestamp] || Time.now.utc
36
- @level = options[:level] || :error
37
- @logger = options[:logger] || 'root'
38
+
39
+ @level = options[:level]
40
+ @logger = options[:logger]
38
41
  @culprit = options[:culprit]
39
- @extra = options[:extra]
40
- @tags = options[:tags]
42
+
43
+ @extra = options[:extra] || {}
44
+ @tags = options[:tags] || {}
41
45
 
42
46
  # Try to resolve the hostname to an FQDN, but fall back to whatever the load name is
43
- hostname = Socket.gethostname
44
- hostname = Socket.gethostbyname(hostname).first rescue hostname
45
- @server_name = options[:server_name] || hostname
47
+ @server_name = options[:server_name] || get_hostname
46
48
 
47
- # Older versions of Rubygems don't support iterating over all specs
48
- if @configuration.send_modules && Gem::Specification.respond_to?(:map)
49
- options[:modules] ||= Hash[Gem::Specification.map {|spec| [spec.name, spec.version.to_s]}]
49
+ if @configuration.send_modules
50
+ options[:modules] ||= get_modules
50
51
  end
51
52
  @modules = options[:modules]
52
53
 
53
54
  block.call(self) if block
54
55
 
56
+ # Merge in context
57
+ @level ||= @context[:level] || :error
58
+ @logger ||= @context[:logger] || 'root'
59
+ @culprit ||= @context[:culprit]
60
+
61
+ @tags.merge!(@context[:tags]) if @context[:tags]
62
+ @extra.merge!(@context[:extra]) if @context[:extra]
63
+
55
64
  # Some type coercion
56
65
  @timestamp = @timestamp.strftime('%Y-%m-%dT%H:%M:%S') if @timestamp.is_a?(Time)
57
66
  @level = LOG_LEVELS[@level.to_s.downcase] if @level.is_a?(String) || @level.is_a?(Symbol)
67
+ end
58
68
 
59
- # Basic sanity checking
60
- raise Error.new('A message is required for all events') unless @message && !@message.empty?
61
- raise Error.new('A timestamp is required for all events') unless @timestamp
69
+ def get_hostname
70
+ hostname = Socket.gethostname
71
+ hostname = Socket.gethostbyname(hostname).first rescue hostname
72
+ end
73
+
74
+ def get_modules
75
+ # Older versions of Rubygems don't support iterating over all specs
76
+ Hash[Gem::Specification.map {|spec| [spec.name, spec.version.to_s]}] if Gem::Specification.respond_to?(:map)
62
77
  end
63
78
 
64
79
  def interface(name, value=nil, &block)
@@ -126,7 +141,7 @@ module Raven
126
141
  frame.in_app = line.in_app
127
142
  if context_lines and frame.abs_path
128
143
  frame.pre_context, frame.context_line, frame.post_context = \
129
- evt.get_context(frame.abs_path, frame.lineno, context_lines)
144
+ evt.get_file_context(frame.abs_path, frame.lineno, context_lines)
130
145
  end
131
146
  end
132
147
  }.select{ |f| f.filename }
@@ -160,7 +175,7 @@ module Raven
160
175
  def self._source_lines(path, from, to)
161
176
  end
162
177
 
163
- def get_context(filename, lineno, context)
178
+ def get_file_context(filename, lineno, context)
164
179
  lines = (2 * context + 1).times.map do |i|
165
180
  Raven::LineCache::getline(filename, lineno - context + i)
166
181
  end
@@ -168,7 +183,7 @@ module Raven
168
183
  end
169
184
 
170
185
  def get_culprit(frames)
171
- lastframe = frames[-1]
186
+ lastframe = frames.reverse.detect { |f| f.in_app } || frames.last
172
187
  "#{lastframe.filename} in #{lastframe.function}" if lastframe
173
188
  end
174
189
 
@@ -31,6 +31,8 @@ module Raven
31
31
  evt = Event.capture_rack_exception(e, env)
32
32
  Raven.send(evt)
33
33
  raise
34
+ ensure
35
+ Raven.context.clear!
34
36
  end
35
37
 
36
38
  error = env['rack.exception'] || env['sinatra.error']
@@ -1,3 +1,3 @@
1
1
  module Raven
2
- VERSION = "0.4.1"
2
+ VERSION = "0.4.2"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sentry-raven
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.4.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-01-29 00:00:00.000000000 Z
13
+ date: 2013-01-30 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: faraday