[ https://issues.apache.org/jira/browse/LOG4J2-3330?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Mircea Lemnaru updated LOG4J2-3330: ----------------------------------- Description: 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: {code:java} LoggerContext loggerContext = LoggerContext.getContext(false);{code} Which fetches the LoggerContext for the caller class. In turn , LoggerContext.getContext has the following content: {code:java} public static LoggerContext getContext(final boolean currentContext) { return (LoggerContext) LogManager.getContext(currentContext); } {code} Which delegates the context fetching to LogManager LogManager in turn get's the context by passing a hardcoded class name as the stack marker: {code:java} private static final String FQCN = LogManager.class.getName();{code} 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: {code:java} 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{code} 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: {code:java} 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{code} 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. was: 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. > 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 > Priority: Major > > 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: > {code:java} > LoggerContext loggerContext = LoggerContext.getContext(false);{code} > Which fetches the LoggerContext for the caller class. > In turn , LoggerContext.getContext has the following content: > > {code:java} > public static LoggerContext getContext(final boolean currentContext) > { return (LoggerContext) LogManager.getContext(currentContext); } > {code} > > Which delegates the context fetching to LogManager > LogManager in turn get's the context by passing a hardcoded class name as the > stack marker: > {code:java} > private static final String FQCN = LogManager.class.getName();{code} > 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: > {code:java} > 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{code} > 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: > {code:java} > 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{code} > 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)