Logging
The Logger class provides a convenient way to generate log files in your programs.
The following method can be used to configure a logger named, name
, that will write to a log file called filename
.
The third argument determines the format of the log file. It will use a simple format unless "XML"
is passed as the third argument, in which case, the log file will use an XML format.
private static boolean configureLogger(String name, String filename, String format) {
Logger logger = Logger.getLogger(name);
try {
FileHandler handler = new FileHandler(filename);
logger.addHandler(handler);
switch (format == null ? "" : format) {
case "XML" -> handler.setFormatter(new XMLFormatter());
default -> handler.setFormatter(new SimpleFormatter());
}
logger.setUseParentHandlers(false);
logger.info("Log file initialized");
} catch (IOException e) {
System.err.println("Warning: error initializing log file. Logging disabled.");
logger = null;
}
return logger != null;
}
Using the logger is pretty simple. You just need to call configureLogger()
at the beginning of your program. Then anywhere you wish to add a log entry
to the log file, you just need to call one of the following on the logger object:
severe()
, warning()
, or info()
. With each call, you should pass the message
that you wish to be logged. For example, the logger.info("Log file initiatized");
call in the method above adds something like the following to the log file:
Dec 09, 2024 6:22:33 AM wk15.LogExample configureLogger
INFO: Log file initialized
In the above example, configureLogger
was a method in the wk15.LogExample
class.
Once the logger object has been configured, it is possible to get access to the logger object anywhere else in the code. Only the name of the logger object needs to be known.
Logger logger = Logger.getLogger(name);
This will cause the local variable logger
to point to the logger object created in
configureLogger()
.
Appending to Log Files
The example above will overwrite the previous log file. To append to the log file,
pass true
as a second argument to the FileHandler
constructor on line 4.
Severity Levels
There may be times when we are interested in more detailed information in our logs and other times when we'd like to limit the information written to log files. For example, when performing internal testing, more verbose logs may be appropriate; however, we may not want to expose all of that information to the end user.
The setLevel()
method in the Logger
class sets the level of logging. Once set
the logger will only log messages at that level of severity or higher.
The Level class
provides the following levels:
OFF
— disables logging of all messagesSEVERE
WARNING
INFO
CONFIG
FINE
FINER
FINEST
ALL
— enables logging of all messages
The default level is INFO
.
Singleton Design Pattern
Careful readers may have noticed that configureLogger()
does not
make use of a constructor. In fact, the constructors for the Logger
class do not have public visibility, so it is not possible to instantiate
a Logger
object in the traditional way. This is by design.
The Logger
design makes use of the singleton pattern. This pattern is
used when we would like to have one single, global object that is shared
throughout the code. The constructors for this class are hidden. Instead,
a static
method, getLogger()
is used to gain access to the single
logger object. The first time getLogger("log.txt")
is called, a Logger
object is constructed and returned. On all subsequent calls, a reference
to the already existing object is returned.