How do I create a custom logger Formatter?

To create a custom Formatter we need to extend the java.util.logging.Formatter abstract class and implements the format(LogRecord) method. In the method then we can format the log message stored in the LogRecord to match our need.

The java.util.logging.Formatter class also have the getHead(Handler) and getTail(Handler) which can be overridden to add a head and a tail to our log message.

package org.kodejava.util.logging;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.*;

public class LogCustomFormatter {
    public static void main(String[] args) {
        Logger logger = Logger.getLogger(LogCustomFormatter.class.getName());
        logger.setUseParentHandlers(false);

        MyFormatter formatter = new MyFormatter();
        ConsoleHandler handler = new ConsoleHandler();
        handler.setFormatter(formatter);

        logger.addHandler(handler);
        logger.info("Example of creating custom formatter.");
        logger.warning("A warning message.");
        logger.severe("A severe message.");
    }
}

class MyFormatter extends Formatter {
    // Create a DateFormat to format the logger timestamp.
    private static final DateFormat df = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss.SSS");

    public String format(LogRecord record) {
        StringBuilder builder = new StringBuilder(1000);
        builder.append(df.format(new Date(record.getMillis()))).append(" - ");
        builder.append("[").append(record.getSourceClassName()).append(".");
        builder.append(record.getSourceMethodName()).append("] - ");
        builder.append("[").append(record.getLevel()).append("] - ");
        builder.append(formatMessage(record));
        builder.append("\n");
        return builder.toString();
    }

    public String getHead(Handler h) {
        return super.getHead(h);
    }

    public String getTail(Handler h) {
        return super.getTail(h);
    }
}

Below is an output produced by the custom formatter above.

08/10/2021 07:55:55.153 - [org.kodejava.util.logging.LogCustomFormatter.main] - [INFO] - Example of creating custom formatter.
08/10/2021 07:55:55.164 - [org.kodejava.util.logging.LogCustomFormatter.main] - [WARNING] - A warning message.
08/10/2021 07:55:55.164 - [org.kodejava.util.logging.LogCustomFormatter.main] - [SEVERE] - A severe message.

How do I prevent the logger send log messages to its parent logger?

To prevent log records being forwarded to the logger’s parent handlers we can set false the useParentHandlers field using the Logger.setUserParentHandlers(boolean useParentHandlers) method.

package org.kodejava.util.logging;

import java.util.logging.Logger;
import java.util.logging.ConsoleHandler;

public class NoParentLogger {
    public static void main(String[] args) {
        Logger logger = Logger.getLogger(NoParentLogger.class.getName());

        // Do not forward any log messages the logger parent handlers.
        logger.setUseParentHandlers(false);

        // Specify a ConsoleHandler for this logger instance.
        logger.addHandler(new ConsoleHandler());
        logger.info("Logging an information message.");
    }
}

How do I set the formatter of logger handlers?

In this example we’ll see how to set the formatter for the logger handlers. We set the formatter by calling the Handler.setFormatter() method. In the code below we set a SimpleFormatter for our FileHandler handler and XMLFormatter for the ConsoleHandler handler.

This SimpleFormatter format the log in a plain text information while on the other side the XMLFormatter format the log record in XML format.

package org.kodejava.util.logging;

import java.util.logging.*;
import java.io.IOException;

public class LogFormatter {
    public static void main(String[] args) {
        Logger logger = Logger.getLogger(LogFormatter.class.getName());

        try {
            // Create a FileHandler that will log to mylog.txt with a
            // SimpleFormatter.
            FileHandler simpleHandler = new FileHandler("mylog.txt", true);
            simpleHandler.setFormatter(new SimpleFormatter());
            logger.addHandler(simpleHandler);

            // Create a ConsoleHandler that will log to the console with
            // an XMLFormatter.
            ConsoleHandler consoleHandler = new ConsoleHandler();
            consoleHandler.setFormatter(new XMLFormatter());
            logger.addHandler(consoleHandler);

            // Do not send the message to parent handlers.
            logger.setUseParentHandlers(false);
        } catch (IOException e) {
            logger.log(Level.SEVERE, "Fail to create logger file handler.", e);
        }

        logger.info("Logging application information message.");
        logger.warning("Logging application warning message.");
    }
}

How do I compare Logger Level severity?

In this example we see how we can compare the Level severity between two levels. The Level class has an intValue() method that return the integer value of Level‘s severity.

package org.kodejava.util.logging;

import java.util.logging.Level;

public class LogLevelSeverityCompare {
    public static void main(String[] args) {
        Level info = Level.INFO;
        Level warning = Level.WARNING;
        Level finest = Level.FINEST;

        // To compare the Level severity we compare the intValue of the Level.
        // Each level is assigned a unique integer value as the severity
        // weight of the level.
        if (info.intValue() < warning.intValue()) {
            System.out.printf("%s (%d) is less severe than %s (%d)%n",
                    info, info.intValue(), warning, warning.intValue());
        }

        if (finest.intValue() < info.intValue()) {
            System.out.printf("%s (%d) is less severe than %s (%d)%n",
                    finest, finest.intValue(), info, info.intValue());
        }
    }
}

When we run the program above will see the following result:

INFO (800) is less severe than WARNING (900)
FINEST (300) is less severe than INFO (800)

How do I get the current Level of a Logger?

Here we demonstrate how to obtain the current level of the Logger instance. The log level will be inherited from the parent logger when the level is not set explicitly .

package org.kodejava.util.logging;

import java.util.logging.Logger;
import java.util.logging.Level;

public class LoggerGetLevel {
    private static Logger logger = Logger.getLogger(LoggerGetLevel.class.getName());

    public static void main(String[] args) {
        LoggerGetLevel demo = new LoggerGetLevel();
        System.out.println("demo.getLevel(logger) = " + demo.getLevel(logger));

        logger.setLevel(Level.WARNING);
        System.out.println("demo.getLevel(logger) = " + demo.getLevel(logger));
    }

    public Level getLevel(Logger logger) {
        Level level = logger.getLevel();
        if (level == null && logger.getParent() != null) {
            level = logger.getParent().getLevel();
        }
        return level;
    }
}

How do I set the Logger log level?

In this example you see how we can change or set the Logger log level. The log level will tell the Logger which particular log message will be logged.

Logger will only record the log message if the level is equal or higher than the Logger level. For instance when the level set to Level.SEVERE, no message other than message logged with Logger.severe(String message) of Logger.log(Level level, String message) will be logged.

package org.kodejava.util.logging;

import java.util.logging.Logger;
import java.util.logging.Level;

public class LogLevelSetting {
    // Obtains a Logger instance, it will create one if it is not already exist.
    private static final Logger logger = Logger.getLogger(LogLevelSetting.class.getName());

    public static void main(String[] args) {
        // Set the log level to Level.INFO, the severe message will be logged.
        logger.setLevel(Level.INFO);
        logger.severe("This message will be logged.");

        // Set the log level to Level.SEVERE, the warning message will not be
        // logged as Level.WARNING is smaller than Level.SEVERE
        logger.setLevel(Level.SEVERE);
        logger.warning("This message won't be logged.");

        // Turn of the log, no message will be logged.
        logger.setLevel(Level.OFF);
        logger.info("All log is turned off.");

        // Turn the logger back on, this will result all the corresponding
        // logger message below will be logged.
        logger.setLevel(Level.ALL);
        logger.info("Information message.");
        logger.warning("Warning message.");
        logger.severe("Severe message.");
    }
}

If we run the program above will see the following result displayed. In the output below we see that the "This message won't be logged." is not displayed.

Oct 08, 2021 7:12:53 AM org.kodejava.util.logging.LogLevelSetting main
SEVERE: This message will be logged.
Oct 08, 2021 7:12:54 AM org.kodejava.util.logging.LogLevelSetting main
INFO: Information message.
Oct 08, 2021 7:12:54 AM org.kodejava.util.logging.LogLevelSetting main
WARNING: Warning message.
Oct 08, 2021 7:12:54 AM org.kodejava.util.logging.LogLevelSetting main
SEVERE: Severe message.

How do I set a filter on a logger handler?

This example give you an example on how to set the Filter of a logger handler. In the code below we implement the Filter on the FileHandler to log only a Level.SEVERE message. Other log level will not be recorded to the file.

package org.kodejava.util.logging;

import java.util.logging.*;
import java.io.IOException;

public class LoggerFilter {
    public static void main(String[] args) {
        Logger logger = Logger.getLogger(LoggerFilter.class.getName());

        FileHandler handler = null;
        try {
            handler = new FileHandler("myapp.log");
            // The message will be recorded to the file When the 
            // LogRecord level is equals to Level.SEVERE
            handler.setFilter(record -> record.getLevel().equals(Level.SEVERE));
        } catch (IOException e) {
            logger.log(Level.SEVERE, "Fail to create logger handler", e);
        }

        logger.addHandler(handler);

        logger.info("Information message");
        logger.warning("Warning message");
        logger.severe("Severe message");
    }
}

How do I use Logger’s MemoryHandler class?

In this example we demonstrate the use of Logger‘s MemoryHandler to log only when some conditions happen in our application, for example when a Level.SEVERE message is logged.

We create an instance of MemoryHandler that will delegate the log to FileHandler class, and it logs the last 100 record until a Level.SEVERE message is logged.

package org.kodejava.util.logging;

import java.util.logging.Logger;
import java.util.logging.FileHandler;
import java.util.logging.MemoryHandler;
import java.util.logging.Level;

public class MemoryHandlerDemo {
    public static void main(String[] args) {
        MemoryHandlerDemo demo = new MemoryHandlerDemo();
        try {
            demo.testMethod();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void testMethod() throws Exception {
        Logger logger = Logger.getLogger(MemoryHandlerDemo.class.getName());
        FileHandler fileHandler = new FileHandler("myapp.log");

        // Create a MemoryHandler that will dump the log messages for the 
        // latest 100 records when a Level.SEVERE log is logged to by the
        // Logger class.
        MemoryHandler memoryHandler = new MemoryHandler(fileHandler, 100, Level.SEVERE);
        logger.addHandler(memoryHandler);

        // Write some messages to the log
        logger.info("Information message");
        logger.warning("Warning message");

        // This causes the log messages dump to the file log.
        logger.severe("Severe message");
    }
}

To check if the message is logged you can open the myapp.log file created by this small program.

How do I use logger ConsoleHandler?

In this example you’ll see how to add ConsoleHandler to the Logger instance. It is simple, just create an instance of ConsoleHandler and add it to the Logger using the Logger.addHandler() method.

package org.kodejava.util.logging;

import java.util.logging.Logger;
import java.util.logging.ConsoleHandler;
import java.util.logging.Level;

public class LogConsoleHandler {
    public static void main(String[] args) {
        // Obtains Logger instance
        Logger logger = Logger.getLogger(LogConsoleHandler.class.getName());

        // Add ConsoleHandler to Logger.
        ConsoleHandler consoleHandler = new ConsoleHandler();
        logger.addHandler(consoleHandler);

        if (logger.isLoggable(Level.INFO)) {
            logger.info("This is information message for testing ConsoleHandler");
        }
    }
}

How do I write log to a file?

An application log need to be persisted so that we can analyze the log when an error occurred in our application. For this reason we need to write to log into a file.

The Logging API provide handlers which helps us to do this. To write log to a file we can use the FileHandler. We define the name of our log file and the appendable mode in this class constructor. For example, you can look at the code presented below.

package org.kodejava.util.logging;

import java.util.logging.FileHandler;
import java.util.logging.Logger;
import java.util.logging.Level;
import java.io.IOException;

public class WriteLogToFile {
    public static void main(String[] args) throws IOException {
        Logger logger = Logger.getLogger(WriteLogToFile.class.getName());

        // Create an instance of FileHandler that write log to a file called
        // app.log. Each new message will be appended at the at of the log file.
        FileHandler fileHandler = new FileHandler("app.log", true);
        logger.addHandler(fileHandler);

        if (logger.isLoggable(Level.INFO)) {
            logger.info("Information message");
        }

        if (logger.isLoggable(Level.WARNING)) {
            logger.warning("Warning message");
        }

    }
}