Java Advanced Features




Subscribe To Our Newsletter
You will receive our latest post and tutorial.
Thank you for subscribing!

required
required


Java Advanced – log4j

Logging is a very important part of software development. A well-written logging code offers quick debugging, easy maintenance, and structured storage of an application’s runtime information.

Logging does have its drawbacks also. It can slow down an application. If too verbose, it can cause scrolling blindness. To alleviate these concerns, log4j is designed to be reliable, fast and extensible.

Since logging is rarely the main focus of an application, the log4j API strives to be simple to understand and to use.

Log4j is fast, threadsafe, uses multiple levels, namely ALL, TRACE, DEBUG, INFO, WARN, ERROR and FATAL and more.

In this tutorial, we are going to learn how to use log4j in your application.

Include the log4j jar file in your classpath or include this dependency in your maven file

<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

 

Create a log4j property file and put it into the root folder.

log4j.rootLogger=TRACE, consoleAppender, fileAppender
 
log4j.appender.consoleAppender=org.apache.log4j.ConsoleAppender
log4j.appender.consoleAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.consoleAppender.layout.ConversionPattern=[date: %d{yyyy-MM-dd HH:mm:ss}] [priority: %-5p] [thread: %t] [memberUuid: %X{memberUuid}]  [class&line: %c{2}.%M:%L] [msg: %m]%n

# log to file
log4j.appender.fileAppender=org.apache.log4j.RollingFileAppender
log4j.appender.fileAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.fileAppender.layout.ConversionPattern=[date: %d{yyyy-MM-dd HH:mm:ss}] [priority: %-5p] [thread: %t] [memberUuid: %X{memberUuid}]  [class&line: %c{2}.%M:%L] [msg: %m]%n
log4j.appender.fileAppender.File=application.log

 

But let’s break down the ConversionPattern layout. You can refer to its documentation here.

%d{yyyy-MM-dd HH:mm:ss} = Date and time format, refer to SimpleDateFormat JavaDoc.
%-5p = The logging priority, like DEBUG or ERROR. The -5 is optional, for the pretty print format.
%c{1} = The logging name we set via getLogger(), refer to log4j PatternLayout guide.
%M = Used to output the method name where the logging request was issued. WARNING Generating caller location information is extremely slow and should be avoided unless execution speed is not an issue.
%L = The line number from where the logging request.
%t = Used to output the name of the thread that generated the logging event.
%m%n = The message to log and line break.
%X = Used to output the MDC (mapped diagnostic context) associated with the thread that generated the logging event. The X conversion character must be followed by the key for the map placed between braces, as in %X{clientNumber} where clientNumber is the key. The value in the MDC corresponding to the key will be output.

For an application to have appropriate logs, you must have at least a console logs and a file containing logs. You can see the logs at real time while debugging and also you can go back to a previous log for a specific point in time.

You can even save your logs into a database

# Define the root logger with appender file
log4j.rootLogger = DEBUG, DB

# Define the DB appender
log4j.appender.DB=org.apache.log4j.jdbc.JDBCAppender

# Set JDBC URL
log4j.appender.DB.URL=jdbc:mysql://localhost/DBNAME

# Set Database Driver
log4j.appender.DB.driver=com.mysql.jdbc.Driver

# Set database user name and password
log4j.appender.DB.user=user_name
log4j.appender.DB.password=password

# Set the SQL statement to be executed.
log4j.appender.DB.sql=INSERT INTO LOGS VALUES('%x','%d','%C','%p','%m')

# Define the layout for file appender
log4j.appender.DB.layout=org.apache.log4j.PatternLayout

create a database table

CREATE TABLE LOGS
   (USER_ID VARCHAR(20)    NOT NULL,
    DATED   DATE           NOT NULL,
    LOGGER  VARCHAR(50)    NOT NULL,
    LEVEL   VARCHAR(10)    NOT NULL,
    MESSAGE VARCHAR(1000)  NOT NULL
);

 

Create a Logger field.

Logger log = Logger.getLogger(MainLog.class);

Log levels

Trace – Designates finer-grained informational events than the DEBUG.

Debug – Designates fine-grained informational events that are most useful to debug an application.

Info – Designates informational messages that highlight the progress of the application at coarse-grained level.

Warn – Designates potentially harmful situations.

Error – Designates error events that might still allow the application to continue running.

Fatal – Designates very severe error events that will presumably lead the application to abort.

All – All levels including custom levels.

Off – The highest possible rank and is intended to turn off logging.

import org.apache.log4j.PropertyConfigurator;

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

public class MainLog {

    static Logger log = Logger.getLogger(MainLog.class);

    public static void main(String[] args) {

        PropertyConfigurator.configure("log4j.properties");

        log.trace("Trace Message Logged !!!");
        log.debug("Debug Message Logged !!!");
        log.info("Info Message Logged !!!");
        log.error("Error Message Logged !!!");
        log.fatal("Fatal Message Logged !!!");
        
    }

}
[date: 2020-10-18 01:58:20] [priority: TRACE] [thread: main] [memberUuid: ]  [class&line: lovemesomecoding.MainLog.main:16] [msg: Trace Message Logged !!!]
[date: 2020-10-18 01:58:20] [priority: DEBUG] [thread: main] [memberUuid: ]  [class&line: lovemesomecoding.MainLog.main:17] [msg: Debug Message Logged !!!]
[date: 2020-10-18 01:58:20] [priority: INFO ] [thread: main] [memberUuid: ]  [class&line: lovemesomecoding.MainLog.main:18] [msg: Info Message Logged !!!]
[date: 2020-10-18 01:58:20] [priority: ERROR] [thread: main] [memberUuid: ]  [class&line: lovemesomecoding.MainLog.main:19] [msg: Error Message Logged !!!]
[date: 2020-10-18 01:58:20] [priority: FATAL] [thread: main] [memberUuid: ]  [class&line: lovemesomecoding.MainLog.main:20] [msg: Fatal Message Logged !!!]

 

March 18, 2020

Java Advanced – Database

Java uses the JDBC library to connect and manupilate databases. JDBC works with Java on a variety of platforms, such as Windows, Mac OS, and the various versions of UNIX.

 

Create Database Connection

First, you need a connection. To create a connection, you need the username, password, and host for the database you want to connect to. Here I have a Enum to create a connection factory.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public enum DBConnection {

    INSTANCE("java_jdbc");

    private Connection connection = null;

    private String     database;

    private DBConnection(String database) {
        this.database = database;
        String URL = "jdbc:mysql://localhost:3306/" + database + "?createDatabaseIfNotExist=true&useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC";
        String USER = "root";
        String PASS = "";

        try {
            connection = DriverManager.getConnection(URL, USER, PASS);
        } catch (SQLException e) {
            System.out.println("SQLException, msg=" + e.getLocalizedMessage());
            e.printStackTrace();
        }
    }

    public Connection getConnection() {

        return connection;
    }

    public String getDatabase() {
        return this.database;
    }

}

 

Create a table

public static void createTable() {
    System.out.println("creating " + TABLE_NAME + " table...");
    DB_CONNECTION = DBConnection.INSTANCE.getConnection();
    Statement stmt = null;
    try {
        stmt = DB_CONNECTION.createStatement();
    } catch (SQLException e) {
        System.out.println("SQLException, msg=" + e.getLocalizedMessage());
        e.printStackTrace();
    }

    System.out.println("Check if table " + TABLE_NAME + " already exists.");
    // @formatter:off
    String checkTableSQL = "SELECT COUNT(*) as tableCount " + 
            "FROM INFORMATION_SCHEMA.TABLES " + 
            "WHERE TABLE_SCHEMA = '"+DBConnection.INSTANCE.getDatabase()+"' "+
            "AND TABLE_NAME = '"+TABLE_NAME+"'; "; 
    // @formatter:on

    try {
        System.out.println("SQL QUERY: " + checkTableSQL);
        ResultSet resultSet = stmt.executeQuery(checkTableSQL);
        resultSet.next();
        int tableCount = resultSet.getInt("tableCount");

        if (tableCount > 0) {
            System.out.println("dropping " + TABLE_NAME + " table.");
            System.out.println("SQL QUERY: " + "DROP TABLE " + TABLE_NAME + "; ");
            boolean removedTable = stmt.execute("DROP TABLE " + TABLE_NAME + "; ");
            System.out.println("table dropped " + removedTable);
        }

    } catch (SQLException e) {
        System.out.println("SQLException, msg=" + e.getLocalizedMessage());
        e.printStackTrace();
    }
    System.out.println("creating " + TABLE_NAME + " table.");
    // @formatter:off
    String createTableSQL = "CREATE TABLE "+TABLE_NAME+" " +
            "(id INTEGER NOT NULL AUTO_INCREMENT, " +
            " first_name VARCHAR(255), " + 
            " last_name VARCHAR(255), " + 
            " age INTEGER, " + 
            " PRIMARY KEY ( id )); "; 
    // @formatter:on

    try {
        System.out.println("SQL QUERY: " + createTableSQL);
        stmt.executeUpdate(createTableSQL);
    } catch (SQLException e) {
        System.out.println("SQLException, msg=" + e.getLocalizedMessage());
        e.printStackTrace();
    }
    System.out.println(TABLE_NAME + " table has been created!\n\n");
}

Insert data into a table

public static void insertDataToTable() {
    System.out.println("inserting data into " + TABLE_NAME + " table...");
    DB_CONNECTION = DBConnection.INSTANCE.getConnection();
    try {
        DB_CONNECTION.setAutoCommit(false);
    } catch (SQLException e) {
        System.out.println("SQLException, msg=" + e.getLocalizedMessage());
        e.printStackTrace();
    }

    // load users
    try {
        for (int i = 0; i < NUMBER_OF_USERS; i++) {
            StringBuilder query = new StringBuilder();
            query.append("INSERT INTO user (first_name, last_name, age) ");
            query.append("VALUES (?, ?, ?); ");
            System.out.println("SQL QUERY: " + query.toString());

            /**
             * Use prepareStatement to insert data into the query and avoid SQL injection
             */
            PreparedStatement pStmnt = DB_CONNECTION.prepareStatement(query.toString(), Statement.RETURN_GENERATED_KEYS);
            String firstName = ConstantUtils.getRandomFirstname();
            String lastName = ConstantUtils.getRandomLastname();
            int age = RandomGeneratorUtils.getIntegerWithin(1, 51);
            pStmnt.setString(1, firstName);
            pStmnt.setString(2, lastName);
            pStmnt.setInt(3, age);

            System.out.println("parameter 1: " + firstName);
            System.out.println("parameter 2: " + lastName);
            System.out.println("parameter 3: " + age);

            int numOfRowsCreated = pStmnt.executeUpdate();

            if (numOfRowsCreated > 0) {
                int id = 0;
                ResultSet rs = pStmnt.getGeneratedKeys();
                if (rs.next()) {
                    id = rs.getInt(1);
                }
                System.out.println("new id: " + id);
            }

        }

        DB_CONNECTION.commit();
    } catch (SQLException e) {
        System.out.println("SQLException, msg=" + e.getLocalizedMessage());

        e.printStackTrace();

        try {
            DB_CONNECTION.rollback();
        } catch (SQLException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
    } finally {
    }

    System.out.println(TABLE_NAME + " table has been populated with " + NUMBER_OF_USERS + " rows!\n\n");
}

 

 

Read data from a table

public static void readDataFromTable(int selectedId) {
    System.out.println("reading data from " + TABLE_NAME + " table...");
    DB_CONNECTION = DBConnection.INSTANCE.getConnection();

    try {
        DB_CONNECTION.setAutoCommit(false);
    } catch (SQLException e) {
        System.out.println("SQLException, msg=" + e.getLocalizedMessage());
        e.printStackTrace();
    }

    ResultSet rs = null;
    PreparedStatement pStmnt = null;
    // Read user
    try {
        StringBuilder query = new StringBuilder();
        query.append("SELECT id, first_name, last_name, age ");
        query.append("FROM user ");
        query.append("WHERE id = ? ");
        System.out.println("SQL QUERY: " + query.toString());

        pStmnt = DB_CONNECTION.prepareStatement(query.toString());
        pStmnt.setInt(1, selectedId);
        System.out.println("parameter 1: " + selectedId);

        rs = pStmnt.executeQuery();
        DB_CONNECTION.commit();

        rs.next();

        User user = User.generateUserFromResultset(rs);
        System.out.println(user.toString());

    } catch (SQLException e) {
        System.out.println("SQLException, msg=" + e.getLocalizedMessage());
        e.printStackTrace();
    } finally {
        try {
            if (rs != null) {
                rs.close();
            }

            if (pStmnt != null) {
                pStmnt.close();
            }
        } catch (SQLException e) {
            System.out.println(e.getMessage());
        }
    }

    System.out.println("Row with id=" + selectedId + " has been retrived from " + TABLE_NAME + ".\n\n");
}

 

Update data from a table

public static void updateDataInTable(int selectedId) {
    System.out.println("updating data in " + TABLE_NAME + " table...");
    DB_CONNECTION = DBConnection.INSTANCE.getConnection();
    try {
        DB_CONNECTION.setAutoCommit(false);
    } catch (SQLException e) {
        System.out.println("SQLException, msg=" + e.getLocalizedMessage());
        e.printStackTrace();
    }

    // Update user
    try {
        StringBuilder query = new StringBuilder();
        query.append("UPDATE user ");
        query.append("SET first_name = ? ");
        query.append(", age = ? ");
        query.append("WHERE id = ? ");
        System.out.println("SQL QUERY: " + query.toString());

        PreparedStatement pStmnt = DB_CONNECTION.prepareStatement(query.toString());
        int age = RandomGeneratorUtils.getIntegerWithin(1, 51);
        String firstName = "Folau";

        pStmnt.setString(1, firstName);
        pStmnt.setInt(2, age);
        pStmnt.setInt(3, selectedId);

        System.out.println("parameter 1: " + firstName);
        System.out.println("parameter 2: " + age);
        System.out.println("parameter 3: " + selectedId);

        pStmnt.executeUpdate();

        DB_CONNECTION.commit();
    } catch (SQLException e) {
        System.out.println("SQLException, msg=" + e.getLocalizedMessage());
        e.printStackTrace();

        try {
            DB_CONNECTION.rollback();
        } catch (SQLException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }

    }

    System.out.println(TABLE_NAME + " table has been updated for row with id=" + selectedId + "!\n\n");
}

Transaction

  1. Set autocommit to false
    DB_CONNECTION.setAutoCommit(false);
  2. Commit changes when things are ok
    DB_CONNECTION.commit();
  3. Roll back when things are not ok
    DB_CONNECTION.rollback();
  4.  
public static void updateDataInTable(int selectedId) {
    System.out.println("updating data in " + TABLE_NAME + " table...");
    DB_CONNECTION = DBConnection.INSTANCE.getConnection();
    try {
        DB_CONNECTION.setAutoCommit(false);
    } catch (SQLException e) {
        System.out.println("SQLException, msg=" + e.getLocalizedMessage());
        e.printStackTrace();
    }

    // Update user
    try {
        StringBuilder query = new StringBuilder();
        query.append("UPDATE user ");
        query.append("SET first_name = ? ");
        query.append(", age = ? ");
        query.append("WHERE id = ? ");
        System.out.println("SQL QUERY: " + query.toString());

        PreparedStatement pStmnt = DB_CONNECTION.prepareStatement(query.toString());
        int age = RandomGeneratorUtils.getIntegerWithin(1, 51);
        String firstName = "Folau";

        pStmnt.setString(1, firstName);
        pStmnt.setInt(2, age);
        pStmnt.setInt(3, selectedId);

        System.out.println("parameter 1: " + firstName);
        System.out.println("parameter 2: " + age);
        System.out.println("parameter 3: " + selectedId);

        pStmnt.executeUpdate();

        DB_CONNECTION.commit();
    } catch (SQLException e) {
        System.out.println("SQLException, msg=" + e.getLocalizedMessage());
        e.printStackTrace();

        try {
            DB_CONNECTION.rollback();
        } catch (SQLException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }

    }

    System.out.println(TABLE_NAME + " table has been updated for row with id=" + selectedId + "!\n\n");
}

 

Source code on Github

 

October 17, 2019

Java Advanced – Multithreading

October 17, 2018