Tag Archives: JMX

Changing Java Logging Levels At Runtime

How to control Java Logger runtime levels? There are many approaches and each logging framework has their own peculiarities. This information is readily available, but surprisingly not many examples are given.

[This is a repost; somehow it got lost]

Here I show a programmatic example using the java.util.logging library; Log4J, SLF4J, and others have similar capability. In listing 1 below, I create three named loggers and two threads.

The first thread will loop and randomly pick a logger and a specific logging level to log a message. If it is blocked, not meeting the current threshold level, another message is output.

The other thread will randomly set a threshold level to one of the created loggers (including the root logger).

Example output

Starting logRunner.
Starting managerRun.
[logger3]: blocked: 'FINEST' 
******* Setting logger "global" to level "WARNING" 
[logger2]: blocked: 'FINER' 
[logger2]: blocked: 'FINE' 
Feb 27, 2011 11:34:25 AM Main2$1 run
SEVERE: [logger2]: not blocked!
Feb 27, 2011 11:34:27 AM Main2$1 run
INFO: [logger3]: not blocked!
Feb 27, 2011 11:34:28 AM Main2$1 run
SEVERE: [logger3]: not blocked!
[logger3]: blocked: 'ALL' 
[logger2]: blocked: 'FINER' 
[logger3]: blocked: 'FINER' 
[logger2]: blocked: 'FINER' 
******* Setting logger "global" to level "ALL" 
[logger3]: blocked: 'FINE' 
[logger2]: blocked: 'FINER' 
[logger2]: blocked: 'FINER' 
[logger2]: blocked: 'FINER' 
Feb 27, 2011 11:34:37 AM Main2$1 run
WARNING: [logger2]: not blocked!
Feb 27, 2011 11:34:38 AM Main2$1 run
INFO: [logger1]: not blocked!
[logger2]: blocked: 'FINE' 

Note:
If your IDE can, this is easier to follow using console colorization. On Eclipse, Grep Console is great; I used the expression, .*blocked:.*, to highlight the blocked lines.

Listing one

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;
import java.util.logging.LoggingMXBean;
import static java.lang.System.*; 

/**
 * 
 * Simple example of runtime Logger level setting.
 * 
 * @author jbetancourt
 *
 */
public class Main2 {
	
	public static Random random = new Random(); 
	
	public static Object lock = new Object();
	
	public static List<String> loggerNames;
	public static List<Logger> loggers;
	
	
	
	/**  
	 * Create two threads to illustrate concept.  
	 * 
	 * One thread will continually choose a logger and a level to log a message.  
	 * The other thread will randomly set a random logger to a random threshold level.   
	 * The first thread will log at a level or show that it is blocked
	 *  
	 * @author Josef Betancourt
	 */
	public static void main(String[] args) {		
		loggers = new ArrayList<Logger>();
		loggers.add(Logger.getLogger("logger1"));
		loggers.add(Logger.getLogger("logger2"));
		loggers.add(Logger.getLogger("logger3"));
		
		
		final LoggingMXBean mxBean = LogManager.getLoggingMXBean();
		final List<String> loggerNames = mxBean.getLoggerNames();
		
		final List<Level> levels = Arrays.asList(
				Level.ALL,Level.FINE,Level.FINER,
				Level.FINEST,Level.INFO,Level.WARNING,
				Level.SEVERE);
		
		
		Runnable logRunner = new Runnable() {		
			@Override
			public void run() {
				System.out.println("Starting logRunner.");
				while(true){
					Level levelToUse =levels.get(random.nextInt(7));
					
					Logger logger = loggers.get(random.nextInt(loggers.size()));
					
					if(logger.isLoggable(levelToUse)){
						logger.log(levelToUse, String.format("[%s]: not blocked!",
								logger.getName()));
					}else{
						out.println(String.format("[%s]: blocked: '%s' ",
								logger.getName(),levelToUse.getName()));
					}
					
					try {
						synchronized (lock) {
							lock.notifyAll();
							Thread.currentThread().sleep(1000);							
						}
					} catch (InterruptedException e) {
						// don't care.	
					}
				}				
			}
		};		
		
		Runnable managerRun = new Runnable(){
			@Override
			public void run() {
				System.out.println("Starting managerRun.");
				while(true){
					Level level = levels.get(random.nextInt(7));					
					String logName = loggerNames.get(
							random.nextInt(loggerNames.size()));
					
					out.println(String.format(
							"******* Setting logger \"%s\" to level \"%s\" ",
							logName, level.getName()));
					
					mxBean.setLoggerLevel(logName, level.getName());
					
					try {
						synchronized (lock) {
							lock.notifyAll();							
						}
						
						Thread.currentThread().sleep(10000);
					} catch (InterruptedException e) {
						// don't care
					}

				}
				
			}
		};
		
		Executors.newSingleThreadExecutor().execute(logRunner);
		Executors.newSingleThreadExecutor().execute(managerRun);
		
	}	
} // end class Main2


Note:
This is probably not a good example of threading code. Wasn’t the point.

Updates
Dec 21, 2013: Fixed link to the the logging overview API page.

Further Reading

Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License.