Log4j + Separate Logger for specific classes or package

We may seen writing logger for entire application or separate DEBUG or ERROR log files. In this tutorial we will see how to set separate logger for specific package or specific class using log4j API.

Log4j + Separate Logger for specific classes or package

In above snapshot we can see 2 packages called "com.SeparateLoggerTest" and "com.newpackage". Where "newpackage" having 2 classes and we are trying to route logs of these classes to separate log file. Lets see simple sample how to achieve this.

log4j.properties

#------------------------------------------------
# Root logger option
#------------------------------------------------

log4j.rootLogger=DEBUG, applogger

# Redirect log messages to a log file, support file rolling.
log4j.appender.applogger=org.apache.log4j.RollingFileAppender
log4j.appender.applogger.File=C:\\log\\mainlog.log
log4j.appender.applogger.MaxFileSize=1MB
log4j.appender.applogger.MaxBackupIndex=5
log4j.appender.applogger.layout=org.apache.log4j.PatternLayout
log4j.appender.applogger.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

#------------------------------------------------
# Package logger option
#------------------------------------------------

log4j.logger.com.newpackage=DEBUG, packageLogger
log4j.additivity.com.newpackage=false

log4j.appender.packageLogger=org.apache.log4j.RollingFileAppender
log4j.appender.packageLogger.File=C:\\log\\separatepackage.log
log4j.appender.packageLogger.MaxFileSize=1MB
log4j.appender.packageLogger.MaxBackupIndex=5
log4j.appender.packageLogger.layout=org.apache.log4j.PatternLayout
log4j.appender.packageLogger.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n


In above log4j.properties file we can see section under "Package logger option" separate logger for complete package classes "com.newpackage". Also log4j.additivity.com.newpackage will used to manage logger write options.
If we set "false" then it will write logs only in separate log file which mentioned under package logger.
If we set "true" then logs will written in both root log file as well under package logger.

MainClass.java

package com.SeparateLoggerTest;

import org.apache.log4j.Logger;

import com.newpackage.SpecialPackageClass_1;
import com.newpackage.SpecialPackageClass_2;


public class MainClass {
 
 final static Logger logger = Logger.getLogger(MainClass.class);
 
    public static void main( String[] args ) {
     
     logger.info("Hello Logger ::::::::::::: "+new MainClass().getClass());
     
        new SpecialPackageClass_1().myMethod();
        new SpecialPackageClass_2().myMethod();
    }
}


SpecialPackageClass_1.java

package com.newpackage;

import org.apache.log4j.Logger;

public class SpecialPackageClass_1 {
 
 final static Logger logger = Logger.getLogger(SpecialPackageClass_1.class);
 
    public void myMethod() {
     
     logger.info("Hello Logger ::::::::::::: "+new SpecialPackageClass_1().getClass());
     
    }
}


SpecialPackageClass_2.java

package com.newpackage;

import org.apache.log4j.Logger;

public class SpecialPackageClass_2 {
 
 final static Logger logger = Logger.getLogger(SpecialPackageClass_2.class);
 
    public void myMethod() {
     
     logger.info("Hello Logger ::::::::::::: "+new SpecialPackageClass_2().getClass());
     
    }
}



OUTPUT:

mainlog.log

Log4j + Separate Logger for specific classes or package


separatepackage.log

Log4j + Separate Logger for specific classes or package

Static Vs Volatile variables in Multi-threading

We all know that Static variables and methods will be associated with the class, rather than with any object. Every instance of the class shares a class variable (static), which is in one fixed location in memory. Any object can change the value of a class variable, but class variables can also be manipulated without creating an instance of the class.

In that case how Static differs from Volatile under Multi-threading?

Declaring static variable means there will be only copy associated with class it doesn’t matter how many object get created for that class. The static variable will be accessible even with no Objects created at all. Thread may have locally cached values of it.

This means that if two threads update a variable of the same Object concurrently, and the variable is not declared volatile, there could be a case in which one of the threads has in cache an old value. Even if you access a static value through multiple threads, each thread can have its local cached copy!

But a volatile variable will keep only one copy in memory and shared across the threads.

Lets assume a class with static and volatile variables, with 2 threads accessing it.

public class MyTestClass {

 int normalInt;
 static int staticInt;
 volatile int volatileInt;

}


Static Vs Volatile variables in Multithreading

Default Method in Interface - Java 8

 
Java 8 comes lots of new features and in one important feature is Default method in Interface. Till Java 7 we can have only abstract methods in interface and we can't have any method definition in interfaces. In Java 8 we can have default method nothing but method with definition, following example will show you how to write those methods.

Next we can ask, why we need Default method in interface?

Lets assume we need to introduce new method in interface and then it breaks all classes implementing those interfaces by compile time error. For example if interface used in hundreds of classes which can break millions of line code by asking to implement new method introduced in Interface.
Even in JDK we can see foreach default method introduced to entire collection classes by giving definition in Iterable interface. Below is the Oracle API docs snapshot for Iterable interface.

Interface Default method in Java 8

Suppose if we don't have default method feature then JDK need to come-up with millions of code change in all collection classes by giving those method implementation.

Next we may ask whats the difference between Java 8 interface and Abstract method?

Interfaces cannot have state associated with them but Abstract classes can have state associated with them.

Next how to solve Multiple Inheritance Ambiguity Problems with default methods?

Since we can implement multiple interface, also we can have same default method (with same name) in 2 different interface. When we implement those interfaces in concrete class compile will give a warning that

"Duplicate default methods named <method_name> with the parameters () and () are inherited from the types <Interface1> and <Interface2>"

To solve this we can Override default method from any 1 interface. Below example will give detail about how to use default method in interface and to solve Ambiguity Problems with 2 interface have same default method.

FirstInterface.java

public interface FirstInterface {

 public void method();
 
 default public String methodName(){
  return "FirstInterface";
 }
}


SecondInterface.java

public interface SecondInterface {
 
 public void method();
 
 public default String methodName(){
  return "SecondInterface";
 }
}


TestClass.java

public class TestClass implements FirstInterface, SecondInterface {

 @Override
 public void method() {
  System.out.println("Hello Java Discover :) ");
 }
 
 /*
  * To solve Ambiguity Problems we can override 
  * default method as below.
  */
 @Override
 public String methodName(){
  return FirstInterface.super.methodName();
 }

 
 public static void main(String[] args) {
  new TestClass().testInterface();
 }
 
 private void testInterface(){
  method();
  System.out.println(FirstInterface.super.methodName());
  System.out.println(SecondInterface.super.methodName());
 }
 
}


OUTPUT:

Hello Java Discover :) 
FirstInterface
SecondInterface

If we see above example 2 interfaces having default method with same name. When we implement those interfaces in our concrete class (TestClass.java) we will get compile time error as

"Duplicate default methods named methodName with the parameters () and () are inherited from the types SecondInterface and FirstInterface"

To overcome this we need to override default method in our class as above. Next we can call default methods by using Interface names as we called in testInterface() method.
  • FirstInterface.super.methodName()
  • SecondInterface.super.methodName()