I am building an admin UI for managing logback loggers level and changing appenders. I know I can find all appenders that are added to some logger with the following code:
private Map<String, Appender<ILoggingEvent>> getAppendersMap() {
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
Map<String, Appender<ILoggingEvent>> appendersMap = new HashMap<>();
for (Logger logger : loggerContext.getLoggerList()) {
Iterator<Appender<ILoggingEvent>> appenderIterator = logger.iteratorForAppenders();
while (appenderIterator.hasNext()) {
Appender<ILoggingEvent> appender = appenderIterator.next();
if (!appendersMap.containsKey(appender.getName())) {
appendersMap.put(appender.getName(), appender);
}
}
}
return appendersMap;
}
The problem is if I have this logback.xml
as example:
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false" scan="true" scanPeriod="10 minutes">
<appender name="writeToConsole" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>
%date{yyyy-MM-dd;HH:mm:ss.SSS} %-11p: %40.40c: %X{tablist}%m %n
</pattern>
</encoder>
</appender>
<appender name="NOPAppender" class="ch.qos.logback.core.helpers.NOPAppender" />
<root>
<level value="INFO"/>
<appender-ref ref="writeToConsole"/>
</root>
</configuration>
the NOPAppender
is not a attached to any logger and therefor the method getAppendersMap()
doesn't find it.
After 4 plus years, I found something that can be used with Logback XML configuration:
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.util.ContextInitializer;
import ch.qos.logback.core.Appender;
import ch.qos.logback.core.joran.action.ActionConst;
import ch.qos.logback.core.joran.spi.InterpretationContext;
import ch.qos.logback.core.joran.spi.JoranException;
/**
* Utility class for finding all configured logback appenders.
*/
public class LogbackAppenderFinder {
private static final Logger LOGGER = LoggerFactory.getLogger(LogbackAppenderFinder.class);
private LogbackAppenderFinder() {
}
/**
* Tries to find all appenders from an xml config. The method works by trying to find the default logback config file
* names, can be further enhanced to include others, e.g. files supported by Spring Boot or custom files.
*
* @return Map of all the appenders configured with the XML file where the key is the appender name configured in
* the xml file and the value is the appender itself.
*/
public static Map<String, Appender<ILoggingEvent>> findAppendersFromXmlConfig() {
try {
LoggerContext dummyLoggerContext = new LoggerContext();
ContextInitializer contextInitializer = new ContextInitializer(dummyLoggerContext);
URL configurationFileUrl = contextInitializer.findURLOfDefaultConfigurationFile(true);
if (configurationFileUrl != null && configurationFileUrl.toString().endsWith(".xml")) {
JoranConfigurator configurator = new JoranConfigurator();
configurator.setContext(dummyLoggerContext);
configurator.doConfigure(configurationFileUrl);
InterpretationContext interpretationContext = configurator.getInterpretationContext();
Map<String, Object> objectMap = interpretationContext.getObjectMap();
return (Map<String, Appender<ILoggingEvent>>) objectMap.get(ActionConst.APPENDER_BAG);
} else {
LOGGER.warn("Unable to find xml configuration file.");
}
} catch (JoranException e) {
LOGGER.warn("Failed to parse logback configuration, check config file.");
}
return new HashMap<>();
}
}