From efc41e456f715abe57a69d6136a2d1a1098eae4c Mon Sep 17 00:00:00 2001
From: Gaetan Boismal <gaetan.boismal@forgerock.com>
Date: Fri, 19 Feb 2016 16:40:00 +0000
Subject: [PATCH] OPENDJ-2006 Add Jul to Slf4j bridge

---
 opendj-server-legacy/src/main/java/org/opends/server/loggers/DebugLogger.java                  |   21 +++++
 opendj-server-legacy/pom.xml                                                                   |   19 +++-
 opendj-server-legacy/src/main/java/org/opends/server/core/DirectoryServer.java                 |    6 +
 opendj-server-legacy/src/messages/src/org/opends/messages/Severity.java                        |   36 +++-----
 opendj-server-legacy/src/messages/org/opends/messages/config.properties                        |    4 
 opendj-server-legacy/src/main/java/org/opends/server/core/ServerContext.java                   |    7 +
 opendj-server-legacy/src/main/java/org/opends/server/loggers/ErrorLogger.java                  |   16 +++
 opendj-server-legacy/src/main/java/org/opends/server/loggers/TextErrorLogPublisher.java        |    3 
 opendj-server-legacy/src/main/java/org/opends/server/core/LoggerConfigManager.java             |  104 ++++++++++++++++++++++++++
 opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPConnectionHandler.java |    5 -
 10 files changed, 186 insertions(+), 35 deletions(-)

diff --git a/opendj-server-legacy/pom.xml b/opendj-server-legacy/pom.xml
index a15beb8..3a9a154 100644
--- a/opendj-server-legacy/pom.xml
+++ b/opendj-server-legacy/pom.xml
@@ -119,11 +119,6 @@
     </dependency>
 
     <dependency>
-      <groupId>org.slf4j</groupId>
-      <artifactId>slf4j-jdk14</artifactId>
-    </dependency>
-
-    <dependency>
       <groupId>org.forgerock.commons</groupId>
       <artifactId>forgerock-util</artifactId>
     </dependency>
@@ -174,6 +169,17 @@
       <artifactId>forgerock-audit-handler-jdbc</artifactId>
     </dependency>
 
+    <!-- slf4j libraries -->
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-jdk14</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>jul-to-slf4j</artifactId>
+    </dependency>
+
     <!-- servlet and mail -->
     <dependency>
       <groupId>javax.servlet</groupId>
@@ -549,6 +555,9 @@
               <classPathProperty>classpath.bootstrap-client</classPathProperty>
               <productJarName>${product.name.lowercase}</productJarName>
               <supportedLocales>${locales}</supportedLocales>
+              <excludes>
+                <exclude>org.slf4j:jul-to-slf4j</exclude>
+              </excludes>
               <additionalJars>
                  <additionalJar>opendj-je-backend.jar</additionalJar>
               </additionalJars>
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/core/DirectoryServer.java b/opendj-server-legacy/src/main/java/org/opends/server/core/DirectoryServer.java
index 4498235..03ad576 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/core/DirectoryServer.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/core/DirectoryServer.java
@@ -764,6 +764,12 @@
     {
       return directoryServer.commonAudit;
     }
+
+    @Override
+    public LoggerConfigManager getLoggerConfigManager()
+    {
+      return directoryServer.loggerConfigManager;
+    }
   }
 
   /**
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/core/LoggerConfigManager.java b/opendj-server-legacy/src/main/java/org/opends/server/core/LoggerConfigManager.java
index af4a40d..e2e2c3d 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/core/LoggerConfigManager.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/core/LoggerConfigManager.java
@@ -28,13 +28,18 @@
 
 import static org.opends.messages.ConfigMessages.*;
 
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.LogManager;
 
 import org.forgerock.i18n.LocalizableMessage;
 import org.forgerock.i18n.slf4j.LocalizedLogger;
 import org.forgerock.opendj.config.server.ConfigException;
 import org.forgerock.opendj.ldap.ResultCode;
+import org.opends.messages.Severity;
 import org.opends.server.admin.server.ConfigurationAddListener;
 import org.opends.server.admin.server.ConfigurationDeleteListener;
 import org.opends.server.admin.server.ServerManagementContext;
@@ -51,6 +56,7 @@
 import org.opends.server.loggers.HTTPAccessLogger;
 import org.forgerock.opendj.config.server.ConfigChangeResult;
 import org.opends.server.types.InitializationException;
+import org.slf4j.bridge.SLF4JBridgeHandler;
 
 /**
  * This class defines a utility that will be used to manage the set of loggers
@@ -64,8 +70,96 @@
 
   private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
 
+  /**
+   * Class to manage java.util.logging to slf4j bridge.
+   * Main purpose of this class is to adapt the j.u.l log level when a debug/error log publisher change is detected.
+   * <p>
+   * @ThreadSafe
+   */
+  private static class JulToSlf4jLogManager
+  {
+    private Level currentJulLogLevel = Level.OFF;
+    private final Object lock = new Object();
+
+    private Level computeJulLogLevel()
+    {
+      if (DebugLogger.getInstance().isEnabled())
+      {
+        return Level.FINEST;
+      }
+
+      for (final Severity severity : Severity.values())
+      {
+        if (ErrorLogger.isEnabledFor("", severity))
+        {
+          return errorLoggerSeverityToJulLevel(severity);
+        }
+      }
+      return Level.OFF;
+    }
+
+    private void adjustJulLevel()
+    {
+      final Level newLevel1 = computeJulLogLevel();
+      if (isMoreDetailedThanCurrentLevel(newLevel1))
+      {
+        synchronized (lock)
+        {
+          final Level newLevel2 = computeJulLogLevel();
+          if (isMoreDetailedThanCurrentLevel(newLevel2))
+          {
+            changeJulLogLevel(newLevel2);
+          }
+        }
+      }
+    }
+
+    private void changeJulLogLevel(final Level newLevel)
+    {
+      try
+      {
+        SLF4JBridgeHandler.removeHandlersForRootLogger();
+        // This is needed to avoid major performance issue. See: http://www.slf4j.org/legacy.html#jul-to-slf4j
+        LogManager.getLogManager().readConfiguration(
+                new ByteArrayInputStream((".level=" + newLevel).getBytes()));
+        SLF4JBridgeHandler.install();
+        currentJulLogLevel = newLevel;
+      }
+      catch (IOException | SecurityException e)
+      {
+        logger.error(ERR_CONFIG_CANNOT_CONFIGURE_JUL_LOGGER.get(e.getMessage()), e);
+        SLF4JBridgeHandler.removeHandlersForRootLogger();
+      }
+    }
+
+    private boolean isMoreDetailedThanCurrentLevel(final Level challenger)
+    {
+      return challenger.intValue() < currentJulLogLevel.intValue();
+    }
+
+    /** Convert OpenDJ error log severity to JUL Severity. */
+    private Level errorLoggerSeverityToJulLevel(Severity severity)
+    {
+      switch (severity)
+      {
+      case DEBUG:
+      case INFORMATION:
+      case NOTICE:
+        return Level.INFO;
+      case WARNING:
+        return Level.WARNING;
+      case ERROR:
+        return Level.SEVERE;
+      default:
+        return Level.OFF;
+      }
+    }
+  }
+
   private final ServerContext serverContext;
 
+  private final JulToSlf4jLogManager julToSlf4jManager = new JulToSlf4jLogManager();
+
   /**
    * Create the logger config manager with the provided
    * server context.
@@ -147,6 +241,7 @@
     AccessLogger.getInstance().initializeLogger(accessPublisherCfgs, serverContext);
     HTTPAccessLogger.getInstance().initializeLogger(httpAccessPublisherCfgs, serverContext);
     ErrorLogger.getInstance().initializeLogger(errorPublisherCfgs, serverContext);
+    julToSlf4jManager.adjustJulLevel();
   }
 
   /**
@@ -227,4 +322,13 @@
     ccr.setResultCode(ResultCode.UNWILLING_TO_PERFORM);
     return ccr;
   }
+
+  /**
+   * Update the current java.util.logging.Level.
+   * This level is used to filter logs from third party libraries which use j.u.l to our slf4j logger.
+   */
+  public void adjustJulLevel()
+  {
+    julToSlf4jManager.adjustJulLevel();
+  }
 }
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/core/ServerContext.java b/opendj-server-legacy/src/main/java/org/opends/server/core/ServerContext.java
index f20da28..237e377 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/core/ServerContext.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/core/ServerContext.java
@@ -106,4 +106,11 @@
    * @return the common audit manager
    */
   CommonAudit getCommonAudit();
+
+  /**
+   * Returns the logger config manager.
+   *
+   * @return the logger config manager
+   */
+  LoggerConfigManager getLoggerConfigManager();
 }
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/loggers/DebugLogger.java b/opendj-server-legacy/src/main/java/org/opends/server/loggers/DebugLogger.java
index fd0adc7..bcb4ff9 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/loggers/DebugLogger.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/loggers/DebugLogger.java
@@ -38,6 +38,7 @@
 import org.opends.server.admin.ClassPropertyDefinition;
 import org.opends.server.admin.std.meta.DebugLogPublisherCfgDefn;
 import org.opends.server.admin.std.server.DebugLogPublisherCfg;
+import org.opends.server.core.ServerContext;
 
 /**
  * A logger for debug and trace logging. DebugLogger provides a debugging
@@ -197,6 +198,7 @@
     loggerStorage.addLogPublisher(publisher);
     updateTracerSettings();
     enabled = true;
+    adjustJulLevel();
   }
 
   @Override
@@ -205,6 +207,7 @@
     boolean removed = loggerStorage.removeLogPublisher(publisher);
     updateTracerSettings();
     enabled = !loggerStorage.getLogPublishers().isEmpty();
+    adjustJulLevel();
     return removed;
   }
 
@@ -214,6 +217,24 @@
     loggerStorage.removeAllLogPublishers();
     updateTracerSettings();
     enabled = false;
+    adjustJulLevel();
   }
 
+  private void adjustJulLevel()
+  {
+    final ServerContext serverContext = getServerContext();
+    if (serverContext != null)
+    {
+      serverContext.getLoggerConfigManager().adjustJulLevel();
+    }
+  }
+
+  /**
+   * Returns whether there is at least one debug log publisher enabled.
+   * @return whether there is at least one debug log publisher enabled.
+   */
+  public boolean isEnabled()
+  {
+    return enabled;
+  }
 }
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/loggers/ErrorLogger.java b/opendj-server-legacy/src/main/java/org/opends/server/loggers/ErrorLogger.java
index 7f2a9df..ec7d53a 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/loggers/ErrorLogger.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/loggers/ErrorLogger.java
@@ -37,6 +37,7 @@
 import org.opends.server.admin.std.server.ErrorLogPublisherCfg;
 import org.opends.server.api.DirectoryThread;
 import org.opends.server.backends.task.Task;
+import org.opends.server.core.ServerContext;
 
 /**
  * This class defines the wrapper that will invoke all registered error loggers
@@ -161,17 +162,30 @@
   public final synchronized void addLogPublisher(final ErrorLogPublisher<ErrorLogPublisherCfg> publisher)
   {
     loggerStorage.addLogPublisher(publisher);
+    adjustJulLevel();
   }
 
   @Override
   public final synchronized boolean removeLogPublisher(final ErrorLogPublisher<ErrorLogPublisherCfg> publisher)
   {
-    return loggerStorage.removeLogPublisher(publisher);
+    final boolean removed = loggerStorage.removeLogPublisher(publisher);
+    adjustJulLevel();
+    return removed;
   }
 
   @Override
   public final synchronized void removeAllLogPublishers()
   {
     loggerStorage.removeAllLogPublishers();
+    adjustJulLevel();
+  }
+
+  private void adjustJulLevel()
+  {
+    final ServerContext serverContext = getServerContext();
+    if (serverContext != null)
+    {
+      serverContext.getLoggerConfigManager().adjustJulLevel();
+    }
   }
 }
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/loggers/TextErrorLogPublisher.java b/opendj-server-legacy/src/main/java/org/opends/server/loggers/TextErrorLogPublisher.java
index 9965fd0..520f3d2 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/loggers/TextErrorLogPublisher.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/loggers/TextErrorLogPublisher.java
@@ -62,6 +62,7 @@
 {
   private TextWriter writer;
   private FileBasedErrorLogPublisherCfg currentConfig;
+  private ServerContext serverContext;
 
   /**
    * Returns a new text error log publisher which will print all messages to the
@@ -105,6 +106,7 @@
   public void initializeLogPublisher(FileBasedErrorLogPublisherCfg config, ServerContext serverContext)
       throws ConfigException, InitializationException
   {
+    this.serverContext = serverContext;
     File logFile = getLogFile(config);
     FileNamingPolicy fnPolicy = new TimeStampNaming(logFile);
 
@@ -350,6 +352,7 @@
 
         currentConfig = config;
       }
+      serverContext.getLoggerConfigManager().adjustJulLevel();
     }
     catch(Exception e)
     {
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPConnectionHandler.java b/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPConnectionHandler.java
index 8eed7f0..d0a52b7 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPConnectionHandler.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPConnectionHandler.java
@@ -52,8 +52,6 @@
 import java.util.TreeSet;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.TimeUnit;
-import java.util.logging.Level;
-import java.util.logging.Logger;
 
 import org.forgerock.http.servlet.HttpFrameworkServlet;
 import org.forgerock.i18n.LocalizableMessage;
@@ -707,9 +705,6 @@
 
   private void startHttpServer() throws Exception
   {
-    // Silence Grizzly's own logging
-    Logger.getLogger("org.glassfish.grizzly").setLevel(Level.OFF);
-
     if (HTTPAccessLogger.getHTTPAccessLogPublishers().isEmpty())
     {
       logger.warn(WARN_CONFIG_LOGGER_NO_ACTIVE_HTTP_ACCESS_LOGGERS);
diff --git a/opendj-server-legacy/src/messages/org/opends/messages/config.properties b/opendj-server-legacy/src/messages/org/opends/messages/config.properties
index 2123ab5..f107696 100644
--- a/opendj-server-legacy/src/messages/org/opends/messages/config.properties
+++ b/opendj-server-legacy/src/messages/org/opends/messages/config.properties
@@ -947,4 +947,6 @@
  configuration entry %s: %s
 ERR_CONFIG_LOGGER_CANNOT_DELETE_LOGGER_736=An error occurred while \
  attempting to delete a Directory Server logger from the information in \
- configuration entry %s: %s
\ No newline at end of file
+ configuration entry %s: %s
+ERR_CONFIG_CANNOT_CONFIGURE_JUL_LOGGER_737=Cannot configure \
+ java.util.logging root logger level: %s. java.util.logging support is now disabled.
diff --git a/opendj-server-legacy/src/messages/src/org/opends/messages/Severity.java b/opendj-server-legacy/src/messages/src/org/opends/messages/Severity.java
index ab0158b..35b4f79 100644
--- a/opendj-server-legacy/src/messages/src/org/opends/messages/Severity.java
+++ b/opendj-server-legacy/src/messages/src/org/opends/messages/Severity.java
@@ -46,31 +46,21 @@
     mayInvoke=true)
 public enum Severity {
 
-  /**
-   * The severity that will be used for informational messages.
-   */
-  INFORMATION("INFO"),
-
-  /**
-   * The severity that will be used for warning messages.
-   */
-  WARNING("WARN"),
-
-  /**
-   * The severity that will be used for warning messages.
-   */
-  ERROR("ERR"),
-
-  /**
-   * The severity that will be used for debug messages.
-   */
+  /** The severity that will be used for debug messages. */
   DEBUG("DEBUG"),
 
-  /**
-   * The severity that will be used for important informational
-   * messages.
-   */
-  NOTICE("NOTE");
+  /** The severity that will be used for informational messages. */
+  INFORMATION("INFO"),
+
+  /** The severity that will be used for important informational messages. */
+  NOTICE("NOTE"),
+
+  /** The severity that will be used for warning messages. */
+  WARNING("WARN"),
+
+  /** The severity that will be used for warning messages. */
+  ERROR("ERR");
+
 
   private static Set<String> PROPERTY_KEY_FORM_VALUES_SET;
 

--
Gitblit v1.10.0