以编程方式更改 Log4j2中的日志级别

我对以编程方式更改 Log4j2中的日志级别感兴趣。我试着查看他们的 配置文件,但似乎没有任何东西。我也试着在包里找: org.apache.logging.log4j.core.config,但是里面看起来也没有什么有用的东西。

116279 次浏览

简单的方法:

根据 log4j2版本2.4 FAQ 编辑

可以使用 Log4jCore 中的 Configurator 类设置日志记录器的级别。但是知道 Configurator 类不是公共 API 的一部分。

// org.apache.logging.log4j.core.config.Configurator;
Configurator.setLevel("com.example.Foo", Level.DEBUG);


// You can also set the root logger:
Configurator.setRootLevel(Level.DEBUG);

来源

最佳方式:

编辑以反映 Log4j2版本2.0.2中引入的 API 的变化

如果希望更改根日志记录器级别,请执行以下操作:

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

这里 是 LoggerConfig 的 javadoc。

这种编程方法相当麻烦,也许您应该检查一下 Log4J2提供的 JMX 支持:

  1. 启动应用程序中的 JMX 端口:

    - Dcom.sun.management. jmxRemote.port = [ port _ num ]

  2. 在执行应用程序时,使用任何可用的 JMX 客户机(JVM 在 JAVA _ HOME/bin/jconsole. exe 中提供了一个)。

  3. 在 JConsole 中查找“ org.apache.logging.log4j2.Loggers”bean

  4. 最后更改日志记录器的级别

我最喜欢的是,您不必修改您的代码或配置来管理它。都是外在的,透明的。

更多信息: http://logging.apache.org/log4j/2.x/manual/jmx.html

如果希望更改单个特定的日志记录器级别(而不是配置文件中配置的根日志记录器或日志记录器) ,可以这样做:

public static void setLevel(Logger logger, Level level) {
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();
}

我在这里找到了一个很好的答案: https://garygregory.wordpress.com/2016/01/11/changing-log-levels-in-log4j2/

可以使用 org.apache.logging.log4j.core.config. Configurator 设置特定日志记录器的级别。

Logger logger = LogManager.getLogger(Test.class);
Configurator.setLevel(logger.getName(), Level.DEBUG);

Log4j22.8.2中,@sladavak 接受的答案对我来说不起作用。

要更改日志 Level 全世界,请使用:

Configurator.setAllLevels(LogManager.getRootLogger().getName(), level);

若要仅更改当前类的日志 Level,请使用:

Configurator.setLevel(LogManager.getLogger(CallingClass.class).getName(), level);

我发现一种不寻常的方法是创建两个具有不同日志级别的独立文件。
例如. log4j2.xml 和 log4j-debug. xml 现在从这个文件中更改配置。
示例代码:

ConfigurationFactory configFactory = XmlConfigurationFactory.getInstance();
ConfigurationFactory.setConfigurationFactory(configFactory);
LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
InputStream inputStream = classloader.getResourceAsStream(logFileName);
ConfigurationSource configurationSource = new ConfigurationSource(inputStream);


ctx.start(configFactory.getConfiguration(ctx, configurationSource));

默认情况下,大多数答案都假设日志记录必须是可加的。但是假设某个包正在生成大量日志,并且您希望仅关闭该特定日志记录器的日志记录。这是我用来让它工作的代码

    public class LogConfigManager {


public void setLogLevel(String loggerName, String level) {
Level newLevel = Level.valueOf(level);
LoggerContext logContext = (LoggerContext) LogManager.getContext(false);
Configuration configuration = logContext.getConfiguration();
LoggerConfig loggerConfig = configuration.getLoggerConfig(loggerName);
// getLoggerConfig("a.b.c") could return logger for "a.b" if there is no logger for "a.b.c"
if (loggerConfig.getName().equalsIgnoreCase(loggerName)) {
loggerConfig.setLevel(newLevel);
log.info("Changed logger level for {} to {} ", loggerName, newLevel);
} else {
// create a new config.
loggerConfig = new LoggerConfig(loggerName, newLevel, false);
log.info("Adding config for: {} with level: {}", loggerConfig, newLevel);
configuration.addLogger(loggerName, loggerConfig);




LoggerConfig parentConfig = loggerConfig.getParent();
do {
for (Map.Entry<String, Appender> entry : parentConfig.getAppenders().entrySet()) {
loggerConfig.addAppender(entry.getValue(), null, null);
}
parentConfig = parentConfig.getParent();
} while (null != parentConfig && parentConfig.isAdditive());
}
logContext.updateLoggers();
}
}

同样的测试用例

public class LogConfigManagerTest {
@Test
public void testLogChange() throws IOException {
LogConfigManager logConfigManager = new LogConfigManager();
File file = new File("logs/server.log");
Files.write(file.toPath(), new byte[0], StandardOpenOption.TRUNCATE_EXISTING);
Logger logger = LoggerFactory.getLogger("a.b.c");
logger.debug("Marvel-1");
logConfigManager.setLogLevel("a.b.c", "debug");
logger.debug("DC-1");
// Parent logger level should remain same
LoggerFactory.getLogger("a.b").debug("Marvel-2");
logConfigManager.setLogLevel("a.b.c", "info");
logger.debug("Marvel-3");
// Flush everything
LogManager.shutdown();


String content = Files.readAllLines(file.toPath()).stream().reduce((s1, s2) -> s1 + "\t" + s2).orElse(null);
Assert.assertEquals(content, "DC-1");
}
}

假设后面的 log4j2.xml 在类路径中

<?xml version="1.0" encoding="UTF-8"?>
<Configuration xmlns="http://logging.apache.org/log4j/2.0/config">


<Appenders>
<File name="FILE" fileName="logs/server.log" append="true">
<PatternLayout pattern="%m%n"/>
</File>
<Console name="STDOUT" target="SYSTEM_OUT">
<PatternLayout pattern="%m%n"/>
</Console>
</Appenders>


<Loggers>
<AsyncLogger name="a.b" level="info">
<AppenderRef ref="STDOUT"/>
<AppenderRef ref="FILE"/>
</AsyncLogger>


<AsyncRoot level="info">
<AppenderRef ref="STDOUT"/>
</AsyncRoot>
</Loggers>


</Configuration>

对于那些还在纠结这个问题的人,我不得不将类加载器添加到“ getContext ()”调用中:

  log.info("Modifying Log level! (maybe)");
LoggerContext ctx = (LoggerContext) LogManager.getContext(this.getClass().getClassLoader(), false);
Configuration config = ctx.getConfiguration();
LoggerConfig loggerConfig = config.getLoggerConfig("com.cat.barrel");
loggerConfig.setLevel(org.apache.logging.log4j.Level.TRACE);
ctx.updateLoggers();

我在测试中添加了一个 jvm 参数: Dlog4j.debug。这会为 log4j 做一些详细的日志记录。我注意到最终的日志管理器不是我正在使用的那个。砰,添加类装入器,就可以开始比赛了。