Logging Levels
The logging API provides multiple levels of reporting and the ability to change to a different level during program execution. Thus, you can dynamically set the logging level to any of the following states:
Level
|
Effect
|
Numeric Value
|
OFF
|
No logging messages are reported.
|
Integer.MAX_VALUE
|
SEVERE
|
Only logging messages with the level SEVERE are reported.
|
1000
|
WARNING
|
Logging messages with levels of WARNING and SEVERE are reported.
|
900
|
INFO
|
Logging messages with levels of INFO and above are reported.
|
800
|
CONFIG
|
Logging messages with levels of CONFIG and above are reported.
|
700
|
FINE
|
Logging messages with levels of FINE and above are reported.
|
500
|
FINER
|
Logging messages with levels of FINER and above are reported.
|
400
|
FINEST
|
Logging messages with levels of FINEST and above are reported.
|
300
|
ALL
|
All logging messages are reported.
|
Integer.MIN_VALUE
|
You can even inherit from java.util.Logging.Level (which has protected constructors) and define your own level. This could, for example, have a value of less than 300, so the level is less than FINEST. Then logging messages at your new level would not appear when the level is FINEST.
You can see the effect of trying out the different levels of logging in the following example:
//: c15:LoggingLevels.java
import com.bruceeckel.simpletest.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.Handler;
import java.util.logging.LogManager;
public class LoggingLevels {
private static Test monitor = new Test();
private static Logger
lgr = Logger.getLogger("com"),
lgr2 = Logger.getLogger("com.bruceeckel"),
util = Logger.getLogger("com.bruceeckel.util"),
test = Logger.getLogger("com.bruceeckel.test"),
rand = Logger.getLogger("random");
private static void logMessages() {
lgr.info("com : info");
lgr2.info("com.bruceeckel : info");
util.info("util : info");
test.severe("test : severe");
rand.info("random : info");
}
public static void main(String[] args) {
lgr.setLevel(Level.SEVERE);
System.out.println("com level: SEVERE");
logMessages();
util.setLevel(Level.FINEST);
test.setLevel(Level.FINEST);
rand.setLevel(Level.FINEST);
System.out.println("individual loggers set to FINEST");
logMessages();
lgr.setLevel(Level.SEVERE);
System.out.println("com level: SEVERE");
logMessages();
monitor.expect("LoggingLevels.out");
}
} ///:~
The first few lines of main( ) are necessary because the default level of logging messages that will be reported is INFO and greater (more severe). If you do not change this, then the messages of level CONFIG and below will not be reported (try taking out the lines to see this happen).
You can have multiple logger objects in your program, and these loggers are organized into a hierarchical tree, which can be programmatically associated with the package namespace. Child loggers keep track of their immediate parent and by default pass the logging records up to the parent.
The “root” logger object is always created by default, and is the base of the tree of logger objects. You get a reference to the root logger by calling the static method Logger.getLogger(""). Notice that it takes an empty string rather than no arguments.
Each Logger object can have one or more Handler objects associated with it. Each Handler object provides a strategy[98] for publishing the logging information, which is contained in LogRecord objects. To create a new type of Handler, you simply inherit from the Handler class and override the publish( ) method (along with flush( ) and close( ), to deal with any streams you may use in the Handler).
The root logger always has one associated handler by default, which sends output to the console. In order to access the handlers, you call getHandlers( ) on the Logger object. In the preceding example, we know that there’s only one handler so we don’t technically need to iterate through the list, but it’s safer to do so in general because someone else may have added other handlers to the root logger. The default level of each handler is INFO, so in order to see all the messages, we set the level to ALL (which is the same as FINEST).
The levels array allows easy testing of all the Level values. The logger is set to each value and all the different logging levels are attempted. In the output you can see that only messages at the currently selected logging level, and those messages that are more severe, are reported.