All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.solr.util.StartupLoggingUtils Maven / Gradle / Ivy

There is a newer version: 9.7.0
Show newest version
/*
 * 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.util;

import java.lang.invoke.MethodHandles;
import java.util.Map;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender;
import org.apache.logging.log4j.core.appender.ConsoleAppender;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.solr.common.util.EnvUtils;
import org.apache.solr.common.util.SuppressForbidden;
import org.slf4j.ILoggerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Handles programmatic modification of logging during startup
 *
 * 

WARNING: This class should only be used during startup. For modifying log levels etc during * runtime, SLF4J and LogWatcher must be used. */ public final class StartupLoggingUtils { private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); private static final ILoggerFactory loggerFactory = LoggerFactory.getILoggerFactory(); /** Checks whether mandatory log dir is given */ public static void checkLogDir() { if (EnvUtils.getProperty("solr.log.dir") == null) { log.error("Missing Java Option solr.log.dir. Logging may be missing or incomplete."); } } public static String getLoggerImplStr() { // nowarn return loggerFactory.getClass().getName(); } /** * Disables all log4j2 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. log4j2 classes were not in * classpath */ @SuppressForbidden(reason = "Legitimate log4j2 access") public static boolean muteConsole() { try { if (!isLog4jActive()) { logNotSupported("Could not mute logging to console."); return false; } LoggerContext ctx = (LoggerContext) LogManager.getContext(false); Configuration config = ctx.getConfiguration(); LoggerConfig loggerConfig = config.getLoggerConfig(LogManager.ROOT_LOGGER_NAME); Map appenders = loggerConfig.getAppenders(); appenders.forEach( (name, appender) -> { if (appender instanceof ConsoleAppender) { loggerConfig.removeAppender(name); ctx.updateLoggers(); } }); return true; } catch (Exception e) { logNotSupported("Could not mute logging to console."); return false; } } /** * Dynamically change log4j log level through property solr.log.level * * @param logLevel String with level, should be one of the supported, e.g. TRACE, DEBUG, INFO, * WARN, ERROR... * @return true if ok or else false if something happened, e.g. log4j classes were not in * classpath */ @SuppressForbidden(reason = "Legitimate log4j2 access") public static boolean changeLogLevel(String logLevel) { try { if (!isLog4jActive()) { logNotSupported("Could not change log level."); return false; } LoggerContext ctx = (LoggerContext) LogManager.getContext(false); Configuration config = ctx.getConfiguration(); LoggerConfig loggerConfig = config.getRootLogger(); loggerConfig.setLevel(Level.toLevel(logLevel, Level.INFO)); ctx.updateLoggers(); return true; } catch (Exception e) { logNotSupported("Could not change log level."); return false; } } private static boolean isLog4jActive() { try { // Make sure we have log4j LogManager in classpath Class.forName("org.apache.logging.log4j.LogManager"); // Make sure that log4j is really selected as logger in slf4j - we could have LogManager in // the bridge class :) return getLoggerImplStr().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); } /** * Perhaps odd to put in startup utils, but this is where the logging-init code is so it seems * logical to put the shutdown here too. * *

Tests are particularly sensitive to this call or the object release tracker will report * "lmax.disruptor" not terminating when asynch logging (new default as of 8.1) is enabled. * *

Expert, there are rarely good reasons for this to be called outside of the test framework. * If you are tempted to call this for running Solr, you should probably be using synchronous * logging. */ @SuppressForbidden(reason = "Legitimate log4j2 access") public static void shutdown() { if (!isLog4jActive()) { logNotSupported("Not running log4j2, could not call shutdown for async logging."); return; } flushAllLoggers(); LogManager.shutdown(true); } /** * This is primarily for tests to insure that log messages don't bleed from one test case to * another, see: SOLR-13268. * *

However, if there are situations where we want to insure that all log messages for all * loggers are flushed, this method can be called by anyone. It should _not_ affect Solr in any * way except, perhaps, a slight delay while messages are being flushed. * *

Expert, there are rarely good reasons for this to be called outside of the test framework. * If you are tempted to call this for running Solr, you should probably be using synchronous * logging. */ @SuppressForbidden(reason = "Legitimate log4j2 access") public static void flushAllLoggers() { if (!isLog4jActive()) { logNotSupported("Not running log4j2, could not call shutdown for async logging."); return; } final LoggerContext logCtx = ((LoggerContext) LogManager.getContext(false)); for (final org.apache.logging.log4j.core.Logger logger : logCtx.getLoggers()) { for (final Appender appender : logger.getAppenders().values()) { if (appender instanceof AbstractOutputStreamAppender) { ((AbstractOutputStreamAppender) appender).getManager().flush(); } } } } /** * Return a string representing the current static ROOT logging level * * @return a string TRACE, DEBUG, WARN, ERROR or INFO representing current log level. Default is * INFO */ public static String getLogLevelString() { final Logger rootLogger = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); if (rootLogger.isTraceEnabled()) return "TRACE"; else if (rootLogger.isDebugEnabled()) return "DEBUG"; else if (rootLogger.isInfoEnabled()) return "INFO"; else if (rootLogger.isWarnEnabled()) return "WARN"; else if (rootLogger.isErrorEnabled()) return "ERROR"; else return "INFO"; } /** * Check whether Jetty request logging is enabled and log info about it. The property * "solr.log.requestlog.enabled is set in solr/server/etc/jetty-requestlog.xml */ public static void checkRequestLogging() { boolean requestLogEnabled = Boolean.getBoolean("solr.log.requestlog.enabled"); String retainDays = System.getProperty("solr.log.requestlog.retaindays"); if (requestLogEnabled) { if (retainDays == null) { log.warn( "Jetty request logging enabled. Will retain logs for last 3 days. See chapter \"Configuring Logging\" in reference guide for how to configure."); } else { log.info("Jetty request logging enabled. Will retain logs for last {} days.", retainDays); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy