差異處

這裏顯示兩個版本的差異處。

連向這個比對檢視

下次修改
前次修改
java:log4j2:changeloglevelatruntime [2022/02/04 16:07]
tony 建立
java:log4j2:changeloglevelatruntime [2023/06/25 09:48] (目前版本)
行 9: 行 9:
 本篇文章主要分享在Log4j2可行的做法。範例程式可參考:​ [[https://​github.com/​frank007love/​Log4j2Practice/​tree/​master/​src/​test/​java/​org/​tonylin/​practice/​log4j2/​example1|link]]。 本篇文章主要分享在Log4j2可行的做法。範例程式可參考:​ [[https://​github.com/​frank007love/​Log4j2Practice/​tree/​master/​src/​test/​java/​org/​tonylin/​practice/​log4j2/​example1|link]]。
 ===== How to? ===== ===== How to? =====
 +==== SUT ====
 +<code java>
 +public class TestLogger {
 +    private static final Logger LOGGER = LoggerFactory.getLogger(TestLogger.class);​
 +    ​
 +    public static void debug(String message) {
 +        LOGGER.debug(message); ​  
 +    }
 +    ​
 +    public static void error(String message) {
 +        LOGGER.error(message); ​  
 +    }
 +}
 +</​code>​
 +==== Configuration properties ====
 +預設啟用了ConsoleAppender,而SUT的level是設為error;另外appender.console.follow設為true,讓Log4j可以反應system.out或system.err的變更,這主要和我們測試時會去攔截console有關:​
 +<​code>​
 +rootLogger.level = info
 +rootLogger.appenderRef.stdout.ref = STDOUT
 +
 +status = error
 +dest = err
 +name = PropertiesConfig
 +
 +filter.threshold.type = ThresholdFilter
 +filter.threshold.level = debug
 + 
 +appender.console.type = Console
 +appender.console.name = STDOUT
 +appender.console.follow = true
 +appender.console.layout.type = PatternLayout
 +appender.console.layout.pattern = %d %p %C{1.} [%t] %m%n
 +appender.console.filter.threshold.type = ThresholdFilter
 +appender.console.filter.threshold.level = trace
 +
 +logger.console.name = org.tonylin.practice.log4j2.example1
 +logger.console.level = error
 +logger.console.additivity = false
 +logger.console.appenderRef.rolling.ref = STDOUT
 +</​code>​
 +==== Unit Test ====
 +測試程式我使用了[[https://​github.com/​Hakky54/​console-captor|console-captor]] library讓我可以很容易去捕捉console內容;測試後我會透過Configurator.reconfigure去重置設置內容:​
 +<code java>
 +    private ConsoleCaptor captor;
 +
 +    @Before
 +    public void setup() {
 +        captor = new ConsoleCaptor();​
 +        Configurator.reconfigure();​
 +    }
 +
 +    @After
 +    public void teardown() {
 +      captor.close();​
 +    }
 +</​code>​
 +首先讓我們先測試debug level不會有console,而error level會有console且內容符合預期:​
 +<code java>
 +    @Test
 +    public void Should_NotSystemOutToConsole_When_LogDebugWithDefaultConfiguration() {   
 +        TestLogger.debug("​test debug"​);​
 +        assertEquals(0,​ captor.getStandardOutput().size());​
 +    }
 +
 +    @Test
 +    public void Should_SystemOutToConsole_When_LogErrorWithDefaultConfiguration() {
 +        TestLogger.error("​test error"​);​
 +        assertEquals(1,​ captor.getStandardOutput().size());​
 +        assertTrue(captor.getStandardOutput().get(0).contains("​test error"​));​
 +    }
 +</​code>​
 +接著就是本篇主角了,第一個方法是直接用Configurator去設定,雖然簡單,但這不是一個[[https://​logging.apache.org/​log4j/​2.x/​faq.html#​reconfig_level_from_code|public的API]],不建議在production code使用:
 +<code java>
 +    @Test
 +    public void Should_SystemOutToConsole_When_LogDebugAfterChangingLogLevelWithConfigurator() {
 +        Configurator.setLevel(TestLogger.class.getName(),​ Level.DEBUG);​
 +        ​
 +        TestLogger.debug("​test debug"​);​
 +        assertEquals(1,​ captor.getStandardOutput().size());​
 +        assertTrue(captor.getStandardOutput().get(0).contains("​test debug"​));​
 +    }
 +</​code>​
 +另外一個方法參考自[[https://​stackoverflow.com/​questions/​23434252/​programmatically-change-log-level-in-log4j2|這裡]],其實就是Configurator實作的方法(Configurator像是一個Utility的Class):​
 +<code java>
 +    @Test
 +    public void Should_SystemOutToConsole_When_LogDebugAfterChangingLogLevel() {
 +        LoggerContext ctx = (LoggerContext) LogManager.getContext(false);​
 +        Configuration config = ctx.getConfiguration();​
 +        LoggerConfig loggerConfig = config.getLoggerConfig(TestLogger.class.getName());​
 +        loggerConfig.setLevel(Level.DEBUG);​
 +        ctx.updateLoggers();​
 +        ​
 +        TestLogger.debug("​test debug"​);​
 +        assertEquals(1,​ captor.getStandardOutput().size());​
 +        assertTrue(captor.getStandardOutput().get(0).contains("​test debug"​));​
 +    }
 +</​code>​
 +註: LogManager.getContext(true)的真正作用情境還不曉得為何,有弄清楚後再分享。
 +===== Reference =====
 +  * [[https://​stackoverflow.com/​questions/​23434252/​programmatically-change-log-level-in-log4j2|Programmatically change log level in Log4j2]]
  
 =====    ===== =====    =====