org.mule.module.launcher.log4j2.LoggerContextConfigurer Maven / Gradle / Ivy
/*
* Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com
* The software in this package is published under the terms of the CPAL v1.0
* license, a copy of which has been included with this distribution in the
* LICENSE.txt file.
*/
package org.mule.module.launcher.log4j2;
import org.mule.api.MuleRuntimeException;
import org.mule.api.config.MuleProperties;
import org.mule.config.i18n.MessageFactory;
import org.mule.module.reboot.MuleContainerBootstrapUtils;
import org.mule.util.ClassUtils;
import org.mule.util.FileUtils;
import java.io.File;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.List;
import java.util.zip.Deflater;
import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.ConsoleAppender;
import org.apache.logging.log4j.core.appender.FileAppender;
import org.apache.logging.log4j.core.appender.RandomAccessFileAppender;
import org.apache.logging.log4j.core.appender.RollingFileAppender;
import org.apache.logging.log4j.core.appender.rolling.DefaultRolloverStrategy;
import org.apache.logging.log4j.core.appender.rolling.RolloverStrategy;
import org.apache.logging.log4j.core.appender.rolling.TimeBasedTriggeringPolicy;
import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
import org.apache.logging.log4j.core.config.AbstractConfiguration;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.ConfigurationListener;
import org.apache.logging.log4j.core.config.ConfiguratonFileWatcher;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.core.config.Reconfigurable;
import org.apache.logging.log4j.core.layout.PatternLayout;
import org.apache.logging.log4j.core.util.FileWatcher;
/**
* This component grabs a {link MuleLoggerContext} which has just been created reading a configuration file
* and applies configuration changes to it so that it complies with mule's logging strategy.
*
* Its basic functions are:
*
* - Disable log4j's shutdown hook so that it doesn't collide with mule's {@link org.mule.module.launcher.artifact.ShutdownListener},
* which would result in a classloader leak.
* - When using a default configuration (one which doesn't come from a config file), the console appender is removed
* - if the classloader is an {@link org.mule.module.launcher.artifact.ArtifactClassLoader}, then it adds a rolling file appender
* to collect the artifact's logs
* - if the configuration did not include a monitorInterval, then one is set to a default value of 60
* - if the context is standalone, then it adds a rolling file appender associated to the artifact
* - if the context is not standalone, then it just logs to a file named mule-main.log
*
*
* @since 3.6.0
*/
final class LoggerContextConfigurer
{
private static final String MULE_APP_LOG_FILE_TEMPLATE = "mule-app-%s.log";
private static final String MULE_DOMAIN_LOG_FILE_TEMPLATE = "mule-domain-%s.log";
private static final String PATTERN_LAYOUT = "%-5p %d [%t] %c: %m%n";
private static final int DEFAULT_MONITOR_INTERVAL_SECS = 60;
static final String FORCED_CONSOLE_APPENDER_NAME = "Forced-Console";
static final String PER_APP_FILE_APPENDER_NAME = "defaultFileAppender";
protected void configure(MuleLoggerContext context)
{
disableShutdownHook(context);
configureMonitor(context);
}
protected void update(MuleLoggerContext context)
{
boolean forceConsoleLog = System.getProperty(MuleProperties.MULE_FORCE_CONSOLE_LOG) != null;
if (context.getConfigFile() == null && !forceConsoleLog)
{
removeConsoleAppender(context);
}
if (context.isArtifactClassloader())
{
addDefaultArtifactContext(context);
}
else if (!context.isStandlone())
{
addDefaultAppender(context, "mule-main.log");
}
if (forceConsoleLog && !hasAppender(context, ConsoleAppender.class))
{
forceConsoleAppender(context);
}
}
private void disableShutdownHook(LoggerContext context)
{
try
{
ClassUtils.setFieldValue(context.getConfiguration(), "isShutdownHookEnabled", false, true);
}
catch (Exception e)
{
throw new MuleRuntimeException(MessageFactory.createStaticMessage("Could not configure shutdown hook. Unexpected configuration type"), e);
}
}
private void configureMonitor(MuleLoggerContext context)
{
Configuration configuration = context.getConfiguration();
File configFile = null;
if (context.getConfigFile() != null)
{
configFile = new File(context.getConfigFile().getPath());
}
else if (!StringUtils.isEmpty(configuration.getName()))
{
configFile = new File(configuration.getName());
}
if (configFile != null && configuration instanceof Reconfigurable)
{
configuration.getWatchManager().setIntervalSeconds(DEFAULT_MONITOR_INTERVAL_SECS);
FileWatcher watcher = new ConfiguratonFileWatcher((Reconfigurable) configuration, getListeners(configuration));
configuration.getWatchManager().watchFile(configFile, watcher);
}
}
private List getListeners(Configuration configuration)
{
try
{
return ClassUtils.getFieldValue(configuration, "listeners", true);
}
catch (Exception e)
{
throw new MuleRuntimeException(MessageFactory.createStaticMessage("Could not get listeners. Unexpected configuration type"), e);
}
}
private void addDefaultAppender(MuleLoggerContext context, String logFilePath)
{
RollingFileAppender appender = createRollingFileAppender(logFilePath, ".%d{yyyy-MM-dd}", PER_APP_FILE_APPENDER_NAME, context.getConfiguration());
doAddAppender(context, appender);
}
private void forceConsoleAppender(MuleLoggerContext context)
{
Appender appender = ConsoleAppender.createAppender(createLayout(context.getConfiguration()), null, null, FORCED_CONSOLE_APPENDER_NAME, null, null);
doAddAppender(context, appender);
}
private void doAddAppender(LoggerContext context, Appender appender)
{
appender.start();
context.getConfiguration().addAppender(appender);
getRootLogger(context).addAppender(appender, Level.ALL, null);
}
private RollingFileAppender createRollingFileAppender(String logFilePath, String filePattern, String appenderName, Configuration configuration)
{
TriggeringPolicy triggeringPolicy = TimeBasedTriggeringPolicy.createPolicy("1", "true");
RolloverStrategy rolloverStrategy = DefaultRolloverStrategy.createStrategy("30", "1", null, String.valueOf(Deflater.NO_COMPRESSION), null, true, configuration);
return RollingFileAppender.createAppender(logFilePath,
logFilePath + filePattern,
"true",
appenderName,
"true",
null, null,
triggeringPolicy,
rolloverStrategy,
createLayout(configuration),
null, null, null, null,
configuration);
}
private Layout extends Serializable> createLayout(Configuration configuration)
{
return PatternLayout.createLayout(PATTERN_LAYOUT, null, configuration, null, null, true, false, null, null);
}
private void addDefaultArtifactContext(MuleLoggerContext context)
{
String logFileNameTemplate = getFilenamePattern(context);
if (logFileNameTemplate == null)
{
return;
}
String artifactName = context.getArtifactName();
String logName = String.format(logFileNameTemplate, (artifactName != null ? artifactName : ""));
File logDir = new File(MuleContainerBootstrapUtils.getMuleHome(), "logs");
File logFile = new File(logDir, logName);
if (context.getConfigLocation() == null)
{
addDefaultAppender(context, logFile.getAbsolutePath());
}
else
{
// If the artifact logging is configured using the global config file and there is no file appender for the artifact, then configure a default one
if (isUrlInsideDirectory(context.getConfigFile(), MuleContainerBootstrapUtils.getMuleConfDir()))
{
if (!hasFileAppender(context))
{
addDefaultAppender(context, logFile.getAbsolutePath());
removeConsoleAppender(context);
}
}
}
}
private void removeConsoleAppender(LoggerContext context)
{
for (Appender appender : getRootLogger(context).getAppenders().values())
{
if (appender instanceof ConsoleAppender)
{
removeAppender(context, appender);
getRootLogger(context).removeAppender(appender.getName());
}
}
}
private boolean hasFileAppender(LoggerContext context)
{
return hasAppender(context, FileAppender.class, RollingFileAppender.class, RandomAccessFileAppender.class);
}
private boolean hasAppender(LoggerContext context, Class extends Appender>... appenderTypes)
{
for (Appender appender : getRootLogger(context).getAppenders().values())
{
for (Class extends Appender> appenderType : appenderTypes)
{
if (appenderType.isInstance(appender))
{
return true;
}
}
}
return false;
}
private boolean isUrlInsideDirectory(URI uri, File directory)
{
if (uri == null)
{
return false;
}
URL url;
try
{
url = uri.toURL();
}
catch (MalformedURLException e)
{
throw new MuleRuntimeException(MessageFactory.createStaticMessage("Could not locate file " + uri), e);
}
if (directory != null && FileUtils.isFile(url))
{
File urlFile = new File(url.getFile());
return directory.equals(urlFile.getParentFile());
}
return false;
}
private String getFilenamePattern(MuleLoggerContext context)
{
if (context.isArtifactClassloader())
{
return context.isApplicationClassloader() ? MULE_APP_LOG_FILE_TEMPLATE : MULE_DOMAIN_LOG_FILE_TEMPLATE;
}
return null;
}
private LoggerConfig getRootLogger(LoggerContext context)
{
return ((AbstractConfiguration) context.getConfiguration()).getRootLogger();
}
private void removeAppender(LoggerContext context, Appender appender)
{
((AbstractConfiguration) context.getConfiguration()).removeAppender(appender.getName());
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy