contrast-exceptional 0.0.1 → 0.0.6
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.
- 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
|