/* * Copyright 2015 herd contributors * * Licensed 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.finra.herd.core.helper; import java.io.StringWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; 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.WriterAppender; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.Configurator; import org.apache.logging.log4j.core.config.LoggerConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import org.finra.herd.core.Command; /** * Log4J2 implementation of the logging helper. */ @Component public class Log4j2LoggingHelper implements LoggingHelper { private static final Logger LOGGER = LoggerFactory.getLogger(Log4j2LoggingHelper.class); @Override public LogLevel getLogLevel(Class clazz) { return getLogLevel(clazz.getName()); } @Override public LogLevel getLogLevel(String loggerName) { // Get the main logger context. LoggerContext loggerContext = (LoggerContext) LogManager.getContext(false); // Get the main configuration. Configuration configuration = loggerContext.getConfiguration(); // Get the logging configuration for the specified logger name from the main configuration. LoggerConfig loggerConfig = configuration.getLoggerConfig(loggerName); // Return the logging level for the logging configuration. return log4jToGenericLogLevel(loggerConfig.getLevel()); } @Override public void setLogLevel(Class clazz, LogLevel logLevel) { setLogLevel(clazz.getName(), logLevel); } @Override public void setLogLevel(String loggerName, LogLevel logLevel) { Configurator.setLevel(loggerName, genericLogLevelToLog4j(logLevel)); } @Override public void shutdownLogging() { LogManager.shutdown(); } @Override public void executeWithoutLogging(Class<?> loggingClass, Command command) throws Exception { List<Class<?>> loggingClasses = new ArrayList<>(); loggingClasses.add(loggingClass); executeWithoutLogging(loggingClasses, command); } @Override public void executeWithoutLogging(List<Class<?>> loggingClasses, Command command) throws Exception { // Get the logger context and it's associated configuration. LoggerContext loggerContext = (LoggerContext) LogManager.getContext(false); Configuration configuration = loggerContext.getConfiguration(); // Temporarily turn off logging. Map<LoggerConfig, Level> loggerToOriginalLevel = new HashMap<>(); for (Class<?> loggingClass : loggingClasses) { LoggerConfig loggerConfig = loggingClass == null ? null : configuration.getLoggerConfig(loggingClass.getName()); Level originalLevel = loggerConfig == null ? null : loggerConfig.getLevel(); if (loggerConfig != null) { loggerConfig.setLevel(Level.OFF); loggerToOriginalLevel.put(loggerConfig, originalLevel); } } // This causes all Loggers to re-fetch information from their LoggerConfig. loggerContext.updateLoggers(); try { // Execute the command. command.execute(); } finally { for (Map.Entry<LoggerConfig, Level> entry : loggerToOriginalLevel.entrySet()) { LoggerConfig loggerConfig = entry.getKey(); Level originalLevel = entry.getValue(); // Turn the original logging back on. loggerConfig.setLevel(originalLevel); } } } @Override public void initLogging(String contextName, String configLocation) { // Initialize via the configurator. Configurator.initialize(contextName, null, configLocation); } @Override public StringWriter addLoggingWriterAppender(String appenderName) { // Get the configuration final LoggerContext loggerContext = (LoggerContext) LogManager.getContext(false); final Configuration configuration = loggerContext.getConfiguration(); // Create a string writer as part of the appender so logging will be written to it. StringWriter stringWriter = new StringWriter(); // Create and start the appender with the string writer. Appender appender = WriterAppender.createAppender(null, null, stringWriter, appenderName, false, true); appender.start(); // Add the appender to the root logger. configuration.getRootLogger().addAppender(appender, null, null); // Return the string writer. return stringWriter; } @Override public void removeLoggingAppender(String appenderName) { // Get the configuration and remove the appender from it. final LoggerContext loggerContext = (LoggerContext) LogManager.getContext(false); final Configuration configuration = loggerContext.getConfiguration(); configuration.getRootLogger().removeAppender(appenderName); } /** * Converts a Log4J specific log level to a generic log level. * * @param level the Log4J log level. * * @return the generic log level. */ private LogLevel log4jToGenericLogLevel(Level level) { LogLevel logLevel = LogLevel.ALL; if (level.equals(Level.OFF)) { logLevel = LogLevel.OFF; } else if (level.equals(Level.FATAL)) { logLevel = LogLevel.FATAL; } else if (level.equals(Level.ERROR)) { logLevel = LogLevel.ERROR; } else if (level.equals(Level.WARN)) { logLevel = LogLevel.WARN; } else if (level.equals(Level.INFO)) { logLevel = LogLevel.INFO; } else if (level.equals(Level.DEBUG)) { logLevel = LogLevel.DEBUG; } else if (level.equals(Level.TRACE)) { logLevel = LogLevel.TRACE; } else if (level.equals(Level.ALL)) { logLevel = LogLevel.ALL; } else { LOGGER.warn("Unsupported log level encountered: " + level.toString() + ". Using ALL."); } return logLevel; } /** * Converts a generic log level to a Log4J specific log level. * * @param logLevel the generic log level. * * @return the Log4J specific log level. */ private Level genericLogLevelToLog4j(LogLevel logLevel) { Level level = Level.ALL; if (logLevel.equals(LogLevel.OFF)) { level = Level.OFF; } else if (logLevel.equals(LogLevel.FATAL)) { level = Level.FATAL; } else if (logLevel.equals(LogLevel.ERROR)) { level = Level.ERROR; } else if (logLevel.equals(LogLevel.WARN)) { level = Level.WARN; } else if (logLevel.equals(LogLevel.INFO)) { level = Level.INFO; } else if (logLevel.equals(LogLevel.DEBUG)) { level = Level.DEBUG; } else if (logLevel.equals(LogLevel.TRACE)) { level = Level.TRACE; } else if (logLevel.equals(LogLevel.ALL)) { level = Level.ALL; } else { LOGGER.warn("Unsupported log level encountered: " + logLevel.toString() + ". Using ALL."); } return level; } }