package org.apache.cassandra.utils.logging;
import java.lang.management.ManagementFactory;
import java.security.AccessControlException;
import java.util.Iterator;
import java.util.Map;
import javax.management.JMX;
import javax.management.ObjectName;
import org.apache.cassandra.security.ThreadAwareSecurityManager;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.LoggerFactory;
import com.google.common.collect.Maps;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.jmx.JMXConfiguratorMBean;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.TurboFilterList;
import ch.qos.logback.classic.turbo.ReconfigureOnChangeFilter;
import ch.qos.logback.classic.turbo.TurboFilter;
import ch.qos.logback.core.Appender;
import ch.qos.logback.core.hook.DelayingShutdownHook;
public class LogbackLoggingSupport implements LoggingSupport
{
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(LogbackLoggingSupport.class);
@Override
public void onStartup()
{
Logger logbackLogger = (Logger) LoggerFactory.getLogger(ThreadAwareSecurityManager.class);
LoggerContext ctx = logbackLogger.getLoggerContext();
TurboFilterList turboFilterList = ctx.getTurboFilterList();
for (int i = 0; i < turboFilterList.size(); i++)
{
TurboFilter turboFilter = turboFilterList.get(i);
if (turboFilter instanceof ReconfigureOnChangeFilter)
{
ReconfigureOnChangeFilter reconfigureOnChangeFilter = (ReconfigureOnChangeFilter) turboFilter;
turboFilterList.set(i, new SMAwareReconfigureOnChangeFilter(reconfigureOnChangeFilter));
break;
}
}
}
@Override
public void onShutdown()
{
DelayingShutdownHook logbackHook = new DelayingShutdownHook();
logbackHook.setContext((LoggerContext) LoggerFactory.getILoggerFactory());
logbackHook.run();
}
@Override
public void setLoggingLevel(String classQualifier, String rawLevel) throws Exception
{
Logger logBackLogger = (Logger) LoggerFactory.getLogger(classQualifier);
if (StringUtils.isBlank(classQualifier) && StringUtils.isBlank(rawLevel))
{
JMXConfiguratorMBean jmxConfiguratorMBean = JMX.newMBeanProxy(ManagementFactory.getPlatformMBeanServer(),
new ObjectName("ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator"),
JMXConfiguratorMBean.class);
jmxConfiguratorMBean.reloadDefaultConfiguration();
return;
}
else if (StringUtils.isNotBlank(classQualifier) && StringUtils.isBlank(rawLevel))
{
if (logBackLogger.getLevel() != null || hasAppenders(logBackLogger))
logBackLogger.setLevel(null);
return;
}
Level level = Level.toLevel(rawLevel);
logBackLogger.setLevel(level);
logger.info("set log level to {} for classes under '{}' (if the level doesn't look like '{}' then the logger couldn't parse '{}')", level, classQualifier, rawLevel, rawLevel);
}
@Override
public Map<String, String> getLoggingLevels()
{
Map<String, String> logLevelMaps = Maps.newLinkedHashMap();
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
for (Logger logBackLogger : lc.getLoggerList())
{
if (logBackLogger.getLevel() != null || hasAppenders(logBackLogger))
logLevelMaps.put(logBackLogger.getName(), logBackLogger.getLevel().toString());
}
return logLevelMaps;
}
private boolean hasAppenders(Logger logBackLogger)
{
Iterator<Appender<ILoggingEvent>> it = logBackLogger.iteratorForAppenders();
return it.hasNext();
}
private static class SMAwareReconfigureOnChangeFilter extends ReconfigureOnChangeFilter
{
SMAwareReconfigureOnChangeFilter(ReconfigureOnChangeFilter reconfigureOnChangeFilter)
{
setRefreshPeriod(reconfigureOnChangeFilter.getRefreshPeriod());
setName(reconfigureOnChangeFilter.getName());
setContext(reconfigureOnChangeFilter.getContext());
if (reconfigureOnChangeFilter.isStarted())
{
reconfigureOnChangeFilter.stop();
start();
}
}
protected boolean changeDetected(long now)
{
if (ThreadAwareSecurityManager.isSecuredThread())
return false;
return super.changeDetected(now);
}
}
}