[log4j] runtime 중 레벨 변경(@Slf4j 같이 적용)

[log4j] runtime 중 레벨 변경(@Slf4j 같이 적용)

Spring을 사용하지 않은 프로젝트에서 log4j 를 설정하기 위해서는 다음의 경로에 log4j.properties 또는 log4j.xml 파일이 있어야 한다.

src/main/resources/log4j.properties

이 파일을 읽을 수 있는건 org.apache.log4j.LogManager 에서 가능한데, 나중에 로그레벨을 변경하는 것도 여기서 한다. 파일안을 보면 다음으로 구성되어 있다

/** * Use the LogManager class to retreive {@link Logger} * instances or to operate on the current {@link * LoggerRepository}. When the LogManager class is loaded * into memory the default initalzation procedure is inititated. The * default intialization procedure is described in the short log4j manual. * * @author Ceki Gülcü */ public class LogManager { /** * @deprecated This variable is for internal use only. It will * become package protected in future versions. * */ static public final String DEFAULT_CONFIGURATION_FILE = "log4j.properties"; static final String DEFAULT_XML_CONFIGURATION_FILE = "log4j.xml"; ... static { // By default we use a DefaultRepositorySelector which always returns 'h'. Hierarchy h = new Hierarchy(new RootLogger((Level) Level.DEBUG)); repositorySelector = new DefaultRepositorySelector(h); /** Search for the properties file log4j.properties in the CLASSPATH. */ String override =OptionConverter.getSystemProperty(DEFAULT_INIT_OVERRIDE_KEY, null); // if there is no default init override, then get the resource // specified by the user or the default config file. if(override == null || "false".equalsIgnoreCase(override)) { String configurationOptionStr = OptionConverter.getSystemProperty( DEFAULT_CONFIGURATION_KEY, null); String configuratorClassName = OptionConverter.getSystemProperty( CONFIGURATOR_CLASS_KEY, null); URL url = null; // if the user has not specified the log4j.configuration // property, we search first for the file "log4j.xml" and then // "log4j.properties" if(configurationOptionStr == null) { url = Loader.getResource(DEFAULT_XML_CONFIGURATION_FILE); if(url == null) { url = Loader.getResource(DEFAULT_CONFIGURATION_FILE); } } else { try { url = new URL(configurationOptionStr); } catch (MalformedURLException ex) { // so, resource is not a URL: // attempt to get the resource from the class path url = Loader.getResource(configurationOptionStr); } } // If we have a non-null url, then delegate the rest of the // configuration to the OptionConverter.selectAndConfigure // method. if(url != null) { LogLog.debug("Using URL ["+url+"] for automatic log4j configuration."); try { OptionConverter.selectAndConfigure(url, configuratorClassName, LogManager.getLoggerRepository()); } catch (NoClassDefFoundError e) { LogLog.warn("Error during default initialization", e); } } else { LogLog.debug("Could not find resource: ["+configurationOptionStr+"]."); } } else { LogLog.debug("Default initialization of overridden by " + DEFAULT_INIT_OVERRIDE_KEY + "property."); } }

static 메서드에서 보면 해당경로에서 읽는 것을 확인할 수 있다. 때문에 어플리케이션이 시작되면 여기서 파일을 읽는다.

그럼 중간에 바꾸려면 어떻게 해야할까?

LogManager 에서 아래 2개를 변경해야 한다

1) RootLevel 변경

2) Package 기준 Level 변경

다음처럼 변경할 수 있다

String packageName = "com.deoklab.app"; Level level = Level.WARN; LogManager.getRootLogger().setLevel(level); LogManager.getLogger(packageName).setLevel(level);

packageName의 경우는 프로젝트의 Root 패키지 이름을 가져오면 된다. 참고로 같은 방식을 설정을 log4j.properties 에다가 할때에는 다음처럼 설정한다

log4j.rootLoger=debug # root 로그 설정 log4j.logger.com.deoklab.app=WARN # 패키지별 로그 설정

그럼 다음처럼 메서드를 만든 후에 변경됐는지 확인해보자

... private void setLogLevel(String logLevel) { Level level; switch (logLevel.toUpperCase()) { case "TRACE": level = Level.TRACE; break; case "DEBUG": level = Level.DEBUG; break; case "INFO": level = Level.INFO; break; case "WARN": level = Level.WARN; break; case "ERROR": level = Level.ERROR; break; case "": level = Level.INFO; break; default: throw new WidetnsException("로그레벨이 잘못 설정되었습니다"); } // 변경기준 패키지명(root package name) String packageName = "com.deoklab.app"; // 변경 전 로그레벨 Level beforeLevelRoot = LogManager.getRootLogger().getLevel(); Level beforeLevelPackage = LogManager.getLogger(packageName).getLevel(); Logger loggerBefore = LoggerFactory.getLogger(packageName); System.out.println("loggerBefore root level=" + beforeLevelRoot); System.out.println("loggerBefore package debug=" + loggerBefore.isDebugEnabled()); System.out.println("loggerBefore package info=" + loggerBefore.isInfoEnabled()); System.out.println("loggerBefore package warn=" + loggerBefore.isWarnEnabled()); System.out.println("------------------------------------------"); // root level 변경 LogManager.getRootLogger().setLevel(level); // 패키지 기준 하위 레벨 변경 LogManager.getLogger(packageName).setLevel(level); Level LevelRootAfter = LogManager.getRootLogger().getLevel(); Logger loggerAfter = LoggerFactory.getLogger(packageName); System.out.println("loggerAfter root level=" + LevelRootAfter); System.out.println("loggerAfter package debug=" + loggerAfter.isDebugEnabled()); System.out.println("loggerAfter package info=" + loggerAfter.isInfoEnabled()); System.out.println("loggerAfter package warn=" + loggerAfter.isWarnEnabled()); // lombok의 @Slf4j를 사용하여 로그출력 log.info("log root level change {} => {}", beforeLevelRoot, level); log.info("log package level change {} => {}", beforeLevelPackage, level); } ...

로그 (WARN => INFO 로 변경)

loggerBefore root level=DEBUG loggerBefore package debug=false loggerBefore package info=false loggerBefore package warn=true ------------------------------------------ loggerAfter root level=INFO loggerAfter package debug=false loggerAfter package info=true loggerAfter package warn=true log root level change DEBUG => INFO log package level change WARN => INFO

잘 변경된 것을 확인할 수 있다.

내 경우 Lombok을 이용해서 @Slf4j를 사용하고 있는데 같이 적용된다.

끝.

from http://lemontia.tistory.com/1061 by ccl(A) rewrite - 2021-12-20 08:03:42