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


109

我对以编程方式更改Log4j2中的日志级别感兴趣。我尝试查看他们的配置文档,但似乎没有任何内容。我也尝试在包中查找:org.apache.logging.log4j.core.config,但其中的任何内容看起来都没有帮助。


2
如果您在这里没有找到答案,请尝试尝试邮件列表,该列表通常由主要作者在两天内查看一次。然后回来回答您自己的问题:-)
tgkprog 2014年

Answers:


139

根据log4j2 2.4版常见问题进行编辑

您可以使用Log4j Core中的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。


3
正确,如果您只想更改特定的记录器(类/程序包),请获取该记录器的上下文setLevel和updateLoggers。
tgkprog 2014年

34
这种令人费解的方法只是用来设置日志记录级别。我敢肯定有理由使用五行代码而不是log4j的先前版本中的原始一行来执行此操作,但是我只是看不到它。无论如何,感谢@slaadvak!
斯特姆2014年

1
.updateLoggers()似乎不是必需的。似乎.setLevel()所做的更改会立即应用。
zbyszek

1
即使添加新的LoggerConfig,也始终需要调用updateLoggers。UpdateLoggers使所有记录器重新与LoggerConfigs关联,并将其日志级别更改为其关联的LoggerConfig的日志级别。如果添加新的LoggerConfig,则与新LoggerConfig模式匹配的所有Logger都将重定向到该Logger。由于日志记录器及其配置已在Log4j2中分开,因此需要“卷积”方式。
rgoers '16

1
以下是为Log4J的较新版本提供更新的1行或2行解决方案的答案:stackoverflow.com/a/44678752/1339923
Lambart

37

@slaadvak接受的答案不适用于Log4j2 2.8.2。以下做了。

Level 普遍更改日志,请使用:

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

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

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

1
我之所以投票,是因为您从记录器本身中提取了记录器名称,而不是将名称硬编码为字符串。
DWoldrich

18

如果要更改单个特定的记录器级别(而不是配置文件中配置的一个或多个根记录器),可以执行以下操作:

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();
}

3
这根本不影响我的记录器。我使用过,setLevel(logger, Level.ERROR);并且logger.debug语句仍然打印。我的log4j2.xml文件位于pastebin.com/fcbV2mTW
Noumenon

我更新了代码。让我知道是否有任何问题。
约尔格弗里德里希

4
在log4j的2.7 LoggerContext还没有一个getConfiguration()方法,见logging.apache.org/log4j/2.x/log4j-api/apidocs/index.html?org/...
maxxyme

log4j-core-2.7.jar具有并且可以用作最终LoggerContext ctx =(LoggerContext)LogManager.getContext(false); 最终配置配置= ctx.getConfiguration();
jprism

3
看到这些之后,我在想。“也许他们不希望我们在运行时更改级别?”
Koray Tugay

13

我在这里找到了一个很好的答案: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);

2
这个答案显示了相同的解决方案,以及如何为根记录程序设置它-有时很有用:stackoverflow.com/a/44678752/1339923
Lambart

4

程序化方法颇具侵入性。也许您应该检查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


非常有帮助,谢谢!
Darren Parker

3

默认情况下,大多数答案都假定日志记录必须是累加的。但是请说某个软件包正在生成大量日志,并且您只想关闭该特定记录器的日志记录。这是我用来使其工作的代码

    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>

2

我发现一种不寻常的方法是创建两个具有不同日志记录级别的单独文件。
例如。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));
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.