浏览代码

HUE-882 [core] Add stack trace and logs link to 500 and PopUpExceptions pages

- Added stack trace with source exception data (given the majority of the code reraises with PopupException)
- Added link to logs
abec 13 年之前
父节点
当前提交
6d5418f

+ 14 - 2
desktop/core/src/desktop/lib/exceptions.py

@@ -15,6 +15,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import sys
+import traceback
+
 from thrift.transport.TTransport import TTransportException
 
 # Need full import statement
@@ -34,6 +37,10 @@ class StructuredException(Exception):
     self.data = data
     self.error_code = error_code
 
+    # Traceback is only relevant if an exception was thrown, caught, and we reraise with this exception.
+    (type, value, tb) = sys.exc_info()
+    self.traceback = traceback.extract_tb(tb)
+
   def __str__(self):
     return "%s (code %s): %s" % (self.message, self.code, repr(self.data))
 
@@ -41,7 +48,8 @@ class StructuredException(Exception):
   def response_data(self):
     return dict(code=self.code,
                 message=self.message,
-                data=self.data)
+                data=self.data,
+                traceback=self.traceback)
 
 class MessageException(StructuredException):
   """
@@ -68,8 +76,12 @@ class PopupException(Exception):
     self.detail = detail
     self.error_code = error_code
 
+    # Traceback is only relevant if an exception was thrown, caught, and we reraise with this exception.
+    (type, value, tb) = sys.exc_info()
+    self.traceback = traceback.extract_tb(tb)
+
   def response(self, request):
-    data = dict(title=self.title, message=self.message, detail=self.detail)
+    data = dict(title=self.title, message=self.message, detail=self.detail, traceback=self.traceback)
     if not request.ajax:
       data['request'] = request
     response = desktop.lib.django_util.render("popup_error.mako", request, data)

+ 38 - 0
desktop/core/src/desktop/templates/500.mako

@@ -14,6 +14,7 @@
 ## See the License for the specific language governing permissions and
 ## limitations under the License.
 <%!
+from desktop.lib.i18n import smart_unicode
 from desktop.views import commonheader, commonfooter
 from django.utils.translation import ugettext as _
 %>
@@ -22,6 +23,43 @@ ${commonheader(_('Error'), "", user)}
   <div class="container-fluid">
     <h1>${_('Server Error (500)')}</h1>
     <p>${_("Sorry, there's been an error. An email was sent to your administrators. Thank you for your patience.")}</p>
+    <div class="details">
+    % if traceback:
+      <a href="javascript:toggleDisplay('#traceback');"><i class="icon-share-alt"></i> ${_('More Info')}</a>
+      &nbsp;
+      <a href="/logs" target="_new">${_('View Logs')}</a>
+      <br />
+      <br />
+      <div id="traceback" class="hide">
+        <table class="table table-striped" style="background: white; border: 1px solid #DDDDDD;">
+          <thead>
+            <tr>
+              <td>${_("File Name")}</td>
+              <td>${_("Line Number")}</td>
+            <td>${_("Function Name")}</td>
+            </tr>
+          </thead>
+          <tbody>
+            % for (file_name, line_number, function_name, text) in traceback:
+              <tr>
+                <td>${smart_unicode(file_name) or "" | h}</td>
+                <td>${smart_unicode(line_number) or "" | h}</td>
+                <td>${smart_unicode(function_name) or "" | h}</td>
+              </tr>
+            % endfor
+          </tbody>
+        </table>
+      </div>
+    % else:
+      <a href="/logs" target="_new">${_('View Logs')}</a>
+    % endif
+    </div>
   </div>
 
+  <script type="text/javascript">
+    function toggleDisplay(selector) {
+      $(selector).slideToggle(500);
+    }
+  </script>
+
 ${commonfooter(messages)}

+ 49 - 12
desktop/core/src/desktop/templates/popup_error.mako

@@ -21,22 +21,59 @@ from django.utils.translation import ugettext as _
 
 ${commonheader(title, "", user)}
 
+  <div class="container-fluid">
+    <div class="alert">
+      <p><strong>${smart_unicode(message) | h}</strong></p>
 
-	<div class="container-fluid">
-		<div class="alert">
-			<p><strong>${smart_unicode(message) | h}</strong></p>
+      % if detail:
+      <p>${smart_unicode(detail) or "" | h}</p>
+      % endif
 
-			% if detail:
-			<p>${smart_unicode(detail) or "" | h}</p>
-			% endif
+    </div>
 
-			<div class="alert-actions">
-				<br/>
-				<a class="btn small" href="javascript:window.history.back(-1)">${_('Go back')}</a>
-			</div>
-		</div>
+    <div class="details">
+      % if traceback:
+        <a href="javascript:toggleDisplay('#traceback');"><i class="icon-share-alt"></i> ${_('More Info')}</a>
+        &nbsp;
+        <a href="/logs" target="_new">${_('View Logs')}</a>
+        <br />
+        <br />
+        <div id="traceback" class="hide">
+          <table class="table table-striped" style="background: white; border: 1px solid #DDDDDD;">
+            <thead>
+              <tr>
+                <td>${_("File Name")}</td>
+                <td>${_("Line Number")}</td>
+              <td>${_("Function Name")}</td>
+              </tr>
+            </thead>
+            <tbody>
+              % for (file_name, line_number, function_name, text) in traceback:
+                <tr>
+                  <td>${smart_unicode(file_name) or "" | h}</td>
+                  <td>${smart_unicode(line_number) or "" | h}</td>
+                  <td>${smart_unicode(function_name) or "" | h}</td>
+                </tr>
+              % endfor
+            </tbody>
+          </table>
+        </div>
+      % else:
+        <a href="/logs" target="_new">${_('View Logs')}</a>
+        <br />
+        <br />
+      % endif
+    </div>
 
+    <div class="alert-actions">
+      <a class="btn small" href="javascript:window.history.back(-1)">${_('Go back')}</a>
+    </div>
+  </div>
 
-	</div>
+  <script type="text/javascript">
+    function toggleDisplay(selector) {
+      $(selector).slideToggle(500);
+    }
+  </script>
 
 ${commonfooter(messages)}

+ 1 - 1
desktop/core/src/desktop/views.py

@@ -218,7 +218,7 @@ def serve_500_error(request, *args, **kwargs):
   """Registered handler for 500. We use the debug view to make debugging easier."""
   if desktop.conf.HTTP_500_DEBUG_MODE.get():
     return django.views.debug.technical_500_response(request, *sys.exc_info())
-  return render("500.mako", request, {})
+  return render("500.mako", request, {'traceback': traceback.extract_tb(sys.exc_info()[2])})
 
 _LOG_LEVELS = {
   "critical": logging.CRITICAL,

+ 16 - 0
desktop/core/static/css/hue2.css

@@ -186,6 +186,22 @@ h1 {
     background-color: #01639c;
 }
 
+a.toggle-display-link:link {
+  color: black; text-decoration: none;
+}
+
+a.toggle-display-link:active {
+  color: black; text-decoration: none;
+}
+
+a.toggle-display-link:visited {
+  color: black; text-decoration: none;
+}
+
+a.toggle-display-link:hover {
+  color: black; text-decoration: none;
+}
+
 .withTitle {
     top: 60px!important;
 }