Mircea Lemnaru created LOG4J2-3330:
--------------------------------------
Summary: Configurator.setLevel not fetching the correct
LoggerContext
Key: LOG4J2-3330
URL: https://issues.apache.org/jira/browse/LOG4J2-3330
Project: Log4j 2
Issue Type: Bug
Components: Core
Affects Versions: 2.17.1
Reporter: Mircea Lemnaru
I needed to set the log level for a certain logger in the application and for
that I tried using the following code:
Configurator.setLevel(logger,level) but it did not seem to set the proper
logging level.
After looking over the source code I have noticed the following behaviour:
Inside setLevel there is this line:
LoggerContext loggerContext = LoggerContext.getContext(false);
Which fetches the LoggerContext for the caller class.
In turn , LoggerContext.getContext has the following content:
public static LoggerContext getContext(final boolean currentContext) {
return (LoggerContext) LogManager.getContext(currentContext);
}
Which delegates the context fetching to LogManager
LogManager in turn get's the context by passing a hardcoded class name as the
stack marker:
private static final String FQCN = LogManager.class.getName();
Because of this , the methods LoggerContext.getContext and
LogManager.getContext behave differently in environments with multiple
LoggerContexts and ClassLoaders
Test:
# Calling LoggerContext.getContext - returns LoggerContextA - corresponding to
the classloader of LoggerContext because if we look at the stack trace:
getCallerClass:151, StackLocator (org.apache.logging.log4j.util)
getCallerClass:70, StackLocatorUtil (org.apache.logging.log4j.util)
getCallerClass:58, StackLocatorUtil (org.apache.logging.log4j.util)
getContext:138, ClassLoaderContextSelector
(org.apache.logging.log4j.core.selector)
getContext:123, ClassLoaderContextSelector
(org.apache.logging.log4j.core.selector)
getContext:230, Log4jContextFactory (org.apache.logging.log4j.core.impl)
getContext:47, Log4jContextFactory (org.apache.logging.log4j.core.impl)
getContext:176, LogManager (org.apache.logging.log4j)
getContext:231, LoggerContext (org.apache.logging.log4j.core) <---- returns this
handle:24, LogLevelChangeHandler (com.ispring.log.event) <----- real caller
class
Because of the fact that the context is fetched by providing the hardcoded FQCN
which is LogManager ... getCallerClass(FQCN) will return LoggerContext instead
of returning LogLevelChangeHandler ( the real caller )
2. Calling LogManager.getContext - returns LoggerContextB - corresponding to
the classloader of LogLevelChangeHandler which is the correct behaviour since
LogLevelChangeHandler is the class that is actually requesting the context.
If we look at the stack trace:
getCallerClass:151, StackLocator (org.apache.logging.log4j.util)
getCallerClass:70, StackLocatorUtil (org.apache.logging.log4j.util)
getCallerClass:58, StackLocatorUtil (org.apache.logging.log4j.util)
getContext:138, ClassLoaderContextSelector
(org.apache.logging.log4j.core.selector)
getContext:123, ClassLoaderContextSelector
(org.apache.logging.log4j.core.selector)
getContext:230, Log4jContextFactory (org.apache.logging.log4j.core.impl)
getContext:47, Log4jContextFactory (org.apache.logging.log4j.core.impl)
getContext:176, LogManager (org.apache.logging.log4j) <-- break point
handle:25, LogLevelChangeHandler (com.ispring.log.event) <--- the correct class
to be returned
Because of the behaviour mentioned above , calling Configurator.setLevel
doesn't have de desired effect in environments with multiple LoggerContexts (
webapp deployed in tomcat ) because it's setting the level one some
LoggerContext which is not the one used by the application classes.
--
This message was sent by Atlassian Jira
(v8.20.1#820001)