From 9ad4517450f576725dfeed22d20382f611ede50b Mon Sep 17 00:00:00 2001 From: David Smiley Date: Sat, 7 Feb 2026 01:44:04 -0500 Subject: [PATCH] SOLR-18017: fix Log4j2Watcher, register parents Now, explicitly traverse parent logger hierarchies when iterating through explicitly configured loggers. This ensures parent loggers are always included in Log4j2Watcher.getAllLoggers(). It seems Log4j 2.25.3 (or one > 2.21.0) changed behavior in ctx.getLoggers(). --- .../solr/logging/log4j2/Log4j2Watcher.java | 51 +++++++++++-------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/solr/core/src/java/org/apache/solr/logging/log4j2/Log4j2Watcher.java b/solr/core/src/java/org/apache/solr/logging/log4j2/Log4j2Watcher.java index 9e266baa5ad6..fabfdb107a5e 100644 --- a/solr/core/src/java/org/apache/solr/logging/log4j2/Log4j2Watcher.java +++ b/solr/core/src/java/org/apache/solr/logging/log4j2/Log4j2Watcher.java @@ -90,16 +90,6 @@ public Log4j2Info(String name, Level level, boolean isSet) { private final boolean isSet; - @Override - public String getLevel() { - return (level != null) ? level : null; - } - - @Override - public String getName() { - return name; - } - @Override public boolean isSet() { return isSet; @@ -199,12 +189,15 @@ public Collection getAllLoggers() { continue; } - // NOTE: just because we have an explicit configuration, doesn't mean we have an explitly set - // level - // (Configuration might be for some other property, and level is still inherited) + // NOTE: just because we have an explicit configuration, doesn't mean we have an explicitly + // set level (Configuration might be for some other property, and level is still inherited) map.putIfAbsent( name, new Log4j2Info(name, logger.getLevel(), null != config.getValue().getExplicitLevel())); + + // Also add parent loggers in the hierarchy, as they are relevant for level inheritance + // This ensures parent loggers appear even if not in ctx.getLoggers() + addParentLoggers(name, map, ctx); } // Now add any "in use" loggers (that aren't already explicitly configured) and their parents @@ -218,18 +211,36 @@ public Collection getAllLoggers() { // If we didn't already see a LoggerConfig for these loggers, then their level is // not (explicitly) set map.putIfAbsent(name, new Log4j2Info(name, logger.getLevel(), false)); - while (true) { - int dot = name.lastIndexOf('.'); - if (dot < 0) break; - - name = name.substring(0, dot); - map.putIfAbsent(name, new Log4j2Info(name, logger.getLevel(), false)); - } + addParentLoggers(name, map, ctx); } return map.values(); } + /** + * Adds all parent loggers in the hierarchy for the given logger name. + * + *

For example, given "org.apache.solr.core.SolrCore", this will add: + * + *

    + *
  • "org.apache.solr.core" + *
  • "org.apache.solr" + *
  • "org" + *
+ */ + private void addParentLoggers( + String loggerName, Map map, LoggerContext ctx) { + String parentName = loggerName; + while (true) { + int dot = parentName.lastIndexOf('.'); + if (dot < 0) break; + + parentName = parentName.substring(0, dot); + map.putIfAbsent( + parentName, new Log4j2Info(parentName, ctx.getLogger(parentName).getLevel(), false)); + } + } + @Override public void setThreshold(String level) { Log4j2Appender app = getAppender();