Browse Source

HUE-3808 [core] Offer to live turn on/off debug level

Here is the idea: https://www.dropbox.com/s/9ix1qprb2g8wc7k/demo-live-debug-level.mkv?dl=0

    turn on / off
    show hostname
    restarting Hue removes it, was worried that leaking the state in the os env might bite back
Romain Rigaux 10 năm trước cách đây
mục cha
commit
a50c369

+ 29 - 2
desktop/core/src/desktop/log/__init__.py

@@ -34,7 +34,7 @@ from desktop.log.formatter import MessageOnlyFormatter
 DEFAULT_LOG_DIR = 'logs'
 LOG_FORMAT = '[%(asctime)s] %(module)-12s %(levelname)-8s %(message)s'
 DATE_FORMAT = '%d/%b/%Y %H:%M:%S %z'
-
+FORCE_DEBUG = False
 CONF_RE = re.compile('%LOG_DIR%|%PROC_NAME%')
 
 _log_dir = None
@@ -127,6 +127,8 @@ def basic_logging(proc_name, log_dir=None):
 
   This removes all previously installed logging handlers.
   """
+  global FORCE_DEBUG
+
   # Setup log_dir
   if not log_dir:
     log_dir = os.getenv("DESKTOP_LOG_DIR", DEFAULT_LOG_DIR)
@@ -159,7 +161,7 @@ def basic_logging(proc_name, log_dir=None):
 
   # Handle env variables
   env_loglevel = os.getenv("DESKTOP_LOGLEVEL")
-  env_debug = os.getenv('DESKTOP_DEBUG')
+  env_debug = os.getenv('DESKTOP_DEBUG') or FORCE_DEBUG
   if env_debug:
     env_loglevel = 'DEBUG'
 
@@ -197,3 +199,28 @@ def fancy_logging():
   buffer_handler.setFormatter(_formatter)
   root_logger = logging.getLogger()
   root_logger.addHandler(buffer_handler)
+
+
+def get_all_debug():
+  from desktop.settings import ENV_DESKTOP_DEBUG # Circular dependency
+  global FORCE_DEBUG
+
+  return FORCE_DEBUG or os.getenv(ENV_DESKTOP_DEBUG) != None
+
+
+def set_all_debug():
+  from desktop.settings import ENV_DESKTOP_DEBUG, ENV_HUE_PROCESS_NAME # Circular dependency
+  global FORCE_DEBUG
+
+  FORCE_DEBUG = True
+  basic_logging(os.environ[ENV_HUE_PROCESS_NAME])
+  fancy_logging()
+
+
+def reset_all_debug():
+  from desktop.settings import ENV_DESKTOP_DEBUG, ENV_HUE_PROCESS_NAME # Circular dependency
+  global FORCE_DEBUG
+
+  FORCE_DEBUG = False
+  basic_logging(os.environ[ENV_HUE_PROCESS_NAME])
+  fancy_logging()

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

@@ -221,7 +221,7 @@ TEMPLATE_CONTEXT_PROCESSORS = (
 # of having multiple apps.  If your app needs
 # to store data related to users, it should
 # manage its own table with an appropriate foreign key.
-AUTH_PROFILE_MODULE=None
+AUTH_PROFILE_MODULE = None
 
 LOGIN_REDIRECT_URL = "/"
 LOGOUT_REDIRECT_URL = "/" # For djangosaml2 bug.

+ 47 - 1
desktop/core/src/desktop/templates/logs.mako

@@ -68,7 +68,14 @@ ${layout.menubar(section='log_view')}
         <input type="text" class="input-xxlarge search-query" placeholder="${_('Search in the logs')}" value="${query}">
       </%def>
       <%def name="creation()">
-        <label class="checkbox" style="display: inline-block; margin-right: 10px"><input id="wrapLogs" type="checkbox" checked="checked">${_('Wrap logs')}</label>
+        ${ _('Host') }: <span style="display: inline-block; margin-right: 10px">${ hostname }</span>
+
+        <label class="checkbox" for="forcedDebug" style="display: inline-block; margin-right: 10px">${_('Force DEBUG level')}</label>
+        <input type="checkbox" id="forcedDebug" data-bind="checked: forcedDebug" style="vertical-align: middle">
+
+        <label class="checkbox" for="wrap" style="display: inline-block; margin-right: 10px">${_('Wrap logs')}</label>
+        <input id="wrapLogs" id="wrap" type="checkbox" checked="checked">
+
         <a href="/desktop/download_logs" class="btn"><i class="fa fa-download"></i> ${_('Download entire log as zip')}</a>
       </%def>
     </%actionbar:render>
@@ -85,8 +92,47 @@ ${layout.menubar(section='log_view')}
 
 </div>
 
+<script src="${ static('desktop/ext/js/knockout.min.js') }" type="text/javascript" charset="utf-8"></script>
+
+
 <script>
+  var LiveDebugging = function () {
+    var self = this;
+
+    self.forcedDebug = ko.observable(false);
+    self.forcedDebug.subscribe(function(newValue) {
+      self.toggleLogLevel();
+    });
+
+    self.getDebugLevel = function() {
+      $.get("/desktop/get_debug_level", function(data) { self.forcedDebug(data.debug_all); });
+    };
+
+    self.toggleLogLevel = function() {
+      var _url = "";
+      if (self.forcedDebug()) {
+        _url = "/desktop/set_all_debug";
+      } else {
+        _url = "/desktop/reset_all_debug";
+      }
+
+      $.post(_url, {}, function(data) {
+        if (data,status != 0) {
+          $(document).trigger("error", data.message);
+        }
+      }).fail(function (xhr, textStatus, errorThrown) {
+        $(document).trigger("error", xhr.responseText);
+      });
+    };
+  }
+
+  var viewModel;
+
   $(document).ready(function () {
+    viewModel = new LiveDebugging();
+    ko.applyBindings(viewModel);
+
+    viewModel.getDebugLevel();
 
     resizeScrollingLogs();
 

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

@@ -75,6 +75,9 @@ dynamic_patterns += patterns('desktop.views',
   (r'^logs$','log_view'),
   (r'^desktop/dump_config$','dump_config'),
   (r'^desktop/download_logs$','download_log_view'),
+  (r'^desktop/get_debug_level','get_debug_level'),
+  (r'^desktop/set_all_debug','set_all_debug'),
+  (r'^desktop/reset_all_debug','reset_all_debug'),
   (r'^bootstrap.js$', 'bootstrap'), # unused
 
   (r'^desktop/prefs/(?P<key>\w+)?$', 'prefs'),

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

@@ -20,6 +20,7 @@ import json
 import logging
 import os
 import re
+import socket
 import sys
 import tempfile
 import time
@@ -33,7 +34,7 @@ from django.core.urlresolvers import reverse
 from django.core.servers.basehttp import FileWrapper
 from django.shortcuts import redirect
 from django.utils.translation import ugettext as _
-from django.views.decorators.http import require_http_methods
+from django.views.decorators.http import require_http_methods, require_POST
 import django.views.debug
 
 import desktop.conf
@@ -49,10 +50,12 @@ from desktop.lib.i18n import smart_str
 from desktop.lib.paths import get_desktop_root
 from desktop.lib.thread_util import dump_traceback
 from desktop.log.access import access_log_level, access_warn
+from desktop.log import set_all_debug as _set_all_debug, reset_all_debug as _reset_all_debug, get_all_debug as _get_all_debug
 from desktop.models import UserPreferences, Settings
 from desktop import appmanager
 
 
+
 LOG = logging.getLogger(__name__)
 
 
@@ -99,12 +102,13 @@ def log_view(request):
   if not request.user.is_superuser:
     return HttpResponse(_("You must be a superuser."))
 
+  hostname = socket.gethostname()
   l = logging.getLogger()
   for h in l.handlers:
     if isinstance(h, desktop.log.log_buffer.FixedBufferHandler):
-      return render('logs.mako', request, dict(log=[l for l in h.buf], query=request.GET.get("q", "")))
+      return render('logs.mako', request, dict(log=[l for l in h.buf], query=request.GET.get("q", ""), hostname=hostname))
 
-  return render('logs.mako', request, dict(log=[_("No logs found!")], query=''))
+  return render('logs.mako', request, dict(log=[_("No logs found!")], query='', hostname=hostname))
 
 @access_log_level(logging.WARN)
 def download_log_view(request):
@@ -523,6 +527,31 @@ def check_config_ajax(request):
                 dict(error_list=error_list),
                 force_template=True)
 
+
+def get_debug_level(request):
+  return JsonResponse({'status': 0, 'debug_all': _get_all_debug()})
+
+
+@require_POST
+def set_all_debug(request):
+  if not request.user.is_superuser:
+    return JsonResponse({'status': 1, 'message': _('You must be a superuser.')})
+
+  _set_all_debug()
+
+  return JsonResponse({'status': 0, 'debug_all': True})
+
+
+@require_POST
+def reset_all_debug(request):
+  if not request.user.is_superuser:
+    return JsonResponse({'status': 1, 'message': _('You must be a superuser.')})
+
+  _reset_all_debug()
+
+  return JsonResponse({'status': 0, 'debug_all': False})
+
+
 # This is a global non-view for inline KO i18n
 def _ko(str=""):
   return _(str).replace("'", "\\'")