Log4j2에서 프로그래밍 방식으로 로그 수준 변경


108

Log4j2의 로그 수준을 프로그래밍 방식으로 변경하는 데 관심이 있습니다. 구성 문서를 살펴 보았지만 아무것도없는 것 같습니다. 나는 또한 패키지를 보려고 시도했지만 org.apache.logging.log4j.core.config거기에 도움이되는 것은 아무것도 없습니다.


2
여기에서 답을 얻지 못한 경우 메일 목록을 시도해보십시오. 일반적으로 주 저자가 2 일에 한 번 확인했습니다. 그런 다음 돌아와서 자신의 질문에 답하십시오 :-)
tgkprog

답변:


138

log4j2 버전 2.4 FAQ에 따라 편집 됨

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에 감사드립니다!
Sturm

1
.updateLoggers ()가 필요하지 않은 것 같습니다. .setLevel ()로 변경 한 내용이 즉시 적용되는 것 같습니다.
zbyszek 2015 년

1
새 LoggerConfig를 추가하더라도 updateLoggers에 대한 호출은 항상 필요합니다. UpdateLoggers는 모든 로거가 자신을 LoggerConfigs와 다시 연결하고 로그 수준을 연결된 LoggerConfig의 수준으로 변경하도록합니다. 새 LoggerConfig를 추가하면 새 LoggerConfig 패턴과 일치하는 모든 Logger가 여기로 리디렉션됩니다. Logger와 그 구성이 Log4j2에서 분리 되었기 때문에 "convoluted"방식이 필요합니다.
rgoers

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
물 자체

코드를 업데이트했습니다. 문제가 있으면 알려주세요.
Jörg Friedrich

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가 있으며이를 최종 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"빈을 찾습니다.

  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));
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.