Module: ExceptionHandling
- Defined in:
- lib/exception_handling.rb,
lib/exception_handling/mailer.rb,
lib/exception_handling/methods.rb,
lib/exception_handling/testing.rb,
lib/exception_handling/version.rb
Overview
some useful test objects
Defined Under Namespace
Modules: Methods, Testing Classes: ClientLoggingError, ExceptionFilters, Mailer, MailerTimeout, Warning
Constant Summary collapse
- SUMMARY_THRESHOLD =
5- SUMMARY_PERIOD =
1.hour
60*60
- SECTIONS =
[:request, :session, :environment, :backtrace, :event_response]
- ENVIRONMENT_WHITELIST =
[ /^HTTP_/, /^QUERY_/, /^REQUEST_/, /^SERVER_/ ]
- ENVIRONMENT_OMIT =
( "CONTENT_TYPE: application/x-www-form-urlencoded\nGATEWAY_INTERFACE: CGI/1.2\nHTTP_ACCEPT: */*\nHTTP_ACCEPT: */*, text/javascript, text/html, application/xml, text/xml, */*\nHTTP_ACCEPT_CHARSET: ISO-8859-1,utf-8;q=0.7,*;q=0.7\nHTTP_ACCEPT_ENCODING: gzip, deflate\nHTTP_ACCEPT_ENCODING: gzip,deflate\nHTTP_ACCEPT_LANGUAGE: en-us\nHTTP_CACHE_CONTROL: no-cache\nHTTP_CONNECTION: Keep-Alive\nHTTP_HOST: www.invoca.com\nHTTP_MAX_FORWARDS: 10\nHTTP_UA_CPU: x86\nHTTP_VERSION: HTTP/1.1\nHTTP_X_FORWARDED_HOST: www.invoca.com\nHTTP_X_FORWARDED_SERVER: www2.invoca.com\nHTTP_X_REQUESTED_WITH: XMLHttpRequest\nLANG:\nLANG:\nPATH: /sbin:/usr/sbin:/bin:/usr/bin\nPWD: /\nRAILS_ENV: production\nRAW_POST_DATA: id=500\nREMOTE_ADDR: 10.251.34.225\nSCRIPT_NAME: /\nSERVER_NAME: www.invoca.com\nSERVER_PORT: 80\nSERVER_PROTOCOL: HTTP/1.1\nSERVER_SOFTWARE: Mongrel 1.1.4\nSHLVL: 1\nTERM: linux\nTERM: xterm-color\n_: /usr/bin/mongrel_cluster_ctl\n" ).split("\n")
- AUTHENTICATION_HEADERS =
['HTTP_AUTHORIZATION','X-HTTP_AUTHORIZATION','X_HTTP_AUTHORIZATION','REDIRECT_X_HTTP_AUTHORIZATION']
- VERSION =
"1.0.3"
Class Attribute Summary collapse
-
.current_controller ⇒ Object
internal settings (don’t set directly).
-
.custom_data_hook ⇒ Object
Returns the value of attribute custom_data_hook.
-
.email_environment ⇒ Object
Returns the value of attribute email_environment.
-
.escalation_recipients ⇒ Object
optional settings.
-
.eventmachine_safe ⇒ Object
Returns the value of attribute eventmachine_safe.
-
.eventmachine_synchrony ⇒ Object
Returns the value of attribute eventmachine_synchrony.
-
.exception_recipients ⇒ Object
Returns the value of attribute exception_recipients.
-
.filter_list_filename ⇒ Object
Returns the value of attribute filter_list_filename.
-
.last_exception_timestamp ⇒ Object
Returns the value of attribute last_exception_timestamp.
-
.logger ⇒ Object
Returns the value of attribute logger.
-
.mailer_send_enabled ⇒ Object
Returns the value of attribute mailer_send_enabled.
-
.periodic_exception_intervals ⇒ Object
Returns the value of attribute periodic_exception_intervals.
-
.post_log_error_hook ⇒ Object
Returns the value of attribute post_log_error_hook.
-
.sender_address ⇒ Object
Returns the value of attribute sender_address.
-
.server_name ⇒ Object
required settings.
-
.stub_handler ⇒ Object
Returns the value of attribute stub_handler.
Class Method Summary collapse
- .enhance_exception_data(data) ⇒ Object
- .ensure_completely_safe(exception_context = "") ⇒ Object
- .ensure_escalation(email_subject) ⇒ Object
- .ensure_safe(exception_context = "") ⇒ Object
- .escalate_error(exception_or_string, email_subject) ⇒ Object
- .escalate_warning(message, email_subject) ⇒ Object
-
.extract_and_merge_controller_data(controller, data) ⇒ Object
Pull certain fields out of the controller and add to the data hash.
- .log_debug(message) ⇒ Object
-
.log_error(exception_or_string, exception_context = '', controller = nil, treat_as_local = false) ⇒ Object
Normal Operation: Called directly by our code, usually from rescue blocks.
-
.log_error_rack(exception, env, rack_filter) ⇒ Object
Gets called by Rack Middleware: DebugExceptions or ShowExceptions it does 2 things: log the error email the error.
- .log_info(message) ⇒ Object
- .log_periodically(exception_key, interval, message) ⇒ Object
- .log_warning(message) ⇒ Object
- .set_log_error_timestamp ⇒ Object
- .should_send_email? ⇒ Boolean
- .trace_timing(description) ⇒ Object
-
.write_exception_to_log(ex, exception_context, timestamp) ⇒ Object
Write an exception out to the log file using our own custom format.
Class Attribute Details
.current_controller ⇒ Object
internal settings (don’t set directly)
139 140 141 |
# File 'lib/exception_handling.rb', line 139 def current_controller @current_controller end |
.custom_data_hook ⇒ Object
Returns the value of attribute custom_data_hook.
106 107 108 |
# File 'lib/exception_handling.rb', line 106 def custom_data_hook @custom_data_hook end |
.email_environment ⇒ Object
Returns the value of attribute email_environment.
101 102 103 |
# File 'lib/exception_handling.rb', line 101 def email_environment @email_environment end |
.escalation_recipients ⇒ Object
optional settings
100 101 102 |
# File 'lib/exception_handling.rb', line 100 def escalation_recipients @escalation_recipients end |
.eventmachine_safe ⇒ Object
Returns the value of attribute eventmachine_safe.
104 105 106 |
# File 'lib/exception_handling.rb', line 104 def eventmachine_safe @eventmachine_safe end |
.eventmachine_synchrony ⇒ Object
Returns the value of attribute eventmachine_synchrony.
105 106 107 |
# File 'lib/exception_handling.rb', line 105 def eventmachine_synchrony @eventmachine_synchrony end |
.exception_recipients ⇒ Object
Returns the value of attribute exception_recipients.
78 79 80 |
# File 'lib/exception_handling.rb', line 78 def exception_recipients @exception_recipients end |
.filter_list_filename ⇒ Object
Returns the value of attribute filter_list_filename.
102 103 104 |
# File 'lib/exception_handling.rb', line 102 def filter_list_filename @filter_list_filename end |
.last_exception_timestamp ⇒ Object
Returns the value of attribute last_exception_timestamp.
140 141 142 |
# File 'lib/exception_handling.rb', line 140 def end |
.logger ⇒ Object
Returns the value of attribute logger.
79 80 81 |
# File 'lib/exception_handling.rb', line 79 def logger @logger end |
.mailer_send_enabled ⇒ Object
Returns the value of attribute mailer_send_enabled.
103 104 105 |
# File 'lib/exception_handling.rb', line 103 def mailer_send_enabled @mailer_send_enabled end |
.periodic_exception_intervals ⇒ Object
Returns the value of attribute periodic_exception_intervals.
141 142 143 |
# File 'lib/exception_handling.rb', line 141 def periodic_exception_intervals @periodic_exception_intervals end |
.post_log_error_hook ⇒ Object
Returns the value of attribute post_log_error_hook.
107 108 109 |
# File 'lib/exception_handling.rb', line 107 def post_log_error_hook @post_log_error_hook end |
.sender_address ⇒ Object
Returns the value of attribute sender_address.
77 78 79 |
# File 'lib/exception_handling.rb', line 77 def sender_address @sender_address end |
.server_name ⇒ Object
required settings
76 77 78 |
# File 'lib/exception_handling.rb', line 76 def server_name @server_name end |
.stub_handler ⇒ Object
Returns the value of attribute stub_handler.
108 109 110 |
# File 'lib/exception_handling.rb', line 108 def stub_handler @stub_handler end |
Class Method Details
.enhance_exception_data(data) ⇒ Object
335 336 337 338 339 340 341 342 343 |
# File 'lib/exception_handling.rb', line 335 def enhance_exception_data(data) return if ! ExceptionHandling.custom_data_hook begin ExceptionHandling.custom_data_hook.call(data) rescue Exception => ex # can't call log_error here or we will blow the call stack log_info( "Unable to execute custom custom_data_hook callback. #{ex.message} #{ex.backtrace.each {|l| "#{l}\n"}}" ) end end |
.ensure_completely_safe(exception_context = "") ⇒ Object
280 281 282 283 284 285 286 |
# File 'lib/exception_handling.rb', line 280 def ensure_completely_safe( exception_context = "" ) yield rescue SystemExit, SystemStackError, NoMemoryError, SecurityError, SignalException raise rescue Exception => ex log_error ex, exception_context end |
.ensure_escalation(email_subject) ⇒ Object
300 301 302 303 304 305 306 307 |
# File 'lib/exception_handling.rb', line 300 def ensure_escalation(email_subject) begin yield rescue => ex escalate_error(ex, email_subject) nil end end |
.ensure_safe(exception_context = "") ⇒ Object
273 274 275 276 277 278 |
# File 'lib/exception_handling.rb', line 273 def ensure_safe( exception_context = "" ) yield rescue => ex log_error ex, exception_context return nil end |
.escalate_error(exception_or_string, email_subject) ⇒ Object
288 289 290 291 292 |
# File 'lib/exception_handling.rb', line 288 def escalate_error(exception_or_string, email_subject) ex = make_exception(exception_or_string) log_error(ex) escalate(email_subject, ex, ExceptionHandling.) end |
.escalate_warning(message, email_subject) ⇒ Object
294 295 296 297 298 |
# File 'lib/exception_handling.rb', line 294 def escalate_warning(, email_subject) ex = Warning.new() log_error(ex) escalate(email_subject, ex, ExceptionHandling.) end |
.extract_and_merge_controller_data(controller, data) ⇒ Object
Pull certain fields out of the controller and add to the data hash.
246 247 248 249 250 251 252 253 254 255 256 257 258 259 |
# File 'lib/exception_handling.rb', line 246 def extract_and_merge_controller_data(controller, data) data[:request] = { :params => controller.request.parameters.to_hash, :rails_root => defined?(Rails) ? Rails.root : "Rails.root not defined. Is this a test environment?", :url => controller.complete_request_uri } data[:environment].merge!(controller.request.env.to_hash) controller.session[:fault_in_session] data[:session] = { :key => controller.request.[:id], :data => controller.session.dup } end |
.log_debug(message) ⇒ Object
269 270 271 |
# File 'lib/exception_handling.rb', line 269 def log_debug( ) ExceptionHandling.logger.debug( ) end |
.log_error(exception_or_string, exception_context = '', controller = nil, treat_as_local = false) ⇒ Object
Normal Operation:
Called directly by our code, usually from rescue blocks.
Does two things: write to log file and send an email
Functional Test Operation:
Calls into handle_stub_log_error and returns. no log file. no email.
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
# File 'lib/exception_handling.rb', line 184 def log_error(exception_or_string, exception_context = '', controller = nil, treat_as_local = false) begin ex = make_exception(exception_or_string) = data = exception_to_data(ex, exception_context, ) if stub_handler return stub_handler.handle_stub_log_error(data) end write_exception_to_log(ex, exception_context, ) if treat_as_local return end if should_send_email? controller ||= current_controller if block_given? # the expectation is that if the caller passed a block then they will be # doing their own merge of hash values into data begin yield data rescue Exception => ex data.merge!(:environment => "Exception in yield: #{ex.class}:#{ex}") end elsif controller # most of the time though, this method will not get passed a block # and additional hash data is extracted from the controller extract_and_merge_controller_data(controller, data) end log_error_email(data, ex) end rescue LogErrorStub::UnexpectedExceptionLogged, LogErrorStub::ExpectedExceptionNotLogged raise rescue Exception => ex $stderr.puts("ExceptionHandling.log_error rescued exception while logging #{exception_context}: #{exception_or_string}:\n#{ex.class}: #{ex}\n#{ex.backtrace.join("\n")}") write_exception_to_log(ex, "ExceptionHandling.log_error rescued exception while logging #{exception_context}: #{exception_or_string}", ) end end |
.log_error_rack(exception, env, rack_filter) ⇒ Object
Gets called by Rack Middleware: DebugExceptions or ShowExceptions it does 2 things:
log the error
email the error
but not during functional tests, when rack middleware is not used
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
# File 'lib/exception_handling.rb', line 151 def log_error_rack(exception, env, rack_filter) = exception_data = exception_to_data(exception, env, ) if stub_handler return stub_handler.handle_stub_log_error(exception_data) end # TODO: add a more interesting custom description, like: # custom_description = ": caught and processed by Rack middleware filter #{rack_filter}" # which would be nice, but would also require changing quite a few tests custom_description = "" write_exception_to_log(exception, custom_description, ) if should_send_email? controller = env['action_controller.instance'] # controller may not exist in some cases (like most 404 errors) if controller extract_and_merge_controller_data(controller, exception_data) controller.session["last_exception_timestamp"] = ExceptionHandling. end log_error_email(exception_data, exception) end end |
.log_info(message) ⇒ Object
265 266 267 |
# File 'lib/exception_handling.rb', line 265 def log_info( ) ExceptionHandling.logger.info( ) end |
.log_periodically(exception_key, interval, message) ⇒ Object
326 327 328 329 330 331 332 333 |
# File 'lib/exception_handling.rb', line 326 def log_periodically(exception_key, interval, ) self.periodic_exception_intervals ||= {} last_logged = self.periodic_exception_intervals[exception_key] if !last_logged || ( (last_logged + interval) < Time.now ) log_error( ) self.periodic_exception_intervals[exception_key] = Time.now end end |
.log_warning(message) ⇒ Object
261 262 263 |
# File 'lib/exception_handling.rb', line 261 def log_warning( ) log_error( Warning.new() ) end |
.set_log_error_timestamp ⇒ Object
309 310 311 |
# File 'lib/exception_handling.rb', line 309 def ExceptionHandling. = Time.now.to_i end |
.should_send_email? ⇒ Boolean
313 314 315 |
# File 'lib/exception_handling.rb', line 313 def should_send_email? ExceptionHandling.mailer_send_enabled end |
.trace_timing(description) ⇒ Object
317 318 319 320 321 322 323 324 |
# File 'lib/exception_handling.rb', line 317 def trace_timing(description) result = nil time = Benchmark.measure do result = yield end log_info "#{description} %.4fs " % time.real result end |
.write_exception_to_log(ex, exception_context, timestamp) ⇒ Object
Write an exception out to the log file using our own custom format.
231 232 233 234 235 236 237 238 239 240 241 |
# File 'lib/exception_handling.rb', line 231 def write_exception_to_log(ex, exception_context, ) ActiveSupport::Deprecation.silence do ExceptionHandling.logger.fatal( if ActionView::TemplateError === ex "#{ex} Error:#{timestamp}" else "\n(Error:#{timestamp}) #{ex.class} #{exception_context} (#{ex.message}):\n " + clean_backtrace(ex).join("\n ") + "\n\n" end ) end end |