How to programmatically set Java Logging defaults and override these defaults using logging.properties

The Java Logging APIs provide a number of properties for create and configuring  Java loggers.  If you plan to create a new Java Logger for your project, it may be very desirable to define a default configuration you logger and handlers. It is also desirable to enable users to override these defaults using the JVM logging.properties file. Why is this desirable? The JVM logging.properties ships with a default configuration. This default configuration may not meet your project requirements. For example, logging.properties sets up a console handler by default. Perhaps,by default, your application should log only to a file, not the console. Or, perhaps, your application requires a dedicated log file. In this post, we will discuss how you can create a logger that meets your application requirements and allows users to customize the logger to meet their  specific needs.

For an overview of the Java Logging APIs, including a description of loggers and handlers, see this post.

During this post, we will explorer 2 key factors for creating a custom logger:

1. How to define the default behavior for your logger.
– Does the logger log to a file?
– Does the logger create a new log file once the log grows to some predefined size? Etc

2. How to enable users to customize your logger and override its defaults.

Let’s get started.

1. How to define the default behavior for your logger.

One can programmatically define properties on a logger very easily. Here’s how…

    // Create a logger and set its level to WARNING
    Logger logger = Logger.getLogger("com.cdimasci.logger.MyLogger");
    logger.setLevel(Level.WARNING);

    // Create a handler and register it with your logger
    // Define a pattern for the handler
    String pattern = "%h/MyLogger%g.log";

    // Optionally define other properties e.g. limit, count, and append
    FileHandler handler = new MyFileHandler(pattern, 10000000, 5, true);

    // Add the handler to the logger
    logger.addHandler(handler);

So, what did we do?
The code above creates a new logger. The logger uses a custom file handler that logs records to a file. The custom file handler will create a log file in the user”s home directory (%h). Once the log file grows to 10MB, a new log file will be created. We will keep up to 5 log files.  Log files will be named like, MyLogger0.log.

Sidebar: Here is a complete list of the substitution variables available for pattern.

So, this is pretty cool, but unfortunately, since we programmatically defined properties e.g. the logger’s level and the file handler’s pattern, etc, the user cannot customize these properties. In the next section, we’ll explorer how to enable a user to override/customize these properties.

2. How to enable users to customize your logger and override its defaults.

Let’s continue with our example from section 1. In section 1, we created a new logger named, com.cdimascio.logger.MyLogger. We also added a file handler to our logger. The fully qualified path of our file handler is com.cdimasci.logger.MyFileHandler.

To summarize, we have a logger:

com.cdimascio.logger.MyLogger

and a file handler:

com.cdimasci.handler.MyFileHandler

Using logging.properties, a user can configure our logger’s properties and our file handler’s properties declaritively.

For example:

# disable parent handlers, including global handlers
com.cdimascio.logger.useParentHandlers=false
# add a file handler
com.cdimascio.logger.MyLogger.level=INFO
com.cdimascio.handler.MyFileHandler.pattern=%h/CoolLog%g.log
com.cdimascio.handler.MyFileHandler.limit=20000000
com.cdimascio.handler.MyFileHandler.count=20

Unfortunately, our logger will not yet honor this configuration.

Let’s now see how to ensure it does!

The key is to use the Java Logging APIs’ LogManager. LogManager provides programattic access to properties configured in logging.properties. Using LogManager, we can read these user defined values by simply specifying their keys.

Here’s how…

   // Get the log manager instance
   LogManager logManager = LogManager.getLogManager();

    // Get the value of level for MyLogger as specified by the user
    String loggerLevel= logManager.getProperty("com.cdimascio.logger.MyLogger.level");

    // Get the pattern as configured by the user
    String handlerPattern = logManager.getProperty("com.cdimascio.handler.MyFileHandler.pattern");

    // Create a logger
    // Create a handler
    // ...
 }

Finally, to programmattically disable globally registered handlers, one can do the following:


Logger glogger= Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
for(Handler handler : gLogger.getHandlers()) {
    gLogger.removeHandler(handler);
}

Thank you!

You may also like...

Leave a Reply