Java – How to create different log files for different packages using same log4j logger

javalog4jlogging

I'm trying to set up separate log files for different packages. I'm using a Wrapper class for a log4j logger. Every class in my application calls same wrapper class. My wrapper class:

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

It is called like this:

MyLogger.write(, , );

Is there a way to configure log4j so that it outputs logging of different packages to different files?

Thanks!

Edit:

Here is my log4j.properties file:

log4j.rootLogger=DEBUG, infoout, aar
log4j.logger.com.businessservice.datapopulation=DEBUG, aar
log4j.additivity.com.businessservice.datapopulation=false

log4j.appender.infoout = org.apache.log4j.RollingFileAppender
log4j.appender.infoout.file=/app/aar_frontend.log
log4j.appender.infoout.append=true
log4j.appender.infoout.Threshold=DEBUG
log4j.appender.infoout.MaxFileSize=2MB
log4j.appender.infoout.MaxBackupIndex=10
log4j.appender.infoout.layout = org.apache.log4j.PatternLayout
log4j.appender.infoout.layout.ConversionPattern = %m%n

log4j.appender.aar = org.apache.log4j.RollingFileAppender
log4j.appender.aar.file=/app/aar/aar_backend.log
log4j.appender.aar.append=true
log4j.appender.aar.Threshold=DEBUG
log4j.appender.aar.MaxFileSize=2MB
log4j.appender.aar.MaxBackupIndex=10
log4j.appender.aar.layout = org.apache.log4j.PatternLayout
log4j.appender.aar.layout.ConversionPattern = %m%n

Best Answer

If you create a static Logger within MyLogger class, then you have one Logger instance, with the name set to MyLogger. When you call that logger from other packages, Log4j is not able to determine the origin of those calls, as they all use the same Logger.

The best way to handle it, is to define a separate Logger within each class, but if you want to use one class as a point of contact with Log4j, then you can do this:

package com.daniel.logger;
import org.apache.log4j.Logger;

import com.daniel.package1.ClassA;
import com.daniel.package2.ClassB;

public class MyLogger{

    public static void write(String message, Class<?> clazz){
        Logger.getLogger(clazz).info(message);
    }

    public static void main(String[] args){
        ClassA.log();
        ClassB.log();
    }
}

Then, one of the class using it could look like:

package com.daniel.package1;

import com.daniel.logger.MyLogger;

public class ClassA {

    public static void log(){
        MyLogger.write("ClassA",ClassA.class);
    }
}

And the log4j.properties file would look like:

log4j.appender.package1=org.apache.log4j.FileAppender 
log4j.appender.package1.File=package1.log
log4j.appender.package1.layout=org.apache.log4j.PatternLayout

log4j.appender.package2=org.apache.log4j.FileAppender
log4j.appender.package2.File=package2.log
log4j.appender.package2.layout=org.apache.log4j.PatternLayout

log4j.logger.com.daniel.package1=DEBUG,package1
log4j.logger.com.daniel.package2=DEBUG,package2

If you don't want to pass the Class from ClassA, you could use a nasty trick with reflection, that gets the calling class' name, but I wouldn't recommend that due to a performance hit:

public class MyLogger
{

    public static void write(String message){
        StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
        Logger.getLogger(stackTraceElements[2].getClassName()).info(message);
    }

    public static void main(String[] args){
        ClassA.log();
        ClassB.log();
    }
}
Related Topic