Getting started with Java Logging

[Updated: May 25, 2017, Created: May 5, 2017]

This tutorial of Java Logging shows a getting-started example and then a quick high level understanding of Java Util logging (also known as JUL) design.

Logging messages

To log messages, we need to get instance of java.util.logging.Logger. We can do that via static factory method: Logger.getLogger(). This method finds or creates a named logger instance.

public class MyClass {
  private static final Logger LOGGER = Logger.getLogger(MyClass.class.getName());

  public static void main(String[] args) {
      System.out.println("main method starts");
      LOGGER.info("in MyClass");
  }
}

Output

main method starts
May 17, 2017 11:55:51 AM com.logicbig.example.MyClass main
INFO: in MyClass

Java Logging, a high level overview

Logger: A named entity to which user application sends messages.
Handler: A specific handler is typically tied to a specific logging destination. A destination is where final formatted messages are sent. A handler can apply any additional logic, e.g. to improve performance.
Examples: ConsoleHandler, FileHandler, SocketHandler, user defined ones.
Level: Used by Logger/Handler. To discard messages if the Level of a given message is less than the Level associated with the Logger/Handler.
Filter: Used by Logger/Handler. It can filter message which cannot be filtered based on Levels. A dynamic/programmatic way to filter messages.
Formatter: To display messages in a specific format.
Examples: SimpleFormatter, XMLFormatter or user defined ones
Resource      Bundle: A Logger may have a ResourceBundle associated with it. It is used to map raw message strings with localized message strings.

Hierarchical Loggers

Loggers are organized in a hierarchical namespace. The recommended namespace should follow the package naming style of the Java classes. For example we can create loggers with following names:
Logger1 > "com.logicbig"
Logger2 > "com.logicbig.MyClass2" > parent namespace= "com.logicbig"
Logger3 > "com.logicbig.MyClass3" > parent namespace= "com.logicbig"

In above example Logger1 is the parent of Logger2 and Logger3. If we setup Logger1 with specific properties (Level, Handler, Formatter etc) then those properties will be inherited to their children. A child is free to setup it's own properties to selectively override the parent ones.

An application will always has a 'root' logger. The root Logger (named "") has no parent.

Configuration, Setting up logging properties

We can load logging properties in one of following ways (in the order of priority):

  1. Using JVM system property: java.util.logging.config.class=com.logicbig.example.MyConfigClass.
    Java will load MyConfigClass during startup. The constructor of this class can use following method to initialize logging properties:
    LogManager.getLogManager().readConfiguration(InputStream);
    In this initializing class, we can also setup base/individual Loggers like this:
    Logger mainLogger = Logger.getLogger("com.logicbig.example");
    mainLogger.setLevel(Level.FINEST);
    mainLogger.addHandler(....);
     ....        
  2. Using JVM system property: java.util.logging.config.file = D:\myApp\logging.properties . Please see next for the format of such file.
  3. If neither of the above properties is defined then LogManager will use lib/logging.properties in the Java installation directory.
    For example C:\Java\jdk1.8.0_111\jre\lib\logging.properties:
    ############################################################
    #  	Default Logging Configuration File
    #
    # You can use a different file by specifying a filename
    # with the java.util.logging.config.file system property.
    # For example java -Djava.util.logging.config.file=myfile
    ############################################################
    
    ############################################################
    #  	Global properties
    ############################################################
    
    # "handlers" specifies a comma separated list of log Handler
    # classes.  These handlers will be installed during VM startup.
    # Note that these classes must be on the system classpath.
    # By default we only configure a ConsoleHandler, which will only
    # show messages at the INFO and above levels.
    handlers= java.util.logging.ConsoleHandler
    
    # To also add the FileHandler, use the following line instead.
    #handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler
    
    # Default global logging level.
    # This specifies which kinds of events are logged across
    # all loggers.  For any given facility this global level
    # can be overriden by a facility specific level
    # Note that the ConsoleHandler also has a separate level
    # setting to limit messages printed to the console.
    .level= INFO
    
    ############################################################
    # Handler specific properties.
    # Describes specific configuration info for Handlers.
    ############################################################
    
    # default file output is in user's home directory.
    java.util.logging.FileHandler.pattern = %h/java%u.log
    java.util.logging.FileHandler.limit = 50000
    java.util.logging.FileHandler.count = 1
    java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter
    
    # Limit the message that are printed on the console to INFO and above.
    java.util.logging.ConsoleHandler.level = INFO
    java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
    
    # Example to customize the SimpleFormatter output format
    # to print one-line log message like this:
    #     <level>: <log message> [<date/time>]
    #
    # java.util.logging.SimpleFormatter.format=%4$s: %5$s [%1$tc]%n
    
    ############################################################
    # Facility specific properties.
    # Provides extra control for each logger.
    ############################################################
    
    # For example, set the com.xyz.foo logger to only log SEVERE
    # messages:
    com.xyz.foo.level = SEVERE
    

See Also