Re: Having trouble changing a logger's level (threshold) at runtime

2023-02-28 Thread Ralph Goers
Looking at Configurator.setLevel(String loggerName, Level level) it should do 
exactly what I described - if there is no LoggerConfig with the name specified 
one will be created and have its level set. Otherwise it sets the Level on the 
located LoggerConfig. It then calls updateLoggers. If this doesn’t work 
correctly then I would want to see the Log4j debug logs from startup to see if 
there are multiple LoggerContexts and multiple configurations.

Ralph

> On Feb 28, 2023, at 9:18 PM, Ralph Goers  wrote:
> 
> What you are running into is a fundamental difference in how Log4j 1.x worked 
> and how Log4j2 works. In Log4j 1 when you added a Logger statement to the 
> configuration it would create a “real” Logger just as if you had called 
> LogManager.getLogger(). Log4j 2.x does not do that. As Pier noted, this is so 
> log events are never lost when configuration changes are made. 
> 
> I have a suspicion here that the “loggerName” you passed in doesn’t actually 
> exist in your configuration.  The way getLoggerConfig works is that it looks 
> for a Logger defined in the configuration that exactly matches what you 
> specified - in this case “com.example.Class”.  If it doesn’t find that it 
> then strips off the last token and tries again (com.example). It repeats this 
> until it gets to the root LoggerConfig.  So if you don’t have any Loggers 
> configured that at least partially match the Logger name you provided then it 
> is going to set the level for the root LoggerConfig..
> 
> If you were to call getLogger for the same name it will only return the 
> LoggerConfig if there is an exact match, otherwise it will return null.
> 
> If you really want to change the level for a specific Logger then you have to 
> ensure that a LoggerConfig actually exists for that name.  You would first 
> call getLogger(loggerName) and if it returns null then you need to add a new 
> LoggerConfig by calling addLogger. You will need to create the LoggerConfig 
> with the appropriate Level, filters, and appenders (or let it inherit those 
> from its parents).  If it does exist then call setLevel on the existing 
> LoggerConfig. In either case you must then call updateLoggers to cause all 
> the Loggers to reassociate with the appropriate LoggerConfigs.
> 
> Ralph
> 
> 
> 
>> On Feb 28, 2023, at 12:04 PM, Christopher Schultz 
>>  wrote:
>> 
>> All,
>> 
>> I'm coming from a log4j v1.x background where this was easy to do:
>> 
>> String loggerName = "com.example.Class";
>> Logger log = LogManager.exists(loggerName);
>> if(null != log) {
>> log.setLevel(targetLevel);
>> }
>> 
>> This appears no longer to be possible -- or at least easy -- and I've seen 
>> at least two techniques on StackOverflow which result in the same behavior: 
>> the log-level threshold for *every logger everywhere* gets set to the target 
>> level.
>> 
>> For example, setting the log-level for the logger called "foo" to TRACE ends 
>> up filling my log with stuff from completely unrelated loggers/classes/etc.
>> 
>> Here is one technique[1]
>> 
>> String loggerName = "com.example.Class";
>> LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
>> Configuration config = ctx.getConfiguration();
>> LoggerConfig loggerConfig = config.getLoggerConfig(loggerName);
>> loggerConfig.setLevel(level);
>> ctx.updateLoggers();  // This causes all Loggers to refetch information from 
>> their LoggerConfig.
>> 
>> I tried both with and without the ctx.updateLoggers() call.
>> 
>> Here is another technique[2]:
>> 
>> Configurator.setLevel(loggerName, level);
>> 
>> This reconfigures everything just like the one above.
>> 
>> The final technique (still in the same SO question) is this:
>> 
>>   final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
>>   final Configuration config = ctx.getConfiguration();
>> 
>>   LoggerConfig loggerConfig = config.getLoggerConfig(logger.getName());
>>   LoggerConfig specificConfig = loggerConfig;
>> 
>>   // We need a specific configuration for this logger,
>>   // otherwise we would change the level of all other loggers
>>   // having the original configuration as parent as well
>> 
>>   if (!loggerConfig.getName().equals(logger.getName())) {
>>   specificConfig = new LoggerConfig(logger.getName(), level, true);
>>   specificConfig.setParent(loggerConfig);
>>   config.addLogger(logger.getName(), specificConfig);
>>   }
>>   specificConfig.setLevel(level);
>>   ctx.updateLoggers();
>> 
>> This does not seem to set the log level for all loggers to e.g. TRACE but it 
>> also doesn't seem to set the actual logger. (I can see e.g. DEBUG and TRACE 
>> logs from other loggers, so it's not an issue with the appender).
>> 
>> What is the recommended technique for changing a single logger's threshold 
>> in log4j2? I realize that the best thing to do would be to "just configure 
>> it correctly the first time" but in reality, you sometimes just have to 
>> enable TRACE logging in production to figure 

Re: Having trouble changing a logger's level (threshold) at runtime

2023-02-28 Thread Ralph Goers
What you are running into is a fundamental difference in how Log4j 1.x worked 
and how Log4j2 works. In Log4j 1 when you added a Logger statement to the 
configuration it would create a “real” Logger just as if you had called 
LogManager.getLogger(). Log4j 2.x does not do that. As Pier noted, this is so 
log events are never lost when configuration changes are made. 

I have a suspicion here that the “loggerName” you passed in doesn’t actually 
exist in your configuration.  The way getLoggerConfig works is that it looks 
for a Logger defined in the configuration that exactly matches what you 
specified - in this case “com.example.Class”.  If it doesn’t find that it then 
strips off the last token and tries again (com.example). It repeats this until 
it gets to the root LoggerConfig.  So if you don’t have any Loggers configured 
that at least partially match the Logger name you provided then it is going to 
set the level for the root LoggerConfig..

If you were to call getLogger for the same name it will only return the 
LoggerConfig if there is an exact match, otherwise it will return null.

If you really want to change the level for a specific Logger then you have to 
ensure that a LoggerConfig actually exists for that name.  You would first call 
getLogger(loggerName) and if it returns null then you need to add a new 
LoggerConfig by calling addLogger. You will need to create the LoggerConfig 
with the appropriate Level, filters, and appenders (or let it inherit those 
from its parents).  If it does exist then call setLevel on the existing 
LoggerConfig. In either case you must then call updateLoggers to cause all the 
Loggers to reassociate with the appropriate LoggerConfigs.

Ralph



> On Feb 28, 2023, at 12:04 PM, Christopher Schultz 
>  wrote:
> 
> All,
> 
> I'm coming from a log4j v1.x background where this was easy to do:
> 
> String loggerName = "com.example.Class";
> Logger log = LogManager.exists(loggerName);
> if(null != log) {
>  log.setLevel(targetLevel);
> }
> 
> This appears no longer to be possible -- or at least easy -- and I've seen at 
> least two techniques on StackOverflow which result in the same behavior: the 
> log-level threshold for *every logger everywhere* gets set to the target 
> level.
> 
> For example, setting the log-level for the logger called "foo" to TRACE ends 
> up filling my log with stuff from completely unrelated loggers/classes/etc.
> 
> Here is one technique[1]
> 
> String loggerName = "com.example.Class";
> LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
> Configuration config = ctx.getConfiguration();
> LoggerConfig loggerConfig = config.getLoggerConfig(loggerName);
> loggerConfig.setLevel(level);
> ctx.updateLoggers();  // This causes all Loggers to refetch information from 
> their LoggerConfig.
> 
> I tried both with and without the ctx.updateLoggers() call.
> 
> Here is another technique[2]:
> 
> Configurator.setLevel(loggerName, level);
> 
> This reconfigures everything just like the one above.
> 
> The final technique (still in the same SO question) is this:
> 
>final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
>final Configuration config = ctx.getConfiguration();
> 
>LoggerConfig loggerConfig = config.getLoggerConfig(logger.getName());
>LoggerConfig specificConfig = loggerConfig;
> 
>// We need a specific configuration for this logger,
>// otherwise we would change the level of all other loggers
>// having the original configuration as parent as well
> 
>if (!loggerConfig.getName().equals(logger.getName())) {
>specificConfig = new LoggerConfig(logger.getName(), level, true);
>specificConfig.setParent(loggerConfig);
>config.addLogger(logger.getName(), specificConfig);
>}
>specificConfig.setLevel(level);
>ctx.updateLoggers();
> 
> This does not seem to set the log level for all loggers to e.g. TRACE but it 
> also doesn't seem to set the actual logger. (I can see e.g. DEBUG and TRACE 
> logs from other loggers, so it's not an issue with the appender).
> 
> What is the recommended technique for changing a single logger's threshold in 
> log4j2? I realize that the best thing to do would be to "just configure it 
> correctly the first time" but in reality, you sometimes just have to enable 
> TRACE logging in production to figure out what the hell is happening.
> 
> Thanks,
> -chris
> 
> 
> [1] Adapted from https://stackoverflow.com/a/23434603/276232
> [2] Adapted from https://stackoverflow.com/a/44678752/276232
> 
> -
> To unsubscribe, e-mail: log4j-user-unsubscr...@logging.apache.org
> For additional commands, e-mail: log4j-user-h...@logging.apache.org
> 


-
To unsubscribe, e-mail: log4j-user-unsubscr...@logging.apache.org
For additional commands, e-mail: log4j-user-h...@logging.apache.org



Re: Having trouble changing a logger's level (threshold) at runtime

2023-02-28 Thread Gary Gregory
How about log4j-core's Configurator class and its setLevel() methods?

Gary

On Tue, Feb 28, 2023, 14:04 Christopher Schultz <
ch...@christopherschultz.net> wrote:

> All,
>
> I'm coming from a log4j v1.x background where this was easy to do:
>
> String loggerName = "com.example.Class";
> Logger log = LogManager.exists(loggerName);
> if(null != log) {
>log.setLevel(targetLevel);
> }
>
> This appears no longer to be possible -- or at least easy -- and I've
> seen at least two techniques on StackOverflow which result in the same
> behavior: the log-level threshold for *every logger everywhere* gets set
> to the target level.
>
> For example, setting the log-level for the logger called "foo" to TRACE
> ends up filling my log with stuff from completely unrelated
> loggers/classes/etc.
>
> Here is one technique[1]
>
> String loggerName = "com.example.Class";
> LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
> Configuration config = ctx.getConfiguration();
> LoggerConfig loggerConfig = config.getLoggerConfig(loggerName);
> loggerConfig.setLevel(level);
> ctx.updateLoggers();  // This causes all Loggers to refetch information
> from their LoggerConfig.
>
> I tried both with and without the ctx.updateLoggers() call.
>
> Here is another technique[2]:
>
> Configurator.setLevel(loggerName, level);
>
> This reconfigures everything just like the one above.
>
> The final technique (still in the same SO question) is this:
>
>  final LoggerContext ctx = (LoggerContext)
> LogManager.getContext(false);
>  final Configuration config = ctx.getConfiguration();
>
>  LoggerConfig loggerConfig = config.getLoggerConfig(logger.getName());
>  LoggerConfig specificConfig = loggerConfig;
>
>  // We need a specific configuration for this logger,
>  // otherwise we would change the level of all other loggers
>  // having the original configuration as parent as well
>
>  if (!loggerConfig.getName().equals(logger.getName())) {
>  specificConfig = new LoggerConfig(logger.getName(), level, true);
>  specificConfig.setParent(loggerConfig);
>  config.addLogger(logger.getName(), specificConfig);
>  }
>  specificConfig.setLevel(level);
>  ctx.updateLoggers();
>
> This does not seem to set the log level for all loggers to e.g. TRACE
> but it also doesn't seem to set the actual logger. (I can see e.g. DEBUG
> and TRACE logs from other loggers, so it's not an issue with the appender).
>
> What is the recommended technique for changing a single logger's
> threshold in log4j2? I realize that the best thing to do would be to
> "just configure it correctly the first time" but in reality, you
> sometimes just have to enable TRACE logging in production to figure out
> what the hell is happening.
>
> Thanks,
> -chris
>
>
> [1] Adapted from https://stackoverflow.com/a/23434603/276232
> [2] Adapted from https://stackoverflow.com/a/44678752/276232
>
> -
> To unsubscribe, e-mail: log4j-user-unsubscr...@logging.apache.org
> For additional commands, e-mail: log4j-user-h...@logging.apache.org
>
>


Re: Having trouble changing a logger's level (threshold) at runtime

2023-02-28 Thread Piotr P. Karwasz
Hi Chris,

On Tue, 28 Feb 2023 at 20:04, Christopher Schultz
 wrote:
> What is the recommended technique for changing a single logger's
> threshold in log4j2? I realize that the best thing to do would be to
> "just configure it correctly the first time" but in reality, you
> sometimes just have to enable TRACE logging in production to figure out
> what the hell is happening.

The recommended approach is to dynamically update your configuration.
Log4j2 Core does not lose events during a reconfiguration event.
By setting a `monitorInterval` attribute on the ``
component[1], Log4j2 will monitor your configuration source (anything
with a Java URL handler) and reconfigure the logging system when it
changes.

Another approach is through global filters (filters directly attached
to the Configuration object), that are evaluated *before* a logger's
level. If they return ACCEPT or DENY, the message is unconditionally
accepted or denied.
Recently Ralph added the (undocumented?)
MutableThreadContextMapFilter[2], which works like its documented
counterpart[3], but regularly reads its configuration from an URL
(configLocation attribute).
This can be used e.g. to increase the logging level for a specific
user dynamically.

If you really require programmatic configuration,
Configurator.setLevel[4] is the most stable way. As you noticed,
Configuration#getLoggerConfig gives you the *effective* configuration
of the logger, which could be the configuration of its parent or even
the root logger.

Piotr

[1] 
https://logging.apache.org/log4j/2.x/manual/configuration.html#AutomaticReconfiguration
[2] 
https://logging.apache.org/log4j/2.x/javadoc/log4j-core/org/apache/logging/log4j/core/filter/MutableThreadContextMapFilter.Builder.html
[3] 
https://logging.apache.org/log4j/2.x/manual/filters.html#ThreadContextMapFilter
[4] 
https://logging.apache.org/log4j/2.x/javadoc/log4j-core/org/apache/logging/log4j/core/config/Configurator.html

-
To unsubscribe, e-mail: log4j-user-unsubscr...@logging.apache.org
For additional commands, e-mail: log4j-user-h...@logging.apache.org



Having trouble changing a logger's level (threshold) at runtime

2023-02-28 Thread Christopher Schultz

All,

I'm coming from a log4j v1.x background where this was easy to do:

String loggerName = "com.example.Class";
Logger log = LogManager.exists(loggerName);
if(null != log) {
  log.setLevel(targetLevel);
}

This appears no longer to be possible -- or at least easy -- and I've 
seen at least two techniques on StackOverflow which result in the same 
behavior: the log-level threshold for *every logger everywhere* gets set 
to the target level.


For example, setting the log-level for the logger called "foo" to TRACE 
ends up filling my log with stuff from completely unrelated 
loggers/classes/etc.


Here is one technique[1]

String loggerName = "com.example.Class";
LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
Configuration config = ctx.getConfiguration();
LoggerConfig loggerConfig = config.getLoggerConfig(loggerName);
loggerConfig.setLevel(level);
ctx.updateLoggers();  // This causes all Loggers to refetch information 
from their LoggerConfig.


I tried both with and without the ctx.updateLoggers() call.

Here is another technique[2]:

Configurator.setLevel(loggerName, level);

This reconfigures everything just like the one above.

The final technique (still in the same SO question) is this:

final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
final Configuration config = ctx.getConfiguration();

LoggerConfig loggerConfig = config.getLoggerConfig(logger.getName());
LoggerConfig specificConfig = loggerConfig;

// We need a specific configuration for this logger,
// otherwise we would change the level of all other loggers
// having the original configuration as parent as well

if (!loggerConfig.getName().equals(logger.getName())) {
specificConfig = new LoggerConfig(logger.getName(), level, true);
specificConfig.setParent(loggerConfig);
config.addLogger(logger.getName(), specificConfig);
}
specificConfig.setLevel(level);
ctx.updateLoggers();

This does not seem to set the log level for all loggers to e.g. TRACE 
but it also doesn't seem to set the actual logger. (I can see e.g. DEBUG 
and TRACE logs from other loggers, so it's not an issue with the appender).


What is the recommended technique for changing a single logger's 
threshold in log4j2? I realize that the best thing to do would be to 
"just configure it correctly the first time" but in reality, you 
sometimes just have to enable TRACE logging in production to figure out 
what the hell is happening.


Thanks,
-chris


[1] Adapted from https://stackoverflow.com/a/23434603/276232
[2] Adapted from https://stackoverflow.com/a/44678752/276232

-
To unsubscribe, e-mail: log4j-user-unsubscr...@logging.apache.org
For additional commands, e-mail: log4j-user-h...@logging.apache.org