sentry-raven 0.4.0 → 0.4.1

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.

data/lib/raven/client.rb CHANGED
@@ -1,10 +1,11 @@
1
1
  require 'openssl'
2
- require 'uri'
3
2
  require 'multi_json'
4
- require 'faraday'
3
+ require 'zlib'
4
+ require 'base64'
5
5
 
6
6
  require 'raven/version'
7
- require 'raven/error'
7
+ require 'raven/transports/http'
8
+ require 'raven/transports/udp'
8
9
 
9
10
  module Raven
10
11
 
@@ -12,7 +13,7 @@ module Raven
12
13
 
13
14
  PROTOCOL_VERSION = '2.0'
14
15
  USER_AGENT = "raven-ruby/#{Raven::VERSION}"
15
- AUTH_HEADER_KEY = 'X-Sentry-Auth'
16
+ CONTENT_TYPE = 'application/json'
16
17
 
17
18
  attr_accessor :configuration
18
19
 
@@ -20,28 +21,44 @@ module Raven
20
21
  @configuration = configuration
21
22
  end
22
23
 
23
- def conn
24
- # Error checking
25
- raise Error.new('No server specified') unless self.configuration[:server]
26
- raise Error.new('No public key specified') unless self.configuration[:public_key]
27
- raise Error.new('No secret key specified') unless self.configuration[:secret_key]
28
- raise Error.new('No project ID specified') unless self.configuration[:project_id]
24
+ def send(event)
25
+ return unless configuration.send_in_current_environment?
29
26
 
30
- Raven.logger.debug "Raven client connecting to #{self.configuration[:server]}"
27
+ # Set the project ID correctly
28
+ event.project = self.configuration.project_id
29
+ Raven.logger.debug "Sending event #{event.id} to Sentry"
30
+ content_type, encoded_data = encode(event)
31
+ transport.send(generate_auth_header(encoded_data), encoded_data,
32
+ :content_type => content_type)
33
+ end
31
34
 
32
- @conn ||= Faraday.new(
33
- :url => self.configuration[:server],
34
- :ssl => {:verify => self.configuration.ssl_verification}
35
- ) do |builder|
36
- builder.adapter Faraday.default_adapter
37
- builder.options[:timeout] = self.configuration.timeout if self.configuration.timeout
38
- builder.options[:open_timeout] = self.configuration.open_timeout if self.configuration.open_timeout
39
- end
35
+ private
36
+
37
+ def encode(event)
38
+ encoded = MultiJson.encode(event.to_hash)
39
+ case self.configuration.encoding
40
+ when 'gzip'
41
+ gzipped = Zlib::Deflate.deflate(encoded)
42
+ b64_encoded = Base64.strict_encode64(gzipped)
43
+ return 'application/octet-stream', b64_encoded
44
+ else
45
+ return 'application/json', encoded
46
+ end
40
47
  end
41
48
 
49
+ def transport
50
+ @transport ||= case self.configuration.scheme
51
+ when 'udp'
52
+ Transports::UDP.new self.configuration
53
+ when 'http', 'https'
54
+ Transports::HTTP.new self.configuration
55
+ else
56
+ raise Error.new("Unknown transport scheme '#{self.configuration.scheme}'")
57
+ end
58
+ end
42
59
 
43
60
  def generate_signature(timestamp, data)
44
- OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new('sha1'), self.configuration[:secret_key], "#{timestamp} #{data}")
61
+ OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new('sha1'), self.configuration.secret_key, "#{timestamp} #{data}")
45
62
  end
46
63
 
47
64
  def generate_auth_header(data)
@@ -50,27 +67,12 @@ module Raven
50
67
  'sentry_version' => PROTOCOL_VERSION,
51
68
  'sentry_client' => USER_AGENT,
52
69
  'sentry_timestamp' => now,
53
- 'sentry_key' => self.configuration[:public_key],
70
+ 'sentry_key' => self.configuration.public_key,
54
71
  'sentry_signature' => generate_signature(now, data)
55
72
  }
56
73
  'Sentry ' + fields.map{|key, value| "#{key}=#{value}"}.join(', ')
57
74
  end
58
75
 
59
- def send(event)
60
- return unless configuration.send_in_current_environment?
61
-
62
- # Set the project ID correctly
63
- event.project = self.configuration[:project_id]
64
- Raven.logger.debug "Sending event #{event.id} to Sentry"
65
- response = self.conn.post '/api/store/' do |req|
66
- req.headers['Content-Type'] = 'application/json'
67
- req.body = MultiJson.encode(event.to_hash)
68
- req.headers[AUTH_HEADER_KEY] = self.generate_auth_header(req.body)
69
- end
70
- raise Error.new("Error from Sentry server (#{response.status}): #{response.body}") unless response.status == 200
71
- response
72
- end
73
-
74
76
  end
75
77
 
76
78
  end
@@ -1,8 +1,8 @@
1
1
  module Raven
2
2
  class Configuration
3
3
 
4
- # Base URL of the Sentry server
5
- attr_accessor :server
4
+ # Simple server string (setter provided below)
5
+ attr_reader :server
6
6
 
7
7
  # Public key for authentication with the Sentry server
8
8
  attr_accessor :public_key
@@ -10,9 +10,18 @@ module Raven
10
10
  # Secret key for authentication with the Sentry server
11
11
  attr_accessor :secret_key
12
12
 
13
+ # Accessors for the component parts of the DSN
14
+ attr_accessor :scheme
15
+ attr_accessor :host
16
+ attr_accessor :port
17
+ attr_accessor :path
18
+
13
19
  # Project ID number to send to the Sentry server
14
20
  attr_accessor :project_id
15
21
 
22
+ # Encoding type for event bodies
23
+ attr_reader :encoding
24
+
16
25
  # Logger to use internally
17
26
  attr_accessor :logger
18
27
 
@@ -59,22 +68,36 @@ module Raven
59
68
  self.excluded_exceptions = IGNORE_DEFAULT
60
69
  self.processors = [Raven::Processor::SanitizeData]
61
70
  self.ssl_verification = true
71
+ self.encoding = 'json'
72
+ self.timeout = 1
73
+ self.open_timeout = 1
62
74
  end
63
75
 
64
76
  def server=(value)
65
77
  uri = URI::parse(value)
78
+ uri_path = uri.path.split('/')
79
+
66
80
  if uri.user
67
81
  # DSN-style string
68
- uri_path = uri.path.split('/')
69
82
  @project_id = uri_path.pop
70
- @server = "#{uri.scheme}://#{uri.host}"
71
- @server << ":#{uri.port}" unless uri.port == {'http'=>80,'https'=>443}[uri.scheme]
72
- @server << uri_path.join('/')
73
83
  @public_key = uri.user
74
84
  @secret_key = uri.password
75
- else
76
- @server = value
77
85
  end
86
+
87
+ @scheme = uri.scheme
88
+ @host = uri.host
89
+ @port = uri.port if uri.port
90
+ @path = uri_path.join('/')
91
+
92
+ # For anyone who wants to read the base server string
93
+ @server = "#{@scheme}://#{@host}"
94
+ @server << ":#{@port}" unless @port == {'http'=>80,'https'=>443}[@scheme]
95
+ @server << @path
96
+ end
97
+
98
+ def encoding=(encoding)
99
+ raise Error.new('Unsupported encoding') unless ['gzip', 'json'].include? encoding
100
+ @encoding = encoding
78
101
  end
79
102
 
80
103
  alias_method :dsn=, :server=
data/lib/raven/event.rb CHANGED
@@ -20,6 +20,8 @@ module Raven
20
20
 
21
21
  BACKTRACE_RE = /^(.+?):(\d+)(?::in `(.+?)')?$/
22
22
 
23
+ PLATFORM = "ruby"
24
+
23
25
  attr_reader :id
24
26
  attr_accessor :project, :message, :timestamp, :level
25
27
  attr_accessor :logger, :culprit, :server_name, :modules, :extra, :tags
@@ -82,6 +84,7 @@ module Raven
82
84
  'level' => self.level,
83
85
  'project' => self.project,
84
86
  'logger' => self.logger,
87
+ 'platform' => PLATFORM,
85
88
  }
86
89
  data['culprit'] = self.culprit if self.culprit
87
90
  data['server_name'] = self.server_name if self.server_name
@@ -115,18 +118,18 @@ module Raven
115
118
  if (exc.backtrace)
116
119
  evt.interface :stack_trace do |int|
117
120
  backtrace = Backtrace.parse(exc.backtrace)
118
- int.frames = backtrace.lines.reverse.map do |line|
121
+ int.frames = backtrace.lines.reverse.map { |line|
119
122
  int.frame do |frame|
120
123
  frame.abs_path = line.file
121
124
  frame.function = line.method
122
125
  frame.lineno = line.number
123
126
  frame.in_app = line.in_app
124
- if context_lines
127
+ if context_lines and frame.abs_path
125
128
  frame.pre_context, frame.context_line, frame.post_context = \
126
129
  evt.get_context(frame.abs_path, frame.lineno, context_lines)
127
130
  end
128
131
  end
129
- end
132
+ }.select{ |f| f.filename }
130
133
  evt.culprit = evt.get_culprit(int.frames)
131
134
  end
132
135
  end
@@ -43,6 +43,8 @@ module Raven
43
43
  end
44
44
 
45
45
  def filename
46
+ return nil if self.abs_path.nil?
47
+
46
48
  prefix = $:.select {|s| self.abs_path.start_with?(s)}.sort_by {|s| s.length}.last
47
49
  prefix ? self.abs_path[prefix.chomp(File::SEPARATOR).length+1..-1] : self.abs_path
48
50
  end
data/lib/raven/rack.rb CHANGED
@@ -33,8 +33,10 @@ module Raven
33
33
  raise
34
34
  end
35
35
 
36
- if env['rack.exception']
37
- evt = Event.capture_rack_exception(env['rack.exception'], env)
36
+ error = env['rack.exception'] || env['sinatra.error']
37
+
38
+ if error
39
+ evt = Event.capture_rack_exception(error, env)
38
40
  Raven.send(evt) if evt
39
41
  end
40
42
 
@@ -0,0 +1,32 @@
1
+ require 'raven/error'
2
+
3
+ module Raven
4
+
5
+ module Transports
6
+
7
+ class Transport
8
+
9
+ attr_accessor :configuration
10
+
11
+ def initialize(configuration)
12
+ @configuration = configuration
13
+ end
14
+
15
+ def send(auth_header, data, options = {})
16
+ raise Error.new('Abstract method not implemented')
17
+ end
18
+
19
+ protected
20
+
21
+ def verify_configuration
22
+ raise Error.new('No server specified') unless self.configuration.server
23
+ raise Error.new('No public key specified') unless self.configuration.public_key
24
+ raise Error.new('No secret key specified') unless self.configuration.secret_key
25
+ raise Error.new('No project ID specified') unless self.configuration.project_id
26
+ end
27
+
28
+ end
29
+
30
+ end
31
+
32
+ end
@@ -0,0 +1,44 @@
1
+ require 'faraday'
2
+
3
+ require 'raven/transports'
4
+ require 'raven/error'
5
+
6
+ module Raven
7
+
8
+ module Transports
9
+
10
+ class HTTP < Transport
11
+
12
+ def send(auth_header, data, options = {})
13
+ response = conn.post '/api/store/' do |req|
14
+ req.headers['Content-Type'] = options[:content_type]
15
+ req.headers['X-Sentry-Auth'] = auth_header
16
+ req.body = data
17
+ end
18
+ raise Error.new("Error from Sentry server (#{response.status}): #{response.body}") unless response.status == 200
19
+ end
20
+
21
+ private
22
+
23
+ def conn
24
+ @conn ||= begin
25
+ self.verify_configuration
26
+
27
+ Raven.logger.debug "Raven HTTP Transport connecting to #{self.configuration.server}"
28
+
29
+ Faraday.new(
30
+ :url => self.configuration[:server],
31
+ :ssl => {:verify => self.configuration.ssl_verification}
32
+ ) do |builder|
33
+ builder.adapter Faraday.default_adapter
34
+ builder.options[:timeout] = self.configuration.timeout if self.configuration.timeout
35
+ builder.options[:open_timeout] = self.configuration.open_timeout if self.configuration.open_timeout
36
+ end
37
+ end
38
+ end
39
+
40
+ end
41
+
42
+ end
43
+
44
+ end
@@ -0,0 +1,35 @@
1
+ require 'socket'
2
+
3
+ require 'raven/transports'
4
+ require 'raven/error'
5
+
6
+ module Raven
7
+
8
+ module Transports
9
+
10
+ class UDP < Transport
11
+
12
+ def send(auth_header, data, options = {})
13
+ conn.send "#{auth_header}\n\n#{data}", 0
14
+ end
15
+
16
+ private
17
+
18
+ def conn
19
+ @conn ||= begin
20
+ sock = UDPSocket.new
21
+ sock.connect(self.configuration.host, self.configuration.port)
22
+ sock
23
+ end
24
+ end
25
+
26
+ def verify_configuration
27
+ super
28
+ raise Error.new('No port specified') unless self.configuration.port
29
+ end
30
+
31
+ end
32
+
33
+ end
34
+
35
+ end
data/lib/raven/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Raven
2
- VERSION = "0.4.0"
2
+ VERSION = "0.4.1"
3
3
  end
metadata CHANGED
@@ -1,84 +1,90 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: sentry-raven
3
- version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 4
8
- - 0
9
- version: 0.4.0
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.1
5
+ prerelease:
10
6
  platform: ruby
11
- authors:
7
+ authors:
12
8
  - Noah Kantrowitz
13
9
  - David Cramer
14
10
  autorequire:
15
11
  bindir: bin
16
12
  cert_chain: []
17
-
18
- date: 2013-01-04 00:00:00 -08:00
19
- default_executable:
20
- dependencies:
21
- - !ruby/object:Gem::Dependency
13
+ date: 2013-01-29 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
22
16
  name: faraday
23
- prerelease: false
24
- requirement: &id001 !ruby/object:Gem::Requirement
25
- requirements:
26
- - - ">="
27
- - !ruby/object:Gem::Version
28
- segments:
29
- - 0
30
- - 7
31
- - 6
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
32
22
  version: 0.7.6
33
23
  type: :runtime
34
- version_requirements: *id001
35
- - !ruby/object:Gem::Dependency
36
- name: uuidtools
37
24
  prerelease: false
38
- requirement: &id002 !ruby/object:Gem::Requirement
39
- requirements:
40
- - - ">="
41
- - !ruby/object:Gem::Version
42
- segments:
43
- - 0
44
- version: "0"
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ! '>='
29
+ - !ruby/object:Gem::Version
30
+ version: 0.7.6
31
+ - !ruby/object:Gem::Dependency
32
+ name: uuidtools
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ! '>='
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
45
39
  type: :runtime
46
- version_requirements: *id002
47
- - !ruby/object:Gem::Dependency
48
- name: multi_json
49
40
  prerelease: false
50
- requirement: &id003 !ruby/object:Gem::Requirement
51
- requirements:
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: multi_json
49
+ requirement: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
52
  - - ~>
53
- - !ruby/object:Gem::Version
54
- segments:
55
- - 1
56
- - 0
57
- version: "1.0"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.0'
58
55
  type: :runtime
59
- version_requirements: *id003
60
- - !ruby/object:Gem::Dependency
61
- name: hashie
62
56
  prerelease: false
63
- requirement: &id004 !ruby/object:Gem::Requirement
64
- requirements:
65
- - - ">="
66
- - !ruby/object:Gem::Version
67
- segments:
68
- - 0
69
- version: "0"
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ~>
61
+ - !ruby/object:Gem::Version
62
+ version: '1.0'
63
+ - !ruby/object:Gem::Dependency
64
+ name: hashie
65
+ requirement: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ! '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
70
71
  type: :runtime
71
- version_requirements: *id004
72
+ prerelease: false
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
72
79
  description:
73
80
  email: noah@coderanger.net
74
- executables:
81
+ executables:
75
82
  - raven
76
83
  extensions: []
77
-
78
- extra_rdoc_files:
84
+ extra_rdoc_files:
79
85
  - README.md
80
86
  - LICENSE
81
- files:
87
+ files:
82
88
  - lib/raven/backtrace.rb
83
89
  - lib/raven/client.rb
84
90
  - lib/raven/configuration.rb
@@ -97,40 +103,37 @@ files:
97
103
  - lib/raven/rails/middleware/debug_exceptions_catcher.rb
98
104
  - lib/raven/railtie.rb
99
105
  - lib/raven/sidekiq.rb
106
+ - lib/raven/transports/http.rb
107
+ - lib/raven/transports/udp.rb
108
+ - lib/raven/transports.rb
100
109
  - lib/raven/version.rb
101
110
  - lib/raven.rb
102
111
  - lib/sentry-raven.rb
103
112
  - README.md
104
113
  - LICENSE
105
- has_rdoc: true
114
+ - bin/raven
106
115
  homepage: http://github.com/getsentry/raven-ruby
107
116
  licenses: []
108
-
109
117
  post_install_message:
110
118
  rdoc_options: []
111
-
112
- require_paths:
119
+ require_paths:
113
120
  - lib
114
- required_ruby_version: !ruby/object:Gem::Requirement
115
- requirements:
116
- - - ">="
117
- - !ruby/object:Gem::Version
118
- segments:
119
- - 0
120
- version: "0"
121
- required_rubygems_version: !ruby/object:Gem::Requirement
122
- requirements:
123
- - - ">="
124
- - !ruby/object:Gem::Version
125
- segments:
126
- - 0
127
- version: "0"
121
+ required_ruby_version: !ruby/object:Gem::Requirement
122
+ none: false
123
+ requirements:
124
+ - - ! '>='
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
127
+ required_rubygems_version: !ruby/object:Gem::Requirement
128
+ none: false
129
+ requirements:
130
+ - - ! '>='
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
128
133
  requirements: []
129
-
130
134
  rubyforge_project:
131
- rubygems_version: 1.3.6
135
+ rubygems_version: 1.8.23
132
136
  signing_key:
133
137
  specification_version: 3
134
138
  summary: A gem that provides a client interface for the Sentry error logger
135
139
  test_files: []
136
-