Find all logback appenders configured in logback.xml even if not attached to any logger

Viewed 1433

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.

2 Answers

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<>();
  }

}
Related