From 7498ca9ad67b25e48e2ae182256864b06d82e186 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Thu, 22 Sep 2016 13:37:13 +0200 Subject: [PATCH] SOLR-8186: Added robustness to the dynamic log muting logic (cherry picked from commit eabb05f) --- .../solr/servlet/SolrDispatchFilter.java | 19 +---- .../solr/servlet/StartupLoggingUtils.java | 85 +++++++++++++++++++ 2 files changed, 86 insertions(+), 18 deletions(-) create mode 100644 solr/core/src/java/org/apache/solr/servlet/StartupLoggingUtils.java diff --git a/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java b/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java index a32a70abcba..17f9b6e2bbf 100644 --- a/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java +++ b/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java @@ -37,7 +37,6 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; -import java.util.Enumeration; import java.util.Locale; import java.util.Properties; import java.util.concurrent.atomic.AtomicBoolean; @@ -49,14 +48,10 @@ import org.apache.commons.io.input.CloseShieldInputStream; import org.apache.commons.io.output.CloseShieldOutputStream; import org.apache.commons.lang.StringUtils; import org.apache.http.client.HttpClient; -import org.apache.log4j.Appender; -import org.apache.log4j.ConsoleAppender; -import org.apache.log4j.LogManager; import org.apache.solr.common.SolrException; import org.apache.solr.common.SolrException.ErrorCode; import org.apache.solr.common.cloud.SolrZkClient; import org.apache.solr.common.util.ExecutorUtil; -import org.apache.solr.common.util.SuppressForbidden; import org.apache.solr.core.CoreContainer; import org.apache.solr.core.NodeConfig; import org.apache.solr.core.SolrCore; @@ -124,7 +119,7 @@ public class SolrDispatchFilter extends BaseSolrFilter { { String muteConsole = System.getProperty(SOLR_LOG_MUTECONSOLE); if (muteConsole != null && !Arrays.asList("false","0","off","no").contains(muteConsole.toLowerCase(Locale.ROOT))) { - muteConsole(); + StartupLoggingUtils.muteConsole(); } log.info("SolrDispatchFilter.init(): {}", this.getClass().getClassLoader()); @@ -161,18 +156,6 @@ public class SolrDispatchFilter extends BaseSolrFilter { log.info("SolrDispatchFilter.init() done"); } - @SuppressForbidden(reason = "Legitimate log4j access") - private void muteConsole() { - Enumeration appenders = LogManager.getRootLogger().getAllAppenders(); - while (appenders.hasMoreElements()) { - Appender appender = (Appender) appenders.nextElement(); - if (appender instanceof ConsoleAppender) { - log.info("Property solr.log.muteconsole given. Muting ConsoleAppender named " + appender.getName()); - LogManager.getRootLogger().removeAppender(appender); - } - } - } - /** * Override this to change CoreContainer initialization * @return a CoreContainer to hold this server's cores diff --git a/solr/core/src/java/org/apache/solr/servlet/StartupLoggingUtils.java b/solr/core/src/java/org/apache/solr/servlet/StartupLoggingUtils.java new file mode 100644 index 00000000000..fbcebebc52d --- /dev/null +++ b/solr/core/src/java/org/apache/solr/servlet/StartupLoggingUtils.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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. + */ + +package org.apache.solr.servlet; + +import java.lang.invoke.MethodHandles; +import java.util.Enumeration; + +import org.apache.log4j.Appender; +import org.apache.log4j.ConsoleAppender; +import org.apache.log4j.LogManager; +import org.apache.solr.common.util.SuppressForbidden; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.impl.StaticLoggerBinder; + +/** + * Handles dynamic modification of during startup, before CoreContainer is created + *

+ * WARNING: This class should only be used during startup. For modifying log levels etc + * during runtime, SLF4J and LogWatcher must be used. + *

+ */ +final class StartupLoggingUtils { + private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + private final static StaticLoggerBinder binder = StaticLoggerBinder.getSingleton(); + + /** + * Disables all log4j ConsoleAppender's by modifying log4j configuration dynamically. + * Must only be used during early startup + * @return true if ok or else false if something happened, e.g. log4j classes were not in classpath + */ + @SuppressForbidden(reason = "Legitimate log4j access") + static boolean muteConsole() { + try { + if (!isLog4jActive()) { + logNotSupported("Could not mute logging to console."); + return false; + } + org.apache.log4j.Logger rootLogger = LogManager.getRootLogger(); + Enumeration appenders = rootLogger.getAllAppenders(); + while (appenders.hasMoreElements()) { + Appender appender = (Appender) appenders.nextElement(); + if (appender instanceof ConsoleAppender) { + log.info("Property solr.log.muteconsole given. Muting ConsoleAppender named " + appender.getName()); + rootLogger.removeAppender(appender); + } + } + return true; + } catch (Exception e) { + logNotSupported("Could not mute logging to console."); + return false; + } + } + + private static boolean isLog4jActive() { + try { + // Make sure we have log4j LogManager in classpath + Class.forName("org.apache.log4j.LogManager"); + // Make sure that log4j is really selected as logger in slf4j - we could have LogManager in the bridge class :) + return binder.getLoggerFactoryClassStr().contains("Log4jLoggerFactory"); + } catch (Exception e) { + return false; + } + } + + private static void logNotSupported(String msg) { + log.warn("{} Dynamic log manipulation currently only supported for Log4j. " + + "Please consult your logging framework of choice on how to configure the appropriate logging.", msg); + } +}