This is an automated email from the ASF dual-hosted git repository.

joemcdonnell pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/impala.git


The following commit(s) were added to refs/heads/master by this push:
     new ad8f468  IMPALA-8860: Improve /log_level usability on WebUI
ad8f468 is described below

commit ad8f468871d3a893bf4c7b702025ec70765ce8e1
Author: Zoltan Garaguly <zgarag...@cloudera.com>
AuthorDate: Tue May 12 15:20:08 2020 +0200

    IMPALA-8860: Improve /log_level usability on WebUI
    
    Add glog level fetching logic and fetch glog level on every request
    which allows:
     - showing glog level on page load/reload
     - showing current glog level in "Log level" combo box
     - showing current glog level in text format
    
    Add log4j log levels fetching logic and fetch all java class log levels
    on every request:
     -  log4j levels for all java classes previously set are shown on page
        as a list, fetching of individual class log levels not needed
        anymore
    
    Page layout standardization:
     - glog/log4j part has similar layout
     - using terms of frontend/backend logs
    
    Change-Id: I2fbf2ef21f4af297913a4e9b16a391768624da33
    Reviewed-on: http://gerrit.cloudera.org:8080/15903
    Reviewed-by: Impala Public Jenkins <impala-public-jenk...@cloudera.com>
    Tested-by: Impala Public Jenkins <impala-public-jenk...@cloudera.com>
---
 be/src/util/logging-support.cc                     | 80 +++++++++++-----------
 common/thrift/Logging.thrift                       | 18 ++---
 .../java/org/apache/impala/util/GlogAppender.java  | 36 ++++++----
 tests/webserver/test_web_pages.py                  | 41 ++++-------
 www/log_level.tmpl                                 | 53 +++++++-------
 5 files changed, 113 insertions(+), 115 deletions(-)

diff --git a/be/src/util/logging-support.cc b/be/src/util/logging-support.cc
index 9d0232d..d05d8dc 100644
--- a/be/src/util/logging-support.cc
+++ b/be/src/util/logging-support.cc
@@ -86,7 +86,7 @@ int FLAGS_v_original_value;
 
 static jclass log4j_logger_class_;
 // Jni method descriptors corresponding to getLogLevel() and setLogLevel() 
operations.
-static jmethodID get_log_level_method; // GlogAppender.getLogLevel()
+static jmethodID get_log_levels_method; // GlogAppender.getLogLevels()
 static jmethodID set_log_level_method; // GlogAppender.setLogLevel()
 static jmethodID reset_log_levels_method; // GlogAppender.resetLogLevels()
 
@@ -98,27 +98,18 @@ void AddDocumentMember(const string& message, const char* 
member,
   document->AddMember(key, output, document->GetAllocator());
 }
 
-template<class F>
-Webserver::UrlCallback MakeCallback(const F& fnc, bool display_log4j_handlers) 
{
-  return [fnc, display_log4j_handlers](const auto& req, auto* doc) {
-    // Display log4j log level handlers only when display_log4j_handlers is 
true.
-    if (display_log4j_handlers) AddDocumentMember("true", 
"include_log4j_handlers", doc);
-    (*fnc)(req, doc);
-  };
-}
-
 void InitDynamicLoggingSupport() {
   JNIEnv* env = JniUtil::GetJNIEnv();
   ABORT_IF_ERROR(JniUtil::GetGlobalClassRef(env, 
"org/apache/impala/util/GlogAppender",
         &log4j_logger_class_));
-  JniMethodDescriptor get_log_level_method_desc =
-      {"getLogLevel", "([B)Ljava/lang/String;", &get_log_level_method};
+  JniMethodDescriptor get_log_levels_method_desc =
+      {"getLogLevels", "()[B", &get_log_levels_method};
   JniMethodDescriptor set_log_level_method_desc =
       {"setLogLevel", "([B)Ljava/lang/String;", &set_log_level_method};
   JniMethodDescriptor reset_log_level_method_desc =
       {"resetLogLevels", "()V", &reset_log_levels_method};
   ABORT_IF_ERROR(JniUtil::LoadStaticJniMethod(
-      env, log4j_logger_class_, &get_log_level_method_desc));
+      env, log4j_logger_class_, &get_log_levels_method_desc));
   ABORT_IF_ERROR(JniUtil::LoadStaticJniMethod(
       env, log4j_logger_class_, &set_log_level_method_desc));
   ABORT_IF_ERROR(JniUtil::LoadStaticJniMethod(
@@ -132,38 +123,28 @@ void InitDynamicLoggingSupport() {
       [](const char* flagname, int value) { return value >= 0 && value <= 3; 
});
 }
 
-// Helper method to get the log level of given Java class. It is a JNI wrapper 
around
-// GlogAppender.getLogLevel().
-Status GetJavaLogLevel(const TGetJavaLogLevelParams& params, string* result) {
-  return JniCall::static_method(log4j_logger_class_, get_log_level_method)
-      .with_thrift_arg(params).Call(result);
-}
-
 Status ResetJavaLogLevels() {
   return JniCall::static_method(log4j_logger_class_, 
reset_log_levels_method).Call();
 }
 
-// Callback handler for /get_java_loglevel.
-void GetJavaLogLevelCallback(const Webserver::WebRequest& req, Document* 
document) {
-  const auto& args = req.parsed_args;
-  Webserver::ArgumentMap::const_iterator log_getclass = args.find("class");
-  if (log_getclass == args.end() || log_getclass->second.empty()) {
-    AddDocumentMember("Invalid input class name", "error", document);
-    return;
-  }
-  string result;
-  TGetJavaLogLevelParams params;
-  params.__set_class_name(log_getclass->second);
-  Status status = GetJavaLogLevel(params, &result);
+void GetJavaLogLevels(Document* document) {
+  TGetJavaLogLevelsResult result;
+
+  Status status =
+    JniCall::static_method(log4j_logger_class_, 
get_log_levels_method).Call(&result);
+
   if (!status.ok()) {
     AddDocumentMember(status.GetDetail(), "error", document);
     return;
   }
-  if (result.empty()) {
-    AddDocumentMember("Invalid input class name", "error", document);
-    return;
+
+  string log_levels;
+  for (const string& logLevel: result.log_levels) {
+    log_levels.append(logLevel);
+    log_levels.append("\n");
   }
-  AddDocumentMember(result, "get_java_loglevel_result", document);
+
+  AddDocumentMember(log_levels, "get_java_loglevel_result", document);
 }
 
 // Callback handler for /set_java_loglevel.
@@ -205,6 +186,19 @@ void ResetJavaLogLevelCallback(const 
Webserver::WebRequest& req, Document* docum
   AddDocumentMember("Java log levels reset.", "reset_java_loglevel_result", 
document);
 }
 
+void GetGlogLevel(Document* document) {
+  string log_level;
+
+  if (google::GetCommandLineOption("v", &log_level)) {
+    AddDocumentMember(log_level, "glog_level", document);
+  }
+  else {
+    AddDocumentMember(to_string(FLAGS_v_original_value), "glog_level", 
document);
+  }
+
+  AddDocumentMember(to_string(FLAGS_v_original_value), "default_glog_level", 
document);
+}
+
 // Callback handler for /set_glog_level
 void SetGlogLevelCallback(const Webserver::WebRequest& req, Document* 
document) {
   const auto& args = req.parsed_args;
@@ -221,7 +215,6 @@ void SetGlogLevelCallback(const Webserver::WebRequest& req, 
Document* document)
     return;
   }
   AddDocumentMember(new_log_level, "set_glog_level_result", document);
-  AddDocumentMember(to_string(FLAGS_v_original_value), "default_glog_level", 
document);
 }
 
 // Callback handler for /reset_glog_level
@@ -231,8 +224,19 @@ void ResetGlogLevelCallback(const Webserver::WebRequest& 
req, Document* document
   AddDocumentMember(new_log_level, "reset_glog_level_result", document);
 }
 
+template<class F>
+Webserver::UrlCallback MakeCallback(const F& fnc, bool display_log4j_handlers) 
{
+  return [fnc, display_log4j_handlers](const auto& req, auto* doc) {
+    // Display log4j log level handlers only when display_log4j_handlers is 
true.
+    if (display_log4j_handlers) AddDocumentMember("true", 
"include_log4j_handlers", doc);
+    (*fnc)(req, doc);
+    if (display_log4j_handlers) {GetJavaLogLevels(doc);}
+    GetGlogLevel(doc);
+  };
 }
 
+} // namespace
+
 namespace impala {
 
 void InitJvmLoggingSupport() {
@@ -321,8 +325,6 @@ void RegisterLogLevelCallbacks(Webserver* webserver, bool 
register_log4j_handler
   webserver->RegisterUrlCallback("/reset_glog_level", "log_level.tmpl",
       MakeCallback(&ResetGlogLevelCallback, register_log4j_handlers), false);
   if (!register_log4j_handlers) return;
-  webserver->RegisterUrlCallback("/get_java_loglevel", "log_level.tmpl",
-      MakeCallback(&GetJavaLogLevelCallback, register_log4j_handlers), false);
   webserver->RegisterUrlCallback("/set_java_loglevel", "log_level.tmpl",
       MakeCallback(&SetJavaLogLevelCallback, register_log4j_handlers), false);
   webserver->RegisterUrlCallback("/reset_java_loglevel", "log_level.tmpl",
diff --git a/common/thrift/Logging.thrift b/common/thrift/Logging.thrift
index b7c51ae..6335667 100644
--- a/common/thrift/Logging.thrift
+++ b/common/thrift/Logging.thrift
@@ -31,15 +31,17 @@ enum TLogLevel {
   FATAL = 6
 }
 
-// Helper structs for GetJavaLogLevel(), SetJavaLogLevel() methods.
-// These are used as input params to get/set the logging level of a
-// particular Java class at runtime using GlogAppender.getLogLevel()
-// and GlogAppender.setLogLevel() methods.
-struct TGetJavaLogLevelParams {
-  1: required string class_name
-}
-
+// Helper structs for GetJavaLogLevels(), SetJavaLogLevel() methods.
+// These are used as:
+// - input param to set the logging level of a particular Java class
+// at runtime using GlogAppender.setLogLevel()
+// - return value as a list of Java classes with corresponding
+// logging levels set before using GlogAppender.getLogLevels()
 struct TSetJavaLogLevelParams {
   1: required string class_name
   2: required string log_level
 }
+
+struct TGetJavaLogLevelsResult {
+  1: required list<string> log_levels
+}
diff --git a/fe/src/main/java/org/apache/impala/util/GlogAppender.java 
b/fe/src/main/java/org/apache/impala/util/GlogAppender.java
index 2eb33f3..82c6c79 100644
--- a/fe/src/main/java/org/apache/impala/util/GlogAppender.java
+++ b/fe/src/main/java/org/apache/impala/util/GlogAppender.java
@@ -17,6 +17,9 @@
 
 package org.apache.impala.util;
 
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
 import java.util.Properties;
 
 import org.apache.log4j.AppenderSkeleton;
@@ -30,7 +33,7 @@ import org.apache.impala.common.InternalException;
 import org.apache.impala.common.ImpalaException;
 import org.apache.impala.common.JniUtil;
 import org.apache.impala.service.BackendConfig;
-import org.apache.impala.thrift.TGetJavaLogLevelParams;
+import org.apache.impala.thrift.TGetJavaLogLevelsResult;
 import org.apache.impala.thrift.TSetJavaLogLevelParams;
 import org.apache.impala.thrift.TLogLevel;
 import org.apache.thrift.protocol.TBinaryProtocol;
@@ -139,17 +142,6 @@ public class GlogAppender extends AppenderSkeleton {
   }
 
   /**
-   * Get the log4j log level corresponding to a serialized 
TGetJavaLogLevelParams.
-   */
-  public static String getLogLevel(byte[] serializedParams) throws 
ImpalaException {
-    TGetJavaLogLevelParams thriftParams = new TGetJavaLogLevelParams();
-    JniUtil.deserializeThrift(protocolFactory_, thriftParams, 
serializedParams);
-    String className = thriftParams.getClass_name();
-    if (Strings.isNullOrEmpty(className)) return null;
-    return Logger.getLogger(className).getEffectiveLevel().toString();
-  }
-
-  /**
    * Sets the logging level of a class as per serialized 
TSetJavaLogLevelParams.
    */
   public static String setLogLevel(byte[] serializedParams) throws 
ImpalaException {
@@ -171,4 +163,24 @@ public class GlogAppender extends AppenderSkeleton {
     Install(TLogLevel.values()[BackendConfig.INSTANCE.getImpalaLogLevel()],
         
TLogLevel.values()[BackendConfig.INSTANCE.getNonImpalaJavaVlogLevel()]);
   }
+
+  /**
+   * Get all the previously set log4j log levels.
+   */
+  public static byte[] getLogLevels() throws ImpalaException {
+    Enumeration<Logger> allLoggers = LogManager.getCurrentLoggers();
+    List<String> logLevels = new ArrayList<String>();
+
+    while (allLoggers.hasMoreElements()) {
+      Logger logger = allLoggers.nextElement();
+      if (logger.getLevel() != null) {
+        logLevels.add(logger.getName() + " : " + logger.getLevel());
+      }
+    }
+
+    TGetJavaLogLevelsResult result = new TGetJavaLogLevelsResult();
+    result.setLog_levels(logLevels);
+
+    return JniUtil.serializeToThrift(result, protocolFactory_);
+  }
 };
diff --git a/tests/webserver/test_web_pages.py 
b/tests/webserver/test_web_pages.py
index 6fa6cea..b93dfa1 100644
--- a/tests/webserver/test_web_pages.py
+++ b/tests/webserver/test_web_pages.py
@@ -31,7 +31,6 @@ import requests
 class TestWebPage(ImpalaTestSuite):
 
   ROOT_URL = "http://localhost:{0}/";
-  GET_JAVA_LOGLEVEL_URL = "http://localhost:{0}/get_java_loglevel";
   SET_JAVA_LOGLEVEL_URL = "http://localhost:{0}/set_java_loglevel";
   RESET_JAVA_LOGLEVEL_URL = "http://localhost:{0}/reset_java_loglevel";
   SET_GLOG_LOGLEVEL_URL = "http://localhost:{0}/set_glog_level";
@@ -201,49 +200,31 @@ class TestWebPage(ImpalaTestSuite):
     malformed inputs. This however does not test that the log level changes 
are actually
     in effect."""
     # Check that the log_level end points are accessible.
-    self.get_and_check_status_jvm(self.GET_JAVA_LOGLEVEL_URL)
     self.get_and_check_status_jvm(self.SET_JAVA_LOGLEVEL_URL)
     self.get_and_check_status_jvm(self.RESET_JAVA_LOGLEVEL_URL)
     self.get_and_check_status(self.SET_GLOG_LOGLEVEL_URL)
     self.get_and_check_status(self.RESET_GLOG_LOGLEVEL_URL)
-    # Try getting log level of a class.
-    get_loglevel_url = (self.GET_JAVA_LOGLEVEL_URL + "?class" +
-        "=org.apache.impala.catalog.HdfsTable")
-    self.get_and_check_status_jvm(get_loglevel_url, "DEBUG")
 
     # Set the log level of a class to TRACE and confirm the setting is in place
     set_loglevel_url = (self.SET_JAVA_LOGLEVEL_URL + "?class" +
         "=org.apache.impala.catalog.HdfsTable&level=trace")
-    self.get_and_check_status_jvm(set_loglevel_url, "Effective log level: 
TRACE")
+    self.get_and_check_status_jvm(
+      set_loglevel_url,
+      "org.apache.impala.catalog.HdfsTable : TRACE")
 
-    get_loglevel_url = (self.GET_JAVA_LOGLEVEL_URL + "?class" +
-        "=org.apache.impala.catalog.HdfsTable")
-    self.get_and_check_status_jvm(get_loglevel_url, "TRACE")
-    # Check the log level of a different class and confirm it is still DEBUG
-    get_loglevel_url = (self.GET_JAVA_LOGLEVEL_URL + "?class" +
-        "=org.apache.impala.catalog.HdfsPartition")
-    self.get_and_check_status_jvm(get_loglevel_url, "DEBUG")
-
-    # Reset Java logging levels and check the logging level of the class again
+    # Reset Java logging levels
     self.get_and_check_status_jvm(self.RESET_JAVA_LOGLEVEL_URL, "Java log 
levels reset.")
-    get_loglevel_url = (self.GET_JAVA_LOGLEVEL_URL + "?class" +
-        "=org.apache.impala.catalog.HdfsTable")
-    self.get_and_check_status_jvm(get_loglevel_url, "DEBUG")
 
     # Set a new glog level and make sure the setting has been applied.
     set_glog_url = (self.SET_GLOG_LOGLEVEL_URL + "?glog=3")
-    self.get_and_check_status(set_glog_url, "v set to 3")
+    self.get_and_check_status(set_glog_url, "val(3)")
 
     # Try resetting the glog logging defaults again.
-    self.get_and_check_status(self.RESET_GLOG_LOGLEVEL_URL, "v set to ")
-
-    # Try to get the log level of an empty class input
-    get_loglevel_url = (self.GET_JAVA_LOGLEVEL_URL + "?class=")
-    self.get_and_check_status_jvm(get_loglevel_url)
+    self.get_and_check_status(self.RESET_GLOG_LOGLEVEL_URL, "Current backend 
log level: ")
 
     # Same as above, for set log level request
     set_loglevel_url = (self.SET_JAVA_LOGLEVEL_URL + "?class=")
-    self.get_and_check_status_jvm(get_loglevel_url)
+    self.get_and_check_status_jvm(set_loglevel_url)
 
     # Empty input for setting a glog level request
     set_glog_url = (self.SET_GLOG_LOGLEVEL_URL + "?glog=")
@@ -254,7 +235,9 @@ class TestWebPage(ImpalaTestSuite):
     # Level.toLevel() method.
     set_loglevel_url = (self.SET_JAVA_LOGLEVEL_URL + "?class" +
         "=org.apache.impala.catalog.HdfsTable&level=foo&")
-    self.get_and_check_status_jvm(set_loglevel_url, "Effective log level: 
DEBUG")
+    self.get_and_check_status_jvm(
+      set_loglevel_url,
+      "org.apache.impala.catalog.HdfsTable : DEBUG")
 
     # Try setting an invalid glog level.
     set_glog_url = self.SET_GLOG_LOGLEVEL_URL + "?glog=foo"
@@ -274,11 +257,11 @@ class TestWebPage(ImpalaTestSuite):
     self.get_and_check_status(self.RESET_GLOG_LOGLEVEL_URL)
     # Set log level to 3.
     set_glog_url = (self.SET_GLOG_LOGLEVEL_URL + "?glog=3")
-    self.get_and_check_status(set_glog_url, "v set to 3")
+    self.get_and_check_status(set_glog_url, "val(3)")
     # Check that Impala doesn't crash when running a query that aggregates.
     self.client.execute("select avg(int_col) from functional.alltypessmall")
     # Reset log level.
-    self.get_and_check_status(self.RESET_GLOG_LOGLEVEL_URL, "v set to ")
+    self.get_and_check_status(self.RESET_GLOG_LOGLEVEL_URL, "Current backend 
log level: ")
 
   def test_catalog(self, cluster_properties, unique_database):
     """Tests the /catalog and /catalog_object endpoints."""
diff --git a/www/log_level.tmpl b/www/log_level.tmpl
index f3b3059..7cd9772 100644
--- a/www/log_level.tmpl
+++ b/www/log_level.tmpl
@@ -26,15 +26,10 @@ under the License.
 </style>
 
 {{?include_log4j_handlers}}
-<h2>Change Java log level (log4j)</h2>
+<h2>Frontend log level configuration (log4j)</h2>
 <div class="log-level">
-<form action="get_java_loglevel">{{>www/form-hidden-inputs.tmpl}}
-  <div class="form-group">
-    <input type="text" class="form-control" name="class" placeholder="e.g. 
org.apache.impala.analysis.Analyzer">
-  </div>
-  <button type="submit" class="btn btn-primary btn-sm">Get Java Log 
Level</button>
-  <label>{{get_java_loglevel_result}}</label>
-</form>
+<h5>Current frontend log level:</h5>
+<span style="white-space: pre-line">{{get_java_loglevel_result}}</span>
 <br>
 <form action="set_java_loglevel">{{>www/form-hidden-inputs.tmpl}}
   <div class="form-group" name="level">
@@ -52,46 +47,50 @@ under the License.
         <option value="trace">TRACE</option>
         <option value="warn">WARN</option>
       </select>
-      <button type="submit" class="btn btn-primary btn-sm">Set Java Log 
Level</button>
-      {{?set_java_loglevel_result}}
-      <strong> Effective log level: {{set_java_loglevel_result}}</strong>
-      {{/set_java_loglevel_result}}
+      <button type="submit" class="btn btn-primary btn-sm">Set Frontend Log 
Level</button>
     </div>
   </div>
 </form>
 <form action="reset_java_loglevel">{{>www/form-hidden-inputs.tmpl}}
   <div class="col-xs-20">
-    <button type="submit" class="btn btn-primary btn-sm">Reset Java Log 
Levels</button>
+    <button type="submit" class="btn btn-primary btn-sm">Reset Frontend Log 
Levels</button>
     <strong>{{reset_java_loglevel_result}}</strong>
   </div>
 </form>
+<br>
 {{/include_log4j_handlers}}
 
-<h2>Change backend logging level (glog)</h2>
+<h2>Backend log level configuration (glog)</h2>
+<h5>Current backend log level: <span id="glog_text"></span></h5>
 <form action="set_glog_level">{{>www/form-hidden-inputs.tmpl}}
   <div class="form-group" name="level">
     <div class="col-xs-20">
       <label>Log level:</label>
       <select name="glog" class="selectpicker" data-style="btn-primary btn-sm">
-        <option value="0">0</option>
-        <option value="1">1</option>
-        <option value="2">2</option>
-        <option value="3">3</option>
+        <option value="0">0 - Off</option>
+        <option value="1">1 - Info</option>
+        <option value="2">2 - Debug</option>
+        <option value="3">3 - All</option>
       </select>
-      <button type="submit" class="btn btn-primary btn-sm">Set Glog 
Level</button>
-      {{?set_glog_level_result}}
-      <strong>&nbsp &nbsp Glog level for --{{set_glog_level_result}}</strong>
-      <strong>&nbsp &nbsp Default glog level: {{default_glog_level}}</strong>
-      {{/set_glog_level_result}}
+      <button type="submit" class="btn btn-primary btn-sm">Set Backend Log 
Level</button>
     </div>
   </div>
 </form>
 <form action="reset_glog_level">{{>www/form-hidden-inputs.tmpl}}
   <div class="col-xs-20">
-    <button type="submit" class="btn btn-primary btn-sm">Reset Glog 
Levels</button>
-    {{?reset_glog_level_result}}
-    <strong> &nbsp &nbsp Glog logging level for 
--{{reset_glog_level_result}}</strong>
-    {{/reset_glog_level_result}}
+    <button type="submit" class="btn btn-primary btn-sm">Reset Backend Log 
Level</button>
+    <strong>&nbsp &nbsp Default backend log level: 
{{default_glog_level}}</strong>
   </div>
 </form>
+
+<script>
+
+  $(document).ready(function() {
+    $('select[name=glog]').val({{glog_level}});
+    var text=$('select[name=glog]').children("option:selected").text();
+    document.getElementById("glog_text").innerHTML = text;
+  });
+
+</script>
+
 {{>www/common-footer.tmpl}}

Reply via email to