找到在logback.xml中配置的所有logback appender,即使没有附加到任何记录器

时间:2017-09-15 23:36:49

标签: java logging logback

我正在构建一个用于管理logback记录器级别和更改appender的管理UI。我知道我可以使用以下代码找到添加到某个记录器的所有appender:

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

问题是我是否以logback.xml为例:

<?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>

NOPAppender 附加到任何记录器,因此方法getAppendersMap() 找不到

1 个答案:

答案 0 :(得分:2)

从外部文件(logback.xml,logback-test.xml,logback.groovy等)配置自身时,Logback会像这样完成配置(这是它的功能的简略版本):

  • 查找任何appenders
  • 将每个appender添加到APPENDER_BAG
  • 中的瞬态InterpretationContext.objectMap
  • 对于每个appender-ref(存在于记录器定义中),在此APPENDER_BAG中查找引用的appender(按名称),如果存在,则将该appender添加到当前记录器

您可以使用appender关联定义显式记录器:<logger name="com.x.y" level="INFO"><appender-ref ref="STDOUT"/></logger>或使用<root/>元素将appender与所有记录器实例相关联:<root level="INFO"><appender-ref ref="STDOUT"/></root>

因此,只有在配置时才知道与任何记录器无关的追加器,一旦LoggerContext被创建,就会丢弃瞬态(APPENDER_BAG)。这就解释了为什么getAppendersMap()找不到您的NOOPAppender

认为这里的要求就是“知道”一个appender,即使在配置时不需要它。据推测,一个appender最初可能是不需要的,但有人可以选择稍后启用。这就像你试图使用logback.xml作为某个可能想要在应用程序运行时中的某些点使用的所有appender的完整语句。为此,您必须首先在LoggerContext中包含可选的appender,但必须使用no-op实现。这是您在问题中已经做过的事情,但您只需要将NOPAppender添加到根上下文中。

<root level="INFO">
    <appender-ref ref="STDOUT"/>
    <appender-ref ref="NOPAppender"/>
</root>

这对正在运行的系统没有任何影响,因为appender是一个无操作系统,但由于它在LoggerContext中被引用,它可供你管理,当然如果你想启用它,那么appender类的选择必须以编程方式更改为no-op之外的其他内容。

另一种替代方法可能是以编程方式创建一个appender,并在需要时将其添加到LoggerContext