Bläddra i källkod

HADOOP-18653. LogLevel servlet to determine log impl before using setLevel (#5456)

The log level can only be set on Log4J log implementations;
probes are used to downgrade to a warning when other
logging back ends are used

Contributed by Viraj Jasani
Viraj Jasani 2 år sedan
förälder
incheckning
aff840c59c

+ 9 - 2
hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/log/LogLevel.java

@@ -34,6 +34,8 @@ import javax.servlet.http.HttpServletResponse;
 
 import org.apache.hadoop.classification.VisibleForTesting;
 import org.apache.hadoop.thirdparty.com.google.common.base.Charsets;
+import org.slf4j.LoggerFactory;
+
 import org.apache.hadoop.HadoopIllegalArgumentException;
 import org.apache.hadoop.classification.InterfaceAudience;
 import org.apache.hadoop.classification.InterfaceStability;
@@ -44,6 +46,7 @@ import org.apache.hadoop.security.authentication.client.AuthenticatedURL;
 import org.apache.hadoop.security.authentication.client.KerberosAuthenticator;
 import org.apache.hadoop.security.ssl.SSLFactory;
 import org.apache.hadoop.util.GenericOptionsParser;
+import org.apache.hadoop.util.GenericsUtil;
 import org.apache.hadoop.util.ServletUtil;
 import org.apache.hadoop.util.Tool;
 import org.apache.hadoop.util.ToolRunner;
@@ -338,14 +341,18 @@ public class LogLevel {
         out.println(MARKER
             + "Submitted Class Name: <b>" + logName + "</b><br />");
 
-        Logger log = Logger.getLogger(logName);
+        org.slf4j.Logger log = LoggerFactory.getLogger(logName);
         out.println(MARKER
             + "Log Class: <b>" + log.getClass().getName() +"</b><br />");
         if (level != null) {
           out.println(MARKER + "Submitted Level: <b>" + level + "</b><br />");
         }
 
-        process(log, level, out);
+        if (GenericsUtil.isLog4jLogger(logName)) {
+          process(Logger.getLogger(logName), level, out);
+        } else {
+          out.println("Sorry, setting log level is only supported for log4j loggers.<br />");
+        }
       }
 
       out.println(FORMS);

+ 26 - 2
hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/util/GenericsUtil.java

@@ -20,6 +20,7 @@ package org.apache.hadoop.util;
 
 import java.lang.reflect.Array;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.apache.hadoop.classification.InterfaceAudience;
 import org.apache.hadoop.classification.InterfaceStability;
@@ -33,6 +34,14 @@ import org.slf4j.LoggerFactory;
 @InterfaceStability.Unstable
 public class GenericsUtil {
 
+  private static final String SLF4J_LOG4J_ADAPTER_CLASS = "org.slf4j.impl.Log4jLoggerAdapter";
+
+  /**
+   * Set to false only if log4j adapter class is not found in the classpath. Once set to false,
+   * the utility method should not bother re-loading class again.
+   */
+  private static final AtomicBoolean IS_LOG4J_LOGGER = new AtomicBoolean(true);
+
   /**
    * Returns the Class object (of type <code>Class&lt;T&gt;</code>) of the  
    * argument of type <code>T</code>. 
@@ -87,12 +96,27 @@ public class GenericsUtil {
     if (clazz == null) {
       return false;
     }
-    Logger log = LoggerFactory.getLogger(clazz);
+    return isLog4jLogger(clazz.getName());
+  }
+
+  /**
+   * Determine whether the log of the given logger is of Log4J implementation.
+   *
+   * @param logger the logger name, usually class name as string.
+   * @return true if the logger uses Log4J implementation.
+   */
+  public static boolean isLog4jLogger(String logger) {
+    if (logger == null || !IS_LOG4J_LOGGER.get()) {
+      return false;
+    }
+    Logger log = LoggerFactory.getLogger(logger);
     try {
-      Class log4jClass = Class.forName("org.slf4j.impl.Log4jLoggerAdapter");
+      Class<?> log4jClass = Class.forName(SLF4J_LOG4J_ADAPTER_CLASS);
       return log4jClass.isInstance(log);
     } catch (ClassNotFoundException e) {
+      IS_LOG4J_LOGGER.set(false);
       return false;
     }
   }
+
 }

+ 1 - 1
hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/TestGenericsUtil.java

@@ -140,7 +140,7 @@ public class TestGenericsUtil {
 
   @Test
   public void testIsLog4jLogger() throws Exception {
-    assertFalse("False if clazz is null", GenericsUtil.isLog4jLogger(null));
+    assertFalse("False if clazz is null", GenericsUtil.isLog4jLogger((Class<?>) null));
     assertTrue("The implementation is Log4j",
         GenericsUtil.isLog4jLogger(TestGenericsUtil.class));
   }