contrast-exceptional 0.0.1 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +6 -0
- data/Manifest +11 -5
- data/README +3 -3
- data/Rakefile +5 -6
- data/exceptional.gemspec +32 -32
- data/init.rb +1 -19
- data/lib/exceptional.rb +12 -223
- data/lib/exceptional/api.rb +108 -0
- data/lib/exceptional/bootstrap.rb +23 -0
- data/lib/exceptional/config.rb +74 -0
- data/lib/exceptional/exception_data.rb +2 -4
- data/lib/exceptional/integration/rails.rb +25 -13
- data/lib/exceptional/log.rb +50 -0
- data/lib/exceptional/remote.rb +75 -0
- data/lib/exceptional/version.rb +1 -1
- data/spec/api_spec.rb +211 -0
- data/spec/bootstrap_spec.rb +58 -0
- data/spec/config_spec.rb +110 -0
- data/spec/exceptional_rescue_from_spec.rb +41 -0
- data/spec/exceptional_spec.rb +16 -58
- data/spec/log_spec.rb +28 -0
- data/spec/remote_spec.rb +137 -0
- data/spec/spec_helper.rb +11 -0
- metadata +43 -25
- data/lib/exceptional/agent/worker.rb +0 -56
- data/lib/exceptional/deployed_environment.rb +0 -86
- data/lib/exceptional/rails.rb +0 -53
- data/spec/deployed_environment_spec.rb +0 -168
- data/spec/worker_spec.rb +0 -21
data/History.txt
CHANGED
@@ -0,0 +1,6 @@
|
|
1
|
+
0.0.6 - Added a better 'safe' to_json method which works more effectively for rails integration avoiding cyclic reference and un-jsonable data
|
2
|
+
0.0.5 - Fixed a bug in the plugin where request.env was being modified directly. dup to solve issues.
|
3
|
+
0.0.4 - Restructured the plugin to extract all different concerns into self contained modules, will give a better base to extend. Also plays nicer with Rdoc + singleton classes
|
4
|
+
0.0.3 - Dropped background queing of exceptions, send them all directly. Fixed issues with session/environment data. Working with rails 2.3 (some hacks needed to get there, need to refactor.)
|
5
|
+
0.0.2 - Fix a bug introduced with nil sessions
|
6
|
+
0.0.1 - First Version
|
data/Manifest
CHANGED
@@ -3,18 +3,24 @@ exceptional.yml
|
|
3
3
|
History.txt
|
4
4
|
init.rb
|
5
5
|
install.rb
|
6
|
-
lib/exceptional/
|
7
|
-
lib/exceptional/
|
6
|
+
lib/exceptional/api.rb
|
7
|
+
lib/exceptional/bootstrap.rb
|
8
|
+
lib/exceptional/config.rb
|
8
9
|
lib/exceptional/exception_data.rb
|
9
10
|
lib/exceptional/integration/rails.rb
|
10
|
-
lib/exceptional/
|
11
|
+
lib/exceptional/log.rb
|
12
|
+
lib/exceptional/remote.rb
|
11
13
|
lib/exceptional/version.rb
|
12
14
|
lib/exceptional.rb
|
13
15
|
Manifest
|
14
16
|
Rakefile
|
15
17
|
README
|
16
|
-
spec/
|
18
|
+
spec/api_spec.rb
|
19
|
+
spec/bootstrap_spec.rb
|
20
|
+
spec/config_spec.rb
|
17
21
|
spec/exception_data_spec.rb
|
22
|
+
spec/exceptional_rescue_from_spec.rb
|
18
23
|
spec/exceptional_spec.rb
|
24
|
+
spec/log_spec.rb
|
25
|
+
spec/remote_spec.rb
|
19
26
|
spec/spec_helper.rb
|
20
|
-
spec/worker_spec.rb
|
data/README
CHANGED
@@ -4,10 +4,10 @@ This plugin posts exception data to Exceptional (http://getexceptional.com). Dat
|
|
4
4
|
|
5
5
|
= Exceptional
|
6
6
|
|
7
|
-
Exceptional (http://getexceptional.com) is a web-based exception tracking and managing system for Ruby on Rails folks and their apps.
|
7
|
+
Exceptional (http://getexceptional.com) is a web-based exception tracking and managing system for Ruby on Rails folks and their apps.
|
8
8
|
|
9
9
|
= Installation
|
10
10
|
|
11
|
-
For installation instructions, follow the steps displayed after adding a new app to your account. Please send any questions or comments to
|
11
|
+
For installation instructions, follow the steps displayed after adding a new app to your account. Please send any questions or comments to feedback@getexceptional.com.
|
12
12
|
|
13
|
-
Copyright © 2008 Contrast.
|
13
|
+
Copyright © 2008, 2009 Contrast.
|
data/Rakefile
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
begin
|
2
2
|
require 'echoe'
|
3
3
|
|
4
|
-
Echoe.new('exceptional', '0.0.
|
4
|
+
Echoe.new('exceptional', '0.0.6') do |p|
|
5
5
|
p.rubyforge_name = 'exceptional'
|
6
6
|
p.summary = "Exceptional is the core Ruby library for communicating with http://getexceptional.com (hosted error tracking service)"
|
7
7
|
p.description = "Exceptional is the core Ruby library for communicating with http://getexceptional.com (hosted error tracking service)"
|
8
8
|
p.url = "http://getexceptional.com/"
|
9
|
-
p.author = [
|
10
|
-
p.email = "
|
9
|
+
p.author = ["Contrast"]
|
10
|
+
p.email = "hello@contrast.ie"
|
11
11
|
p.dependencies = ["json"]
|
12
12
|
end
|
13
13
|
|
@@ -24,17 +24,16 @@ begin
|
|
24
24
|
t.spec_files = FileList['spec/**/*_spec.rb']
|
25
25
|
t.spec_opts = ['--color']
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
task :test do
|
29
29
|
Rake::Task['spec'].invoke
|
30
30
|
end
|
31
|
-
|
31
|
+
|
32
32
|
Spec::Rake::SpecTask.new("coverage") do |t|
|
33
33
|
t.spec_files = FileList['spec/**/*_spec.rb']
|
34
34
|
t.spec_opts = ['--color']
|
35
35
|
t.rcov = true
|
36
36
|
t.rcov_opts = ['--exclude', '^spec,/gems/']
|
37
37
|
end
|
38
|
-
|
39
38
|
|
40
39
|
end
|
data/exceptional.gemspec
CHANGED
@@ -1,34 +1,34 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
1
3
|
Gem::Specification.new do |s|
|
2
|
-
s.name
|
3
|
-
s.version
|
4
|
-
|
5
|
-
s.
|
6
|
-
s.
|
7
|
-
s.
|
8
|
-
s.description =
|
4
|
+
s.name = %q{exceptional}
|
5
|
+
s.version = "0.0.6"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Contrast"]
|
9
|
+
s.date = %q{2009-07-09}
|
10
|
+
s.description = %q{Exceptional is the core Ruby library for communicating with http://getexceptional.com (hosted error tracking service)}
|
11
|
+
s.email = %q{hello@contrast.ie}
|
12
|
+
s.extra_rdoc_files = ["lib/exceptional/api.rb", "lib/exceptional/bootstrap.rb", "lib/exceptional/config.rb", "lib/exceptional/exception_data.rb", "lib/exceptional/integration/rails.rb", "lib/exceptional/log.rb", "lib/exceptional/remote.rb", "lib/exceptional/version.rb", "lib/exceptional.rb", "README"]
|
13
|
+
s.files = ["exceptional.gemspec", "exceptional.yml", "History.txt", "init.rb", "install.rb", "lib/exceptional/api.rb", "lib/exceptional/bootstrap.rb", "lib/exceptional/config.rb", "lib/exceptional/exception_data.rb", "lib/exceptional/integration/rails.rb", "lib/exceptional/log.rb", "lib/exceptional/remote.rb", "lib/exceptional/version.rb", "lib/exceptional.rb", "Manifest", "Rakefile", "README", "spec/api_spec.rb", "spec/bootstrap_spec.rb", "spec/config_spec.rb", "spec/exception_data_spec.rb", "spec/exceptional_rescue_from_spec.rb", "spec/exceptional_spec.rb", "spec/log_spec.rb", "spec/remote_spec.rb", "spec/spec_helper.rb"]
|
9
14
|
s.has_rdoc = true
|
10
|
-
s.
|
11
|
-
s.
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
"spec/worker_spec.rb"]
|
31
|
-
s.rdoc_options = ["--main", "README"]
|
32
|
-
s.extra_rdoc_files = ["History.txt", "Manifest", "README"]
|
33
|
-
s.add_dependency("json", ["> 0.0.0"])
|
34
|
-
end
|
15
|
+
s.homepage = %q{http://getexceptional.com/}
|
16
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Exceptional", "--main", "README"]
|
17
|
+
s.require_paths = ["lib"]
|
18
|
+
s.rubyforge_project = %q{exceptional}
|
19
|
+
s.rubygems_version = %q{1.3.1}
|
20
|
+
s.summary = %q{Exceptional is the core Ruby library for communicating with http://getexceptional.com (hosted error tracking service)}
|
21
|
+
|
22
|
+
if s.respond_to? :specification_version then
|
23
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
24
|
+
s.specification_version = 2
|
25
|
+
|
26
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
27
|
+
s.add_runtime_dependency(%q<json>, [">= 0"])
|
28
|
+
else
|
29
|
+
s.add_dependency(%q<json>, [">= 0"])
|
30
|
+
end
|
31
|
+
else
|
32
|
+
s.add_dependency(%q<json>, [">= 0"])
|
33
|
+
end
|
34
|
+
end
|
data/init.rb
CHANGED
@@ -1,20 +1,2 @@
|
|
1
1
|
require 'exceptional'
|
2
|
-
|
3
|
-
def to_stderr(s)
|
4
|
-
STDERR.puts "** [Exceptional] " + s
|
5
|
-
end
|
6
|
-
|
7
|
-
config_file = File.join(RAILS_ROOT,"/config/exceptional.yml")
|
8
|
-
|
9
|
-
begin
|
10
|
-
Exceptional.application_root = RAILS_ROOT
|
11
|
-
Exceptional.environment = RAILS_ENV
|
12
|
-
|
13
|
-
Exceptional.load_config(config_file)
|
14
|
-
if Exceptional.enabled?
|
15
|
-
Exceptional::Rails.init
|
16
|
-
end
|
17
|
-
rescue Exception => e
|
18
|
-
to_stderr e
|
19
|
-
to_stderr "Plugin disabled."
|
20
|
-
end
|
2
|
+
Exceptional.bootstrap(RAILS_ENV, RAILS_ROOT)
|
data/lib/exceptional.rb
CHANGED
@@ -1,231 +1,20 @@
|
|
1
1
|
$:.unshift File.dirname(__FILE__)
|
2
|
-
|
3
|
-
require 'exceptional/deployed_environment'
|
4
|
-
require 'exceptional/agent/worker'
|
2
|
+
|
5
3
|
require 'exceptional/exception_data'
|
6
4
|
require 'exceptional/version'
|
7
|
-
require '
|
8
|
-
|
9
|
-
require '
|
10
|
-
require '
|
11
|
-
require '
|
12
|
-
require 'logger'
|
13
|
-
require 'yaml'
|
14
|
-
require 'json' unless defined? Rails
|
15
|
-
# Hack to force Rails version prior to 2.0 to use quoted JSON as per the JSON standard... (TODO: could be cleaner!)
|
16
|
-
ActiveSupport::JSON.unquote_hash_key_identifiers = false if (defined?(ActiveSupport::JSON) && ActiveSupport::JSON.respond_to?(:unquote_hash_key_identifiers))
|
5
|
+
require 'exceptional/log'
|
6
|
+
require 'exceptional/config'
|
7
|
+
require 'exceptional/remote'
|
8
|
+
require 'exceptional/api'
|
9
|
+
require 'exceptional/bootstrap'
|
17
10
|
|
18
11
|
module Exceptional
|
19
|
-
class LicenseException < StandardError; end
|
20
|
-
class ConfigurationException < StandardError; end
|
21
|
-
|
22
|
-
::PROTOCOL_VERSION = 3
|
23
|
-
# Defaults for configuration variables
|
24
|
-
::REMOTE_HOST = "getexceptional.com"
|
25
|
-
::REMOTE_PORT = 80
|
26
|
-
::REMOTE_SSL_PORT = 443
|
27
|
-
::SSL = false
|
28
|
-
::LOG_LEVEL = 'info'
|
29
|
-
::LOG_PATH = nil
|
30
|
-
::WORKER_TIMEOUT = 10 # seconds
|
31
|
-
::MODE = :direct
|
32
|
-
|
33
|
-
class << self
|
34
|
-
attr_accessor :api_key, :log, :deployed_environment, :log_path, :worker,
|
35
|
-
:worker_thread, :environment, :application_root
|
36
|
-
attr_writer :remote_host, :remote_port, :ssl_enabled, :log_level
|
37
|
-
|
38
|
-
# rescue any exceptions within the given block,
|
39
|
-
# send it to exceptional,
|
40
|
-
# then raise
|
41
|
-
def rescue(&block)
|
42
|
-
begin
|
43
|
-
block.call
|
44
|
-
rescue Exception => e
|
45
|
-
self.catch(e)
|
46
|
-
raise(e)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
# parse an exception into an ExceptionData object
|
51
|
-
def parse(exception)
|
52
|
-
exception_data = ExceptionData.new
|
53
|
-
exception_data.exception_backtrace = exception.backtrace
|
54
|
-
exception_data.exception_message = exception.message
|
55
|
-
exception_data.exception_class = exception.class.to_s
|
56
|
-
exception_data
|
57
|
-
end
|
58
|
-
|
59
|
-
# authenticate with getexceptional.com
|
60
|
-
# returns true if the configured api_key is registered and can send data
|
61
|
-
# otherwise false
|
62
|
-
def authenticate
|
63
|
-
begin
|
64
|
-
# TODO No data required to authenticate, send a nil string? hacky
|
65
|
-
# TODO should retry if a http connection failed
|
66
|
-
return @authenticated if @authenticated
|
67
|
-
authenticated = call_remote(:authenticate, "")
|
68
|
-
@authenticated = authenticated =~ /true/
|
69
|
-
rescue
|
70
|
-
@authenticated = false
|
71
|
-
ensure
|
72
|
-
return @authenticated
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
# post the given exception data to getexceptional.com
|
77
|
-
def post(exception_data)
|
78
|
-
call_remote(:errors, exception_data.to_json)
|
79
|
-
end
|
80
|
-
|
81
|
-
# given a regular ruby Exception class, will parse into an ExceptionData
|
82
|
-
# object and post to getexceptional.com
|
83
|
-
def catch(exception)
|
84
|
-
exception_data = parse(exception)
|
85
|
-
exception_data.controller_name = File.basename($0)
|
86
|
-
post(exception_data)
|
87
|
-
end
|
88
|
-
|
89
|
-
# used with Rails, takes an exception, controller, request and parameters
|
90
|
-
# creates an ExceptionData object
|
91
|
-
# if Exceptional is running in :direct mode, will post to getexceptional.com
|
92
|
-
# if Exceptional is running in :queue mode, the data will be queued and posted later
|
93
|
-
def handle(exception, controller, request, params)
|
94
|
-
log! "Handling #{exception.message}", 'info'
|
95
|
-
e = parse(exception)
|
96
|
-
# Additional data for Rails Exceptions
|
97
|
-
e.framework = "rails"
|
98
|
-
e.controller_name = controller.controller_name
|
99
|
-
e.action_name = controller.action_name
|
100
|
-
e.application_root = self.application_root
|
101
|
-
e.occurred_at = Time.now.strftime("%Y%m%d %H:%M:%S %Z")
|
102
|
-
e.environment = request.env.to_hash
|
103
|
-
e.url = "#{request.protocol}#{request.host}#{request.request_uri}"
|
104
|
-
# Need to remove rack data from environment hash
|
105
|
-
safe_environment = request.env.to_hash
|
106
|
-
safe_environment.delete_if { |k,v| k =~ /rack/ }
|
107
|
-
e.environment = safe_environment
|
108
|
-
|
109
|
-
safe_session = {}
|
110
|
-
request.session.instance_variables.each do |v|
|
111
|
-
next if v =~ /cgi/
|
112
|
-
next if v =~ /db/
|
113
|
-
# remove prepended @'s
|
114
|
-
var = v.sub("@","")
|
115
|
-
safe_session[var] = request.session.instance_variable_get(v)
|
116
|
-
end
|
117
|
-
|
118
|
-
e.session = safe_session
|
119
|
-
e.parameters = params.to_hash
|
120
12
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
log! "Error posting data to Exceptional."
|
128
|
-
log! exception.message
|
129
|
-
log! exception.backtace.join("\n"), 'debug'
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
# TODO these configuration methods & defaults should have their own class
|
135
|
-
def remote_host
|
136
|
-
@remote_host || ::REMOTE_HOST
|
137
|
-
end
|
138
|
-
|
139
|
-
def remote_port
|
140
|
-
@remote_port || default_port
|
141
|
-
end
|
142
|
-
|
143
|
-
def log_level
|
144
|
-
@log_level || ::LOG_LEVEL
|
145
|
-
end
|
146
|
-
|
147
|
-
def mode
|
148
|
-
deployed_environment ? deployed_environment.determine_mode : ::MODE
|
149
|
-
end
|
150
|
-
|
151
|
-
def default_port
|
152
|
-
ssl_enabled? ? ::REMOTE_SSL_PORT : ::REMOTE_PORT
|
153
|
-
end
|
154
|
-
|
155
|
-
def ssl_enabled?
|
156
|
-
@ssl_enabled || ::SSL
|
157
|
-
end
|
158
|
-
|
159
|
-
def enabled?
|
160
|
-
@enabled
|
161
|
-
end
|
162
|
-
|
163
|
-
def log!(msg, level = 'info')
|
164
|
-
to_stderr msg
|
165
|
-
log.send level, msg if log
|
166
|
-
end
|
167
|
-
|
168
|
-
def to_stderr(msg)
|
169
|
-
if deployed_environment && deployed_environment.server != :unknown
|
170
|
-
STDERR.puts "** [Exceptional] " + msg
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
|
-
def log_config_info
|
175
|
-
log! "API Key: #{api_key}", 'debug'
|
176
|
-
log! "Deployed Environment: #{deployed_environment.to_s}", 'debug'
|
177
|
-
log! "Remote Host: #{remote_host}:#{remote_port}", 'debug'
|
178
|
-
log! "Mode: #{mode}", 'debug'
|
179
|
-
log! "Log level: #{log_level}", 'debug'
|
180
|
-
log! "Log path: #{log_path}", 'debug'
|
181
|
-
end
|
182
|
-
|
183
|
-
def load_config(file)
|
184
|
-
begin
|
185
|
-
config = YAML::load(File.open(file))[self.environment]
|
186
|
-
@api_key = config['api-key'] unless config['api-key'].nil?
|
187
|
-
@ssl_enabled = config['ssl'] unless config['ssl'].nil?
|
188
|
-
@log_level = config['log-level'] unless config['log-level'].nil?
|
189
|
-
@enabled = config['enabled'] unless config['enabled'].nil?
|
190
|
-
@remote_port = config['remote-port'].to_i unless config['remote-port'].nil?
|
191
|
-
@remote_host = config['remote-host'] unless config['remote-host'].nil?
|
192
|
-
rescue Exception => e
|
193
|
-
raise ConfigurationException.new("Unable to load configuration file:#{file} for environment:#{environment}")
|
194
|
-
end
|
195
|
-
end
|
196
|
-
|
197
|
-
protected
|
198
|
-
|
199
|
-
def valid_api_key?
|
200
|
-
@api_key && @api_key.length == 40
|
201
|
-
end
|
202
|
-
|
203
|
-
|
204
|
-
def call_remote(method, data)
|
205
|
-
if @api_key.nil?
|
206
|
-
raise LicenseException.new("API Key must be configured")
|
207
|
-
end
|
208
|
-
|
209
|
-
http = Net::HTTP.new(remote_host, remote_port)
|
210
|
-
uri = "/#{method.to_s}?&api_key=#{@api_key}&protocol_version=#{::PROTOCOL_VERSION}"
|
211
|
-
headers = { 'Content-Type' => 'application/x-gzip', 'Accept' => 'application/x-gzip' }
|
212
|
-
compressed_data = CGI::escape(Zlib::Deflate.deflate(data, Zlib::BEST_SPEED))
|
213
|
-
response = http.start do |http|
|
214
|
-
http.post(uri, compressed_data, headers)
|
215
|
-
end
|
216
|
-
|
217
|
-
if response.kind_of? Net::HTTPSuccess
|
218
|
-
return response.body
|
219
|
-
else
|
220
|
-
raise Exception.new("#{response.code}: #{response.message}")
|
221
|
-
end
|
222
|
-
|
223
|
-
rescue Exception => e
|
224
|
-
log! "Error contacting Exceptional: #{e}", 'info'
|
225
|
-
log! e.backtrace.join("\n"), 'debug'
|
226
|
-
raise e
|
227
|
-
end
|
228
|
-
|
13
|
+
class << self
|
14
|
+
include Exceptional::Config
|
15
|
+
include Exceptional::Api
|
16
|
+
include Exceptional::Remote
|
17
|
+
include Exceptional::Log
|
18
|
+
include Exceptional::Bootstrap
|
229
19
|
end
|
230
|
-
|
231
20
|
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'json' unless defined? Rails
|
2
|
+
|
3
|
+
|
4
|
+
module Exceptional
|
5
|
+
|
6
|
+
module Api
|
7
|
+
# parse an exception into an ExceptionData object
|
8
|
+
def parse(exception)
|
9
|
+
exception_data = ExceptionData.new
|
10
|
+
exception_data.exception_backtrace = exception.backtrace
|
11
|
+
exception_data.exception_message = exception.message
|
12
|
+
exception_data.exception_class = exception.class.to_s
|
13
|
+
exception_data
|
14
|
+
end
|
15
|
+
|
16
|
+
# post the given exception data to getexceptional.com
|
17
|
+
def post(exception_data)
|
18
|
+
hash = exception_data.to_hash
|
19
|
+
if hash[:session]
|
20
|
+
hash[:session].delete("initialization_options")
|
21
|
+
hash[:session].delete("request")
|
22
|
+
end
|
23
|
+
|
24
|
+
Exceptional.post_exception(hash.to_json)
|
25
|
+
end
|
26
|
+
|
27
|
+
# used with Rails, takes an exception, controller, request and parameters
|
28
|
+
# creates an ExceptionData object
|
29
|
+
def handle(exception, controller, request, params)
|
30
|
+
Exceptional.log! "Handling #{exception.message}", 'info'
|
31
|
+
begin
|
32
|
+
e = parse(exception)
|
33
|
+
# Additional data for Rails Exceptions
|
34
|
+
e.framework = "rails"
|
35
|
+
e.controller_name = controller.controller_name
|
36
|
+
e.action_name = controller.action_name
|
37
|
+
e.application_root = Exceptional.application_root
|
38
|
+
e.occurred_at = Time.now.strftime("%Y%m%d %H:%M:%S %Z")
|
39
|
+
e.environment = request.env.to_hash
|
40
|
+
e.url = "#{request.protocol}#{request.host}#{request.request_uri}"
|
41
|
+
e.environment = safe_environment(request)
|
42
|
+
e.session = safe_session(request.session)
|
43
|
+
e.parameters = sanitize_hash(params.to_hash)
|
44
|
+
|
45
|
+
post(e)
|
46
|
+
rescue Exception => exception
|
47
|
+
Exceptional.log! "Error preparing exception data."
|
48
|
+
Exceptional.log! exception.message
|
49
|
+
Exceptional.log! exception.backtrace.join("\n"), 'debug'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# rescue any exceptions within the given block,
|
54
|
+
# send it to exceptional,
|
55
|
+
# then raise
|
56
|
+
def rescue(&block)
|
57
|
+
begin
|
58
|
+
block.call
|
59
|
+
rescue Exception => e
|
60
|
+
self.catch(e)
|
61
|
+
raise(e)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def catch(exception)
|
66
|
+
exception_data = parse(exception)
|
67
|
+
exception_data.controller_name = File.basename($0)
|
68
|
+
post(exception_data)
|
69
|
+
end
|
70
|
+
|
71
|
+
protected
|
72
|
+
|
73
|
+
def safe_environment(request)
|
74
|
+
safe_environment = request.env.dup.to_hash
|
75
|
+
# From Rails 2.3 these objects that cause a circular reference error on .to_json need removed
|
76
|
+
# TODO potentially remove this case, should be covered by sanitize_hash
|
77
|
+
safe_environment.delete_if { |k,v| k =~ /rack/ || k =~ /action_controller/ || k == "_"}
|
78
|
+
# needed to add a filter for the hash for "_", causing invalid xml.
|
79
|
+
sanitize_hash(safe_environment)
|
80
|
+
end
|
81
|
+
|
82
|
+
def safe_session(session)
|
83
|
+
result = {}
|
84
|
+
session.instance_variables.each do |v|
|
85
|
+
next if v =~ /cgi/ || v =~ /db/ || v =~ /env/
|
86
|
+
var = v.sub("@","") # remove prepended @'s
|
87
|
+
result[var] = session.instance_variable_get(v)
|
88
|
+
end
|
89
|
+
sanitize_hash(result)
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def sanitize_hash(hash)
|
95
|
+
return {} if hash.nil?
|
96
|
+
hash.reject { |key, val| !ensure_json_able(val) }
|
97
|
+
end
|
98
|
+
|
99
|
+
def ensure_json_able(value)
|
100
|
+
begin
|
101
|
+
value.to_json
|
102
|
+
true && value.instance_values.all? { |e| ensure_json_able(e)}
|
103
|
+
rescue Exception => e
|
104
|
+
false
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|