Browse Source

HUE-6820 [frontend] Catch all the JS errors and send them to the backend

Enrico Berti 8 years ago
parent
commit
3554285548

+ 56 - 0
desktop/core/src/desktop/static/desktop/js/hue.errorcatcher.js

@@ -0,0 +1,56 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+(function () {
+
+  /**
+   * @param {string} [msg] - the error message
+   * @param {string} [url] - the error url
+   * @param {string} [line] - the error line number
+   * @param {string} [column] - the error column number
+   * @param {Object} [error] - available in some browsers, it contains the stack
+   */
+  window.onerror = function (msg, url, line, column, error) {
+    try {
+      console.error('Hue detected a Javascript error: ', url, line, column, msg);
+      var xmlHTTP = new XMLHttpRequest();
+      var params = {
+        msg: msg,
+        url: url,
+        line: line,
+        column: column
+      };
+      if (error && error.stack) {
+        params.stack = error.stack;
+      }
+
+      xmlHTTP.onreadystatechange = function () {
+        if (xmlHTTP.readyState == 4 && xmlHTTP.status == 200) {
+          console.warn('JS error sent correctly to the Hue logs');
+        }
+      }
+      xmlHTTP.open('POST', '/desktop/log_js_error', true);
+      xmlHTTP.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
+      if (!XMLHttpRequest.prototype.isAugmented) {
+        xmlHTTP.setRequestHeader('X-CSRFToken', window.CSRF_TOKEN); // from common_header_footer_components
+      }
+      xmlHTTP.send('jserror=' + JSON.stringify(params));
+    }
+    catch (e) {}
+    return true;
+  }
+
+})()

+ 1 - 0
desktop/core/src/desktop/templates/common_header.mako

@@ -114,6 +114,7 @@ if USE_NEW_EDITOR.get():
 
   ${ commonHeaderFooterComponents.header_i18n_redirection(user, is_s3_enabled, apps) }
 
+  <script src="${ static('desktop/js/hue.errorcatcher.js') }"></script>
   <script src="${ static('desktop/js/hue.utils.js') }"></script>
   <script src="${ static('desktop/ext/js/jquery/jquery-2.1.1.min.js') }"></script>
   <script src="${ static('desktop/js/jquery.migration.js') }"></script>

+ 8 - 6
desktop/core/src/desktop/templates/common_header_footer_components.mako

@@ -32,6 +32,12 @@ from metadata.conf import has_optimizer, OPTIMIZER
     var IS_S3_ENABLED = '${ is_s3_enabled }' === 'True';
     var HAS_OPTIMIZER = '${ has_optimizer() }' === 'True';
 
+    %if request and request.COOKIES and request.COOKIES.get('csrftoken','')!='':
+    window.CSRF_TOKEN = '${request.COOKIES.get('csrftoken')}';
+    %else:
+    window.CSRF_TOKEN = '';
+    %endif
+
     var BOOTSTRAP_RATIOS = {
       SPAN3: function () {
         var _w = $(window).width();
@@ -249,14 +255,10 @@ from metadata.conf import has_optimizer, OPTIMIZER
     //Add CSRF Token to all XHR Requests
     var xrhsend = XMLHttpRequest.prototype.send;
     XMLHttpRequest.prototype.send = function (data) {
-    %if request and request.COOKIES and request.COOKIES.get('csrftoken','')!='':
-      this.setRequestHeader('X-CSRFToken', "${request.COOKIES.get('csrftoken')}");
-    %else:
-      this.setRequestHeader('X-CSRFToken', "");
-    %endif
-
+      this.setRequestHeader('X-CSRFToken', window.CSRF_TOKEN);
       return xrhsend.apply(this, arguments);
     };
+    XMLHttpRequest.prototype.isAugmented = true;
 
     $.fn.dataTableExt.sErrMode = "throw";
 

+ 1 - 0
desktop/core/src/desktop/templates/hue.mako

@@ -57,6 +57,7 @@
     var IS_HUE_4 = true;
   </script>
 
+  <script src="${ static('desktop/js/hue.errorcatcher.js') }"></script>
   <script src="${ static('desktop/js/hue4.utils.js') }"></script>
 </head>
 

+ 1 - 0
desktop/core/src/desktop/urls.py

@@ -74,6 +74,7 @@ else:
 
 dynamic_patterns += patterns('desktop.views',
   (r'^logs$','log_view'),
+  (r'^desktop/log_js_error$','log_js_error'),
   (r'^desktop/dump_config$','dump_config'),
   (r'^desktop/download_logs$','download_log_view'),
   (r'^desktop/get_debug_level','get_debug_level'),

+ 3 - 0
desktop/core/src/desktop/views.py

@@ -145,6 +145,9 @@ def path_forbidden(request):
     'is_embeddable': request.GET.get('is_embeddable', False)
   })
 
+def log_js_error(request):
+  LOG.info('JS ERROR: ' + request.POST.get('jserror', 'Unspecified JS error'))
+  return JsonResponse({ 'status': 0 })
 
 @access_log_level(logging.WARN)
 def log_view(request):