def test_logger(): fn = setup_file('test_logger.log') rep = LogReporter( filename=fn, show_hidden_frames=False) try: int('a') except: exc_data = collector.collect_exception(*sys.exc_info()) else: assert 0 rep.report(exc_data) content = open(fn).read() assert len(content.splitlines()) == 4 assert 'ValueError' in content assert 'int' in content assert 'test_reporter.py' in content assert 'test_logger' in content try: 1 / 0 except: exc_data = collector.collect_exception(*sys.exc_info()) else: assert 0 rep.report(exc_data) content = open(fn).read() print content assert len(content.splitlines()) == 8 assert 'ZeroDivisionError' in content
def test_file(): fn = setup_file('test_file.log') f = open(fn, 'w') rep = FileReporter(file=f, show_hidden_frames=False) try: int('a') except: exc_data = collector.collect_exception(*sys.exc_info()) else: assert 0 rep.report(exc_data) f.flush() content = open(fn).read() assert len(content.splitlines()) == 4 assert 'ValueError' in content assert 'int' in content assert 'test_reporter.py' in content assert 'test_file' in content try: 1 / 0 except: exc_data = collector.collect_exception(*sys.exc_info()) else: assert 0 rep.report(exc_data) f.flush() content = open(fn).read() print content assert len(content.splitlines()) == 8 assert 'ZeroDivisionError' in content
def test_file(): fn = setup_file("test_file.log") f = open(fn, "w") rep = FileReporter(file=f, show_hidden_frames=False) try: int("a") except: exc_data = collector.collect_exception(*sys.exc_info()) else: assert 0 rep.report(exc_data) f.flush() content = open(fn).read() assert len(content.splitlines()) == 4 assert "ValueError" in content assert "int" in content assert "test_reporter.py" in content assert "test_file" in content try: 1 / 0 except: exc_data = collector.collect_exception(*sys.exc_info()) else: assert 0 rep.report(exc_data) f.flush() content = open(fn).read() print content assert len(content.splitlines()) == 8 assert "ZeroDivisionError" in content
def capture_exception(event_type="Exception", exc_info=None, level=logging.ERROR, tags=None, extra=None): """Capture the current exception""" exc_info = exc_info or sys.exc_info() # Ensure that no matter what happens, we always del the exc_info try: collected = collect_exception(*exc_info) # Check to see if this hash has been reported past the threshold # TODO: Use this in the future # cur_sec = int(time.time()) # capture_key = '%s %s' % (hash, cur_sec) frames = [] update_frame_visibility(collected.frames) for frame in collected.frames: fdata = { 'id': frame.tbid, 'filename': frame.filename, 'module': frame.modname or '?', 'function': frame.name or '?', 'lineno': frame.lineno, 'vars': frame.locals, 'context_line': frame.get_source_line(), 'with_context': frame.get_source_line(context=5), 'visible': frame.visible, } frames.append(fdata) data = { 'value': transform(collected.exception_value), 'type': collected.exception_type, 'message': ''.join(collected.exception_formatted), 'level': level, 'frames': frames, 'traceback': ''.join(traceback.format_exception(*exc_info)), } modules = [frame['module'] for frame in data['frames']] data['versions'] = lookup_versions(modules) return capture(event_type, tags=tags, data=data, extra=extra, hash=collected.identification_code) finally: del exc_info if 'collected' in locals(): del collected
def __call__(self, environ, start_response): """ This is straight copied from the original ErrorMiddleware code. Unfortunately they didnt separate out the actual exception handling into a function, so I must override... basically just adds the handle_async_exception() call """ # We want to be careful about not sending headers twice, # and the content type that the app has committed to (if there # is an exception in the iterator body of the response) if environ.get('paste.throw_errors'): return self.application(environ, start_response) environ['paste.throw_errors'] = True try: __traceback_supplement__ = errormiddleware.Supplement, self, environ sr_checker = errormiddleware.ResponseStartChecker(start_response) app_iter = self.application(environ, sr_checker) return self.make_catching_iter(app_iter, environ, sr_checker) except: exc_info = sys.exc_info() try: count = get_debug_count(environ) base_path = Request(environ).application_url + '/_debug/' exc_data = collector.collect_exception(*exc_info) exc_data.view_url = base_path + str(count) if self.reporters: for reporter in self.reporters: reporter.report(exc_data) #is_async is set by the @ajax decorator if environ.get('is_async', None): start_response('500 Internal Server Error', [('content-type', 'application/json; charset=utf8')], exc_info) response = handle_async_exception(exc_info, environ) else: start_response('500 Internal Server Error', [('content-type', 'text/html; charset=utf8')], exc_info) # @@: it would be nice to deal with bad content types here response = self.exception_handler(exc_info, environ) if isinstance(response, unicode): response = response.encode('utf8') return [response] finally: # clean up locals... exc_info = None
def capture_exception(event_type="Exception", exc_info=None, level=logging.ERROR, tags=None, extra=None): """Capture the current exception""" exc_info = exc_info or sys.exc_info() # Ensure that no matter what happens, we always del the exc_info try: collected = collect_exception(*exc_info) # Check to see if this hash has been reported past the threshold # TODO: Use this in the future # cur_sec = int(time.time()) # capture_key = '%s %s' % (hash, cur_sec) frames = [] update_frame_visibility(collected.frames) for frame in collected.frames: fdata = { 'id': frame.tbid, 'filename': frame.filename, 'module': frame.modname or '?', 'function': frame.name or '?', 'lineno': frame.lineno, 'vars': frame.locals, 'context_line': frame.get_source_line(), 'with_context': frame.get_source_line(context=5), 'visible': frame.visible, } frames.append(fdata) data = { 'value': transform(collected.exception_value), 'type': collected.exception_type, 'message': ''.join(collected.exception_formatted), 'level': level, 'frames': frames, 'traceback': ''.join(traceback.format_exception(*exc_info)), } modules = [frame['module'] for frame in data['frames']] data['versions'] = lookup_versions(modules) return capture(event_type, tags=tags, data=data, extra=extra, hash=collected.identification_code) finally: del exc_info if 'collected' in locals(): del collected
def format(type='html', **ops): data = collector.collect_exception(*sys.exc_info()) report = getattr(formatter, 'format_' + type)(data, **ops) # report[1] is some head data (if any), like CSS or Javascript return report[0]
def respond(self, environ, start_response): req = Request(environ) if req.environ.get('paste.throw_errors'): return self.application(environ, start_response) base_path = req.application_url + '/_debug' req.environ['paste.throw_errors'] = True started = [] def detect_start_response(status, headers, exc_info=None): try: return start_response(status, headers, exc_info) except: raise else: started.append(True) try: __traceback_supplement__ = errormiddleware.Supplement, self, environ app_iter = self.application(environ, detect_start_response) # Don't create a list from a paste.fileapp object if isinstance(app_iter, fileapp._FileIter): return app_iter try: return_iter = list(app_iter) return return_iter finally: if hasattr(app_iter, 'close'): app_iter.close() except: exc_info = sys.exc_info() # Tell the Registry to save its StackedObjectProxies current state # for later restoration ## FIXME: needs to be more abstract (something in the environ) ## to remove the Paste dependency registry.restorer.save_registry_state(environ) count = get_debug_count(environ) view_uri = self.make_view_url(environ, base_path, count) if not started: headers = [('content-type', 'text/html')] headers.append(('X-Debug-URL', view_uri)) start_response('500 Internal Server Error', headers, exc_info) environ['wsgi.errors'].write('Debug at: %s\n' % view_uri) exc_data = collector.collect_exception(*exc_info) exc_data.view_url = view_uri if self.reporters: for reporter in reporters: reporter.report(exc_data) debug_info = DebugInfo(count, exc_info, exc_data, base_path, environ, view_uri, self.error_template, self.templating_formatters, self.head_html, self.footer_html, self.libraries) assert count not in self.debug_infos self.debug_infos[count] = debug_info if self.xmlhttp_key: if self.xmlhttp_key in req.params: exc_data = collector.collect_exception(*exc_info) html, extra_html = formatter.format_html( exc_data, include_hidden_frames=False, include_reusable=False, show_extra_data=False) return [html, extra_html] # @@: it would be nice to deal with bad content types here return debug_info.content()
def handle_exception(exc_info, error_stream, html=True, debug_mode=False, error_email=None, error_log=None, show_exceptions_in_wsgi_errors=False, error_email_from='errors@localhost', smtp_server='localhost', smtp_username=None, smtp_password=None, smtp_use_tls=False, error_subject_prefix='', error_message=None, simple_html_error=False, reporters=None, show_error_reason=False ): """ For exception handling outside of a web context Use like:: import sys import paste import paste.error_middleware try: do stuff except: paste.error_middleware.exception_handler( sys.exc_info(), paste.CONFIG, sys.stderr, html=False) If you want to report, but not fully catch the exception, call ``raise`` after ``exception_handler``, which (when given no argument) will reraise the exception. """ reported = False exc_data = collector.collect_exception(*exc_info) extra_data = '' if error_email: rep = reporter.EmailReporter( to_addresses=error_email, from_address=error_email_from, smtp_server=smtp_server, smtp_username=smtp_username, smtp_password=smtp_password, smtp_use_tls=smtp_use_tls, subject_prefix=error_subject_prefix) rep_err = send_report(rep, exc_data, html=html) if rep_err: extra_data += rep_err else: reported = True if reporters: for rep in reporters: rep_err = send_report(rep, exc_data, html=html) if rep_err: extra_data += rep_err else: ## FIXME: should this be true? reported = True if error_log: rep = reporter.LogReporter( filename=error_log) rep_err = send_report(rep, exc_data, html=html) if rep_err: extra_data += rep_err else: reported = True if show_exceptions_in_wsgi_errors: rep = reporter.FileReporter( file=error_stream) rep_err = send_report(rep, exc_data, html=html) if rep_err: extra_data += rep_err else: reported = True else: error_stream.write('Error - %s: %s\n' % ( exc_data.exception_type, exc_data.exception_value)) if html: if debug_mode and simple_html_error: return_error = formatter.format_html( exc_data, include_hidden_frames=False, include_reusable=False, show_extra_data=False) reported = True elif debug_mode and not simple_html_error: error_html = formatter.format_html( exc_data, include_hidden_frames=True, include_reusable=False) head_html = '' return_error = error_template( head_html, error_html, extra_data) extra_data = '' reported = True else: default_msg = ''' An error occurred. See the error logs for more information. ''' if not show_error_reason: default_msg += '''(Turn debug on to display exception reports here)''' msg = error_message or default_msg if show_error_reason: extra = "%s - %s" % (exc_data.exception_type, exc_data.exception_value) extra = cgi.escape(extra).encode('ascii', 'xmlcharrefreplace') else: extra = '' return_error = error_template('', msg, extra) else: return_error = None if not reported and error_stream: err_report = formatter.format_text(exc_data, show_hidden_frames=True)[0] err_report += '\n' + '-'*60 + '\n' error_stream.write(err_report) if extra_data: error_stream.write(extra_data) return return_error
def handle_exception( exc_info, error_stream, html=True, debug_mode=False, error_email=None, error_log=None, show_exceptions_in_wsgi_errors=False, error_email_from='errors@localhost', smtp_server='localhost', smtp_username=None, smtp_password=None, smtp_use_tls=False, error_subject_prefix='', error_message=None, simple_html_error=False, reporters=None, ): """ For exception handling outside of a web context Use like:: import sys import paste import paste.error_middleware try: do stuff except: paste.error_middleware.exception_handler( sys.exc_info(), paste.CONFIG, sys.stderr, html=False) If you want to report, but not fully catch the exception, call ``raise`` after ``exception_handler``, which (when given no argument) will reraise the exception. """ reported = False exc_data = collector.collect_exception(*exc_info) extra_data = '' if error_email: rep = reporter.EmailReporter(to_addresses=error_email, from_address=error_email_from, smtp_server=smtp_server, smtp_username=smtp_username, smtp_password=smtp_password, smtp_use_tls=smtp_use_tls, subject_prefix=error_subject_prefix) rep_err = send_report(rep, exc_data, html=html) if rep_err: extra_data += rep_err else: reported = True if reporters: for rep in reporters: rep_err = send_report(rep, exc_data, html=html) if rep_err: extra_data += rep_err else: ## FIXME: should this be true? reported = True if error_log: rep = reporter.LogReporter(filename=error_log) rep_err = send_report(rep, exc_data, html=html) if rep_err: extra_data += rep_err else: reported = True if show_exceptions_in_wsgi_errors: rep = reporter.FileReporter(file=error_stream) rep_err = send_report(rep, exc_data, html=html) if rep_err: extra_data += rep_err else: reported = True else: error_stream.write('Error - %s: %s\n' % (exc_data.exception_type, exc_data.exception_value)) if html: if debug_mode and simple_html_error: return_error = formatter.format_html(exc_data, include_hidden_frames=False, include_reusable=False, show_extra_data=False) reported = True elif debug_mode and not simple_html_error: error_html = formatter.format_html(exc_data, include_hidden_frames=True, include_reusable=False) head_html = '' return_error = error_template(head_html, error_html, extra_data) extra_data = '' reported = True else: msg = error_message or ''' An error occurred. See the error logs for more information. (Turn debug on to display exception reports here) ''' return_error = error_template('', msg, '') else: return_error = None if not reported and error_stream: err_report = formatter.format_text(exc_data, show_hidden_frames=True)[0] err_report += '\n' + '-' * 60 + '\n' error_stream.write(err_report) if extra_data: error_stream.write(extra_data) return return_error
def format(type='html', **ops): data = collector.collect_exception(*sys.exc_info()) report = getattr(formatter, 'format_' + type)(data, **ops) # report[1] is some head data (if any), like CSS or Javascript return report[0]
def respond(self, environ, start_response): """ This is straight copied from the original ErrorMiddleware code. Unfortunately they didnt separate out the actual exception handling into a function, so I must override... basically just adds the handle_async_exception() call """ req = Request(environ) if req.environ.get('paste.throw_errors'): return self.application(environ, start_response) base_path = req.application_url + '/_debug' req.environ['paste.throw_errors'] = True started = [] def detect_start_response(status, headers, exc_info=None): try: return start_response(status, headers, exc_info) except: raise else: started.append(True) try: __traceback_supplement__ = errormiddleware.Supplement, self, environ app_iter = self.application(environ, detect_start_response) # Don't create a list from a paste.fileapp object if isinstance(app_iter, fileapp._FileIter): return app_iter try: return_iter = list(app_iter) return return_iter finally: if hasattr(app_iter, 'close'): app_iter.close() except: exc_info = sys.exc_info() is_async = environ.get('is_async', None) == True content_type = is_async and 'application/json' or 'text/html' # Tell the Registry to save its StackedObjectProxies current state # for later restoration registry.restorer.save_registry_state(environ) count = get_debug_count(environ) view_uri = self.make_view_url(environ, base_path, count) if not started: headers = [('content-type', content_type)] headers.append(('X-Debug-URL', view_uri)) start_response('500 Internal Server Error', headers, exc_info) environ['wsgi.errors'].write('Debug at: %s\n' % view_uri) exc_data = collector.collect_exception(*exc_info) exc_data.view_url = view_uri if self.reporters: for reporter in self.reporters: reporter.report(exc_data) debug_info = DebugInfo(count, exc_info, exc_data, base_path, environ, view_uri, self.error_template, self.templating_formatters, self.head_html, self.footer_html, self.libraries) assert count not in self.debug_infos self.debug_infos[count] = debug_info if is_async: return [handle_async_exception(exc_info, environ, debug_info=debug_info)] # @@: it would be nice to deal with bad content types here return debug_info.content()