<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body>
<p>Hi,</p>
<p>I have a custom Configurator installed via META_INF.services in a
bunch of different services.<br>
I do it this way because I was finding that managing logback.xml
files across a lot of different services was awkward and
unnecessary log levels were leaking into production.<br>
I also have a custom class for changing specific log levels based
on env vars or system properties, and a vertx router for changing
them dynamically at runtime.</p>
<p>All of this has been working work a few years, but I have
recently found that in some circumstances I'm getting duplicate
messages (at first it was just in some builds, but now it's in
production so I need to do something about it).</p>
<p>I've added a load of debug spew to my classes, but it appears
that the default configuration is being applied after my custom
Configurator and I can't work out what is causing that.<br>
And, of course, right now I can only reproduce this by executing a
jar on the command line, rather than in a unit test.</p>
<p>My main method looks like this:</p>
<pre> public static void main(String[] args) {
Main main = new Main(args);
logger.info("Starting ({})", LoggerFactory.getILoggerFactory());
</pre>
<pre> LoggerContext lc = ((LoggerContext) LoggerFactory.getILoggerFactory());
System.out.println(lc.getName());
for (ch.qos.logback.classic.Logger logger : lc.getLoggerList()) {
System.out.println("\t" + logger.getName());
for (Iterator<Appender<ILoggingEvent>> iter = logger.iteratorForAppenders(); iter.hasNext(); ) {
Appender<ILoggingEvent> a = iter.next();
System.out.println("\t\t" + a.getName());
}
}
// irrelevant stuff here
}
and my custom Configurator is this:
<pre> /**
* Perform the configuration.
* @param lc The LoggerContext to configure.
* @param asJson If true then logs will be recorded as JSON.
*/
public void configure(LoggerContext lc, boolean asJson) {
@SuppressWarnings("unchecked")
Map<Object, Object> ruleRegistry = (Map<Object, Object>) lc.getObject(CoreConstants.PATTERN_RULE_REGISTRY);
if (ruleRegistry == null) {
ruleRegistry = new HashMap<>();
lc.putObject(CoreConstants.PATTERN_RULE_REGISTRY, ruleRegistry);
}
registerConverters(ruleRegistry);
Appender<ILoggingEvent> appender;
if (asJson) {
appender = configureJsonOutput(lc, createConsoleAppender(lc));
} else {
appender = configureMultiLineOutput(lc, createConsoleAppender(lc));
}
appender.start();
System.out.println(lc.getName());
for (Logger logger : lc.getLoggerList()) {
System.out.println("\t" + logger.getName());
for (Iterator<Appender<ILoggingEvent>> iter = logger.iteratorForAppenders(); iter.hasNext(); ) {
Appender<ILoggingEvent> a = iter.next();
System.out.println("\t\t" + a.getName());
}
logger.detachAndStopAllAppenders();
}
Logger rootLogger = lc.getLogger(Logger.ROOT_LOGGER_NAME);
rootLogger.addAppender(appender);
rootLogger.setLevel(Level.INFO);
rootLogger.setAdditive(true);
System.out.println(lc.getName());
for (Logger logger : lc.getLoggerList()) {
System.out.println("\t" + logger.getName());
for (Iterator<Appender<ILoggingEvent>> iter = logger.iteratorForAppenders(); iter.hasNext(); ) {
Appender<ILoggingEvent> a = iter.next();
System.out.println("\t\t" + a.getName());
}
}
}
</pre>The output from this is:
<pre>NOTE: Picked up JDK_JAVA_OPTIONS: -server -XX:-OmitStackTraceInFastThrow
default
ROOT
default
ROOT
STDOUTPUT
2023-05-04 12:55:18.653 [main] c.groupgti.shared.configservice.Main INFO - Starting (ch.qos.logback.classic.LoggerContext[default])
13:55:18.653 [main] INFO com.groupgti.shared.configservice.Main -- Starting (ch.qos.logback.classic.LoggerContext[default])
default
ROOT
STDOUTPUT
console
com
com.groupgti
com.groupgti.shared
com.groupgti.shared.configservice
com.groupgti.shared.configservice.Main
+ more packages
</pre>
</pre>
So my custom Configurator is running, but then (I think when the
static loggers are created) the console appender is being added to
the ROOT logger.<br>
<p>I tried naming my appender "console", that just resulted in two
appenders called "console" :)</p>
<p>How can I stop the default "console" appender being added to
root?</p>
<p>Thanks</p>
<p>Jim<br>
</p>
<br>
<br>
<p><br>
</p>
</body>
</html>