Creating a Logger
The package java.util.logging provides the logging capabilities via the class Logger.
Java code:
import java.util.logging.Logger;
private final static Logger LOGGER = Logger.getLogger(MyClass.class .getName());
Logging Levels
Once the logger created, (above we have created logger per class, so its static.) we can use it to log errors, or simple info or even the lowest detail of the user program.
So the levels are divided as follows:
Log Levels in descending order are:
- SEVERE (highest)
- WARNING
- INFO
- CONFIG
- FINE
- FINER
- FINEST
Java code to set logging level:
LOGGER.setLevel(Level.DEBUG);
package logging.example;
import java.util.logging.Logger;
public class HelloLogging {
private static Logger theLogger =
Logger.getLogger(HelloLogging.class.getName());
private String aMessage;
public HelloWorld(String message) {
aMessage = message;
}
public void sayHello() {
// use the 'least important' type of message, one at
// the 'finest' level.
theLogger.finest("Hello logging!");
System.err.println(aMessage);
}
}
Now in main simply call this class:
public static void main(String[] args) {
HelloLogger helloLog = new HelloLogger("Hello world logger!");
helloLog.sayHello();
}
As we have done logger level to finest we cannot get "Hello logging" on console. For this in sayHello we can write this:
theLogger.INFO("Hello logging!");
This will log "INFO" or higher level logs to the console.
Handler
Now we can handle these logs. By handling I mean is that we get the log message and export it to certain target accordingly. See Log handlers in Java APIs for this.
Formatter
Each handlers output can be configured with a formatter, which format the output in custom way before sent to display. See here for more.
Logger Inheritance
Loggers inherit certain characteristics from their parents when they are created, Typically a Logger will inherit the following:
- If a Logger is created with no Level set it will inherit the first Level it finds set in a Logger as it walks up the tree.
- The default setting is to use parent handlers so if you don't specify a handler explicitly LogRecords may still be published by parent Loggers.
- If a Logger has a null ResourceBundle name it will use the name given to its parent and so on.
Logging Convenience Methods
The default Logger implimentation has numerous convenience logging methods that can save a great deal of time when adding log messages to code. The convenience methods take one of two forms. Either "void info( String message )" or "void info( String sourceClass, String sourceMethod, String message )". The first version is sold to developers that want quick logging the second is to developers that want accurate logging. The second is more "accurate" because it explicitly names the source class and method, information that may be lost when the class is JITed. In reality I have never seen the first version turn out the wrong result (or no result which is more likely).
Logging Configuration
This section will have a bit of a Tomcat twist to it towards the end because most of my work is done with Tomcat. This is another area where Sun seem to have dropped the ball a little. There is no way using the basic Java logging framework to distinguish between different web applications in the same container if they use the same Logger. This means that if you had the same code deployed twice you wouldn't be able to tell where the log messages were coming from. Log4j solves that problem but for now we will stick to the default Java logging API and later I will show you a way round the problem.
Configuring Java Logging
Logging can be configured in three different ways: you can supply a properties file that describes the logging setup (by default this is called logging.properties and lives in JRE/lib/), you can provide a class that can be instantiated at VM initialisation that will configure the logging or you can roll your own logging configuration. I include rolling you own because I don't like either of the other two solutions much. The first means you have to play with a file that lives in one of hte VM distribution directories which, to my mind, is a bad thing. The second means adding another argument to the invocation of the VM which, IMHO, leads to screw ups. Either way, those are your options. I will focus mostly on the properties file as that is more commonly used. The class configuration technique is useful of you need to configure loggers from a database or other source but if you need something that complex you probably have enough time to "do it right".
The logging.properties file simply defines a number of Loggers, Handlers, Formatters and Filters that are constructed and ready to go shortly after the VM has loaded. Normally the top portion of the file is devoted to setting up Handlers for the root logger. The set up for the root Logger is a little different to the other Loggers because it doesn't have a name. To add handlers to the root logger include a line that begins handlers and then lists the handlers to add to the root logger. For instance this
handlers = java.util.logging.ConsoleHandler,
java.util.logging.FileHandler
will add a ConsoleHandler and FileHandler to the root logger. Next set the logging level of the root logger which is done with the name .level. To set it to all use
.level = ALL
To set the logging levels for the two handlers created add lines like this
java.util.logging.ConsoleHandler.level = INFO
java.util.logging.FileHandler.level = ALL
and finally to set a formatter simply specify its name like this
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
It is possible to set any of the instance variables on the Loggers, Handlers, Formatters and Filters in a similar manner by specifying its name followed by the property name you want to set. To set handlers on other loggers use the syntax loggerName.handlers=list_of_handler_class_names.
You can probably see the limitation in the default Java logging setup now. There is no way to separatly configure the handlers for different loggers because you have no way to seperate the names of the handlers - you have to refer to them by their class name.
Excellent article , you have indeed covered topic in details with code examples and explanation. I have also blogged some of my experience as 10 tips on logging in Java
ReplyDeleteThanks
Javin
10 tips on logging in Java