Logback Change Log Level at Runtime Example
1. Introduction
In this post, we feature a comprehensive Example on Logback Change Log Level. Logback is one of the most widely used logging frameworks in the Java community. Most applications set the logger level to INFO
in the production environment, but sometimes we need more detailed logging messages to troubleshoot issues and would like to change the logger lever at runtime. In this example, I will demonstrate how to change logger level in two ways:
- Update the logger level with
LoggerContext
. - Enable the
scan
option in thelogback.xml
, so it will detect and apply the change automatically.
2. Technologies Used
The example code in this article was built and run using:
- Java 1.8.101
- Maven 3.3.9
- Logback 1.2.3
- Eclipse Oxygen
3. Maven Java Application
There are many ways to create a Maven Java application. The easiest way for me is via Eclipse. Please click here for detailed steps.
3.1 Manage Dependencies
Pom.xml
manages the project dependencies.
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>jcg.zheng.demo</groupId> <artifactId>logback-changelevel-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>Mary Zheng demo for logback change level</name> <properties> <maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.source>1.8</maven.compiler.source> </properties> <dependencies> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-access</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.2.3</version> </dependency> </dependencies> </project>
3.2 Java Application
Create a java application to update the logger level at runtime.
ChangeLogLevelDemo.java
package jcg.zheng.demo; import java.util.Arrays; import java.util.List; import java.util.Scanner; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.LoggerContext; public class ChangeLogLevelDemo { private final Logger lOG = LoggerFactory.getLogger(this.getClass()); private final static List VALID_LEVELS = Arrays.asList("TRACE", "DEBUG", "INFO", "WARN", "ERROR"); private static Scanner scanner; public static void main(String[] args) { ChangeLogLevelDemo demo = new ChangeLogLevelDemo(); scanner = new Scanner(System.in); demo.step("some log message"); String updateLogLevel = null; do { System.out.println("Enter Logback Logger Level - TRACE, DEBUG, INFO, WARN, ERROR! "); System.out.println("q to quit, anything else to repeat this message: "); updateLogLevel = scanner.nextLine(); if (VALID_LEVELS.contains(updateLogLevel)) { setLogLevel(updateLogLevel, "jcg.zheng.demo"); demo.step("log message after level change"); } } while (!updateLogLevel.equalsIgnoreCase("q")); scanner.close(); } public void step(String logmessage) { if (lOG.isTraceEnabled()) { lOG.trace("Start step for {}", logmessage); } if (lOG.isDebugEnabled()) { lOG.debug("Start step for {}", logmessage); } if (lOG.isInfoEnabled()) { lOG.info("Start step {}", logmessage); } if (lOG.isWarnEnabled()) { lOG.warn("Start step {}", logmessage); } if (lOG.isErrorEnabled()) { lOG.error("Start step {}", logmessage); } } private static void setLogLevel(String logLevel, String packageName) { LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory(); ch.qos.logback.classic.Logger logger = loggerContext.getLogger(packageName); System.out.println(packageName + " current logger level: " + logger.getLevel()); System.out.println(" You entered: " + logLevel); logger.setLevel(Level.toLevel(logLevel)); } }
Note:
- Line 31: Invoke
setLogLevel
to change logger level - Line 66: Obtain
LoggerContext
fromLoggerFactory.getILoggerFactory()
- Line 72: update the logger level via the
setLevel
method
3.3 Logback Configuration
Create a logback.xml
with the scan
option enabled. It automatically detects the configuration file change and applies accordingly.
logback.xml
<!-- demo the debug value difference --> <configuration debug="true" scan="true" scanPeriod="10 seconds"> <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <charset>UTF-8</charset> <Pattern>%d %-4relative [%thread] %-5level %logger{35} - %msg%n </Pattern> </encoder> </appender> <logger name="jcg.zheng.demo" level="info" additivity="false"> <appender-ref ref="consoleAppender" /> </logger> <root level="error"> <appender-ref ref="consoleAppender" /> </root> </configuration>
4. Demo
In this step, I will demonstrate how to update the logger level at runtime:
- Start
ChangeLogLevelDemo
as a Java application. - Enter the “ERROR” level.
- Watch the console outputting the messages.
- Repeat steps 2 and 3 for other logger levels – DEBUG, WARN, TRACE.
- Update
logback.xml
logger level from “INFO” to “DEBUG”. - Wait 10 seconds
- Watch the console logging messages.
Application console Log
Console Log
16:33:27,972 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback-test.xml] 16:33:27,972 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback.groovy] 16:33:27,972 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Found resource [logback.xml] at [file:/C:/gitworkspace/logback-clevel-demo/target/classes/logback.xml] 16:33:28,088 |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - Will scan for changes in [file:/C:/gitworkspace/logback-clevel-demo/target/classes/logback.xml] 16:33:28,088 |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - Setting ReconfigureOnChangeTask scanning period to 10 seconds 16:33:28,090 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - About to instantiate appender of type [ch.qos.logback.core.ConsoleAppender] 16:33:28,094 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [consoleAppender] 16:33:28,101 |-INFO in ch.qos.logback.core.joran.action.NestedComplexPropertyIA - Assuming default type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for [encoder] property 16:33:28,138 |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting level of logger [jcg.zheng.demo] to ERROR 16:33:28,138 |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting additivity of logger [jcg.zheng.demo] to false 16:33:28,138 |-INFO in ch.qos.logback.core.joran.action.AppenderRefAction - Attaching appender named [consoleAppender] to Logger[jcg.zheng.demo] 16:33:28,139 |-INFO in ch.qos.logback.classic.joran.action.RootLoggerAction - Setting level of ROOT logger to ERROR 16:33:28,139 |-INFO in ch.qos.logback.core.joran.action.AppenderRefAction - Attaching appender named [consoleAppender] to Logger[ROOT] 16:33:28,139 |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - End of configuration. 16:33:28,140 |-INFO in ch.qos.logback.classic.joran.JoranConfigurator@2eafffde - Registering current configuration as safe fallback point 2018-08-15 16:33:28,147 209 [main] ERROR jcg.zheng.demo.ChangeLogLevelDemo - Start step some log message Enter Logback Logger Level - TRACE, DEBUG, INFO, WARN, ERROR! q to quit, anything else to repeat this message: ERROR jcg.zheng.demo current logger level: ERROR You entered: ERROR 2018-08-15 16:33:34,863 6925 [main] ERROR jcg.zheng.demo.ChangeLogLevelDemo - Start step log message after level change Enter Logback Logger Level - TRACE, DEBUG, INFO, WARN, ERROR! q to quit, anything else to repeat this message: DEBUG jcg.zheng.demo current logger level: ERROR You entered: DEBUG 2018-08-15 16:35:16,786 108848 [main] DEBUG jcg.zheng.demo.ChangeLogLevelDemo - Start step for log message after level change 2018-08-15 16:35:16,787 108849 [main] INFO jcg.zheng.demo.ChangeLogLevelDemo - Start step log message after level change 2018-08-15 16:35:16,787 108849 [main] WARN jcg.zheng.demo.ChangeLogLevelDemo - Start step log message after level change 2018-08-15 16:35:16,787 108849 [main] ERROR jcg.zheng.demo.ChangeLogLevelDemo - Start step log message after level change Enter Logback Logger Level - TRACE, DEBUG, INFO, WARN, ERROR! q to quit, anything else to repeat this message: WARN jcg.zheng.demo current logger level: DEBUG You entered: WARN 2018-08-15 16:35:20,597 112659 [main] WARN jcg.zheng.demo.ChangeLogLevelDemo - Start step log message after level change 2018-08-15 16:35:20,597 112659 [main] ERROR jcg.zheng.demo.ChangeLogLevelDemo - Start step log message after level change Enter Logback Logger Level - TRACE, DEBUG, INFO, WARN, ERROR! q to quit, anything else to repeat this message: TRACE jcg.zheng.demo current logger level: WARN You entered: TRACE 2018-08-15 16:35:26,435 118497 [main] TRACE jcg.zheng.demo.ChangeLogLevelDemo - Start step for log message after level change 2018-08-15 16:35:26,435 118497 [main] DEBUG jcg.zheng.demo.ChangeLogLevelDemo - Start step for log message after level change 2018-08-15 16:35:26,435 118497 [main] INFO jcg.zheng.demo.ChangeLogLevelDemo - Start step log message after level change 2018-08-15 16:35:26,435 118497 [main] WARN jcg.zheng.demo.ChangeLogLevelDemo - Start step log message after level change 2018-08-15 16:35:26,436 118498 [main] ERROR jcg.zheng.demo.ChangeLogLevelDemo - Start step log message after level change Enter Logback Logger Level - TRACE, DEBUG, INFO, WARN, ERROR! q to quit, anything else to repeat this message: ttt Enter Logback Logger Level - TRACE, DEBUG, INFO, WARN, ERROR! q to quit, anything else to repeat this message: 16:36:08,082 |-INFO in ReconfigureOnChangeTask(born:1534368808085) - Detected change in configuration files. 16:36:08,082 |-INFO in ReconfigureOnChangeTask(born:1534368808085) - Will reset and reconfigure context named [default] 16:36:08,082 |-INFO in ReconfigureOnChangeTask(born:1534368808085) - Detected change in configuration files. 16:36:08,082 |-INFO in ReconfigureOnChangeTask(born:1534368808085) - Will reset and reconfigure context named [default] 16:36:08,085 |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - Will scan for changes in [file:/C:/gitworkspace/logback-clevel-demo/target/classes/logback.xml] 16:36:08,085 |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - Setting ReconfigureOnChangeTask scanning period to 10 seconds 16:36:08,086 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - About to instantiate appender of type [ch.qos.logback.core.ConsoleAppender] 16:36:08,086 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [consoleAppender] 16:36:08,086 |-INFO in ch.qos.logback.core.joran.action.NestedComplexPropertyIA - Assuming default type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for [encoder] property 16:36:08,087 |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting level of logger [jcg.zheng.demo] to INFO 16:36:08,087 |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting additivity of logger [jcg.zheng.demo] to false 16:36:08,087 |-INFO in ch.qos.logback.core.joran.action.AppenderRefAction - Attaching appender named [consoleAppender] to Logger[jcg.zheng.demo] 16:36:08,087 |-INFO in ch.qos.logback.classic.joran.action.RootLoggerAction - Setting level of ROOT logger to ERROR 16:36:08,087 |-INFO in ch.qos.logback.core.joran.action.AppenderRefAction - Attaching appender named [consoleAppender] to Logger[ROOT] 16:36:08,087 |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - End of configuration. 16:36:08,087 |-INFO in ch.qos.logback.classic.joran.JoranConfigurator@76d42a65 - Registering current configuration as safe fallback point
5. Summary
In this article, I demonstrated how to change the logger level at runtime, one via LoggerContext
, the other via the configuration file.
6. Download the Source Code
This example consists of a Java application to demonstrate how to update the Logback logger level at Runtime.
You can download the full source code of this example here: Logback Change Log Level at Runtime Example
Does this work when you build a jar-file and the logback.xml is inside the jar?