summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Vrbanac <john.vrbanac@rackspace.com>2015-06-01 18:24:22 -0500
committerJohn Vrbanac <john.vrbanac@rackspace.com>2015-06-03 19:12:53 -0500
commitd3159f1d6bec06845b152de836793f4454d95804 (patch)
tree39b6776ad87cd3014daae890ce5e8f3cc589001e
parent17d5357003f65249aebbf6ee08bf38cc6bf40b63 (diff)
downloadpecan-d3159f1d6bec06845b152de836793f4454d95804.tar.gz
Allowing tracebacks to be surfaced through abort
Currently, anytime abort(...) is called, It raises a new exception which then suppresses any existing tracebacks. This causes error monitoring systems like NewRelic to report back worthless surface-level tracebacks that have nothing to do with the application. This change allows for the exception type to change, but keep the existing traceback (if one exists). This allows for monitoring systems to see a real traceback that can be correlated to logged information. Change-Id: Ibe6eb37e25b74d1dcfca76dfc1f5bbce28d34e85
-rw-r--r--pecan/core.py25
-rw-r--r--pecan/tests/test_base.py15
2 files changed, 34 insertions, 6 deletions
diff --git a/pecan/core.py b/pecan/core.py
index a6525ca..14b9ad3 100644
--- a/pecan/core.py
+++ b/pecan/core.py
@@ -8,6 +8,7 @@ from mimetypes import guess_type, add_type
from os.path import splitext
import logging
import operator
+import sys
import types
import six
@@ -123,12 +124,24 @@ def abort(status_code=None, detail='', headers=None, comment=None, **kw):
:param comment: A comment to include in the response.
'''
- raise exc.status_map[status_code](
- detail=detail,
- headers=headers,
- comment=comment,
- **kw
- )
+ # If there is a traceback, we need to catch it for a re-raise
+ try:
+ _, _, traceback = sys.exc_info()
+ webob_exception = exc.status_map[status_code](
+ detail=detail,
+ headers=headers,
+ comment=comment,
+ **kw
+ )
+
+ if six.PY3:
+ raise webob_exception.with_traceback(traceback)
+ else:
+ # Using exec to avoid python 3 parsers from crashing
+ exec('raise webob_exception, None, traceback')
+ finally:
+ # Per the suggestion of the Python docs, delete the traceback object
+ del traceback
def redirect(location=None, internal=False, code=None, headers={},
diff --git a/pecan/tests/test_base.py b/pecan/tests/test_base.py
index e6adf0e..785b522 100644
--- a/pecan/tests/test_base.py
+++ b/pecan/tests/test_base.py
@@ -3,6 +3,7 @@
import sys
import os
import json
+import traceback
import warnings
import webob
@@ -1121,6 +1122,20 @@ class TestAbort(PecanTestCase):
r = app.get('/', status=401)
assert r.status_int == 401
+ def test_abort_keeps_traceback(self):
+ last_exc, last_traceback = None, None
+
+ try:
+ try:
+ raise Exception('Bottom Exception')
+ except:
+ abort(404)
+ except Exception:
+ last_exc, _, last_traceback = sys.exc_info()
+
+ assert last_exc is HTTPNotFound
+ assert 'Bottom Exception' in traceback.format_tb(last_traceback)[-1]
+
class TestScriptName(PecanTestCase):