PROGRAMMING

m9/ JAVA
REMEMBERS




Last update:   26-07-2021

Logger

We create a logger object using the getLogger static method. The we are logging messages at different levels.
 
import java.util.logging.Level;
import java.util.logging.Logger;

class LoggerApp {
    public static void main(String[] args) {
        
        final Logger LOGGER = 
            Logger.getLogger(LoggerApp.class.getName()); // {}

        LOGGER.info("Logger name: " + LOGGER.getName());

        int[] numbers = {1, 2, 3};

        try {
            int current = numbers[4];
        } catch(ArrayIndexOutOfBoundsException ex) {
            LOGGER.log(Level.SEVERE, "Exception: ", ex);
        }
    }
}

/*

Jun 22, 2021 10:55:46 AM LoggerApp main
INFO: Logger name: LoggerApp
Jun 22, 2021 10:55:46 AM LoggerApp main
SEVERE: Exception: 
java.lang.ArrayIndexOutOfBoundsException: Index 4 out of bounds for length 3
        at LoggerApp.main(LoggerApp.java:15)

*/
... 17 lines
 

HANDLER

! The handler is responsible for printing the log message. This example generates a xml log file and console messages.
 
import java.io.IOException;
import java.util.logging.ConsoleHandler;
import java.util.logging.FileHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;

class LoggerApp {
    public static void main(String[] args) throws IOException {
        
        final Logger LOGGER = 
            Logger.getLogger(LoggerApp.class.getName()); // {}

        Handler handler1 = new ConsoleHandler();
        Handler handler2 = new FileHandler("./LogerApp.log");

        LOGGER.addHandler(handler1);
        LOGGER.addHandler(handler2);

        handler1.setLevel(Level.ALL);
        handler2.setLevel(Level.ALL);
        LOGGER.setLevel(Level.ALL);

        LOGGER.config("Loggger configuration done");
    }
}

/* 

-- LoggerApp.log --

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE log SYSTEM "logger.dtd">
<log>
<record>
  <date>2021-06-22T08:19:39.914918Z</date>
  <millis>1624349979914</millis>
  <nanos>918000</nanos>
  <sequence>0</sequence>
  <logger>LoggerApp</logger>
  <level>CONFIG</level>
  <class>LoggerApp</class>
  <method>main</method>
  <thread>1</thread>
  <message>Loggger configuration done</message>
</record>
</log>

*/
... 33 lines
 
Formater    (2/3)

FORMATER

A Formater is used to format the log. Java provides two built-in formaters SimpleFormat and XMLFormat.
 
import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;

class LoggerApp {
    public static void main(String[] args) throws IOException {
        
        final Logger LOGGER = 
            Logger.getLogger(LoggerApp.class.getName()); // {}

        Handler h = new FileHandler("./LogerApp.formatter.log");        
        LOGGER.addHandler(h);
        LOGGER.setLevel(Level.ALL);

        Formatter f = new SimpleFormatter();
        h.setFormatter(f);
        h.setLevel(Level.ALL);
        
        LOGGER.info("My simple message");
    }
}

/* 

-- LogerApp.formatter.log --

Jun 22, 2021 12:18:17 PM LoggerApp main
INFO: My simple message

*/
... 19 lines
 

CONFIG

! You can provide a configuration properties file. This helps to remove the configuration from code.
 
import java.io.FileInputStream;
import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Handler;
import java.util.logging.LogManager;
import java.util.logging.Logger;

class LoggerApp {
    public static void main(String[] args) throws IOException {
        
        final Logger LOGGER = Logger.getLogger("myLogger");
        
        final LogManager MANAGER = LogManager.getLogManager();
        MANAGER.readConfiguration(
            new FileInputStream("LoggerApp.properties")
        );

        Handler h = new FileHandler("./LogerApp.log");        
        LOGGER.addHandler(h);

        LOGGER.log(Level.INFO, "My simple message");
    }
}

/* 

-- LoggerApp.properties --

handlers=java.util.logging.FileHandler
.level=ALL
java.util.logging.FileHandler.level=ALL
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
myLogger.level=ALL

-- LoggerApp.log --

Jun 22, 2021 1:11:50 PM LoggerApp main
INFO: My simple message

*/
... 23 lines
 

SEQUENCE

Create an instance of FileHandler with 5 files sequence. Set a specific size for each file + append flag set to true.
 
import java.io.FileInputStream;
import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Handler;
import java.util.logging.LogManager;
import java.util.logging.Logger;

class LoggerApp {
    public static void main(String[] args) throws IOException {
        
        Logger LOGGER = Logger.getLogger("myLogger");
        
        LogManager MANAGER = LogManager.getLogManager();
        MANAGER.readConfiguration(
            new FileInputStream("LoggerApp.properties")
        );

        final int FILE_SIZE = 1024; // default 1000000 (1 MB) 
        final int LIMIT = 5;
        Handler h = 
            new FileHandler("./app.log", FILE_SIZE, LIMIT, true);       
        LOGGER.addHandler(h);

        for(int i=0; i<30; i++) { // loop to generate 2 files
            LOGGER.info("My log message");
        }
    }
}

/*

-- Gemerates 2 log files (from maximum 5 permitted) --

app.log.0
app.log.1

*/
... 22 lines
 
Log4j    (3/3)

LOG4J

The logging framework is something you don't want to be bundled with the JVM. Java default logger isn't well suited for multiple applications in the same JVM. Also, log4j is thread-safe and optimize for speed.
 
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

class LoggerApp {
    public static void main(String[] args) {
        PropertyConfigurator.configure("./log4j.properties");
        Logger logger = Logger.getLogger("myLogger");
        logger.debug("My debug message");
        logger.info("My info message");
    }
}

/* 
-- logs/myapp.log --

My debug message
My info message
*/
... 9 lines
 
 
# log4j.properties 

log4j.rootLogger = DEBUG, FILE  
log4j.appender.FILE=org.apache.log4j.FileAppender  
log4j.appender.FILE.File=./logs/myapp.log 
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout 
You can change the root logger level. Logging can be redirected to both console and file.
 
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

class LoggerApp {
    public static void main(String[] args) {
        PropertyConfigurator.configure("./log4j.properties");
        Logger logger = Logger.getLogger("myLogger");
        logger.debug("My debug message"); // this will be ignored
        logger.info("My info message");
    }
}

/*

-- logs/myapp.log --

My info message

*/
... 8 lines
 
 
# log4j.properties

log4j.rootLogger = INFO, FILE, stdout
log4j.appender.FILE=org.apache.log4j.FileAppender  
log4j.appender.FILE.File=./logs/myapp.log 
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout  

log4j.appender.stdout=org.apache.log4j.ConsoleAppender 
log4j.appender.stdout.Target=System.out  
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout  
... 2 lines
 

Questions    
Constructors