24

I am using log4j to log information. I have used a log4j.xml file for creating log files. I have given the absolute path for each log file as a param tag value.

E.g.:

<appender name="FA" class="org.apache.log4j.DailyRollingFileAppender">
  <param name="DatePattern" value="'_'yyyyMMdd"/>
  <param name="File" value="D:/logFiles/GPreprocessor.log"/>
  <layout class="com.dnb.genericpreprocessor.common.log.AppXMLLayout"/>
</appender>

I do not want to write "GPreprocessor.log" directly. Actually, that file name is dynamic, based on my project's name. For example, if I run the program ABC.java, logging should go to D:/logFiles/ABC.log, but if I run XYZ.java, logging should go to D:/logFiles/XYZ.log. The file's location will always remain the same: D:/logFiles/. How can I change the log file's name dynamically?

Pops
  • 28,257
  • 34
  • 127
  • 149
Bittu
  • 241
  • 1
  • 2
  • 4

5 Answers5

81

It's much easier to do the following:

In log4j.xml define variable as ${variable}:

<appender name="FILE" class="org.apache.log4j.FileAppender">    
    <param name="File" value="${logfilename}.log" />
    <layout class="org.apache.log4j.PatternLayout">
        <param name="ConversionPattern" value="%d::[%t]::%-5p::%c::%x - %m%n" />
    </layout>       
</appender>

Then make sure you set the system property when you start your JVM such as:

java -Dlogfilename=my_fancy_filename  example.Application

That will create a dynamic log file name: my_fancy_filename.log

Alternatively, you can set the system property in code so long as you do it before you create a logger (this is useful if you want your PID in your logs for instance). Such as:

System.setProperty("logfilename", "a_cool_logname");

Once that is set you can go ahead and get your loggers as normal and they will log to the dynamic file (be careful of those static Loggers that create loggers before your main method executes).

Bo Persson
  • 86,087
  • 31
  • 138
  • 198
Big B
  • 811
  • 6
  • 3
  • 1
    Will it support/take if i give the values in the .properties file? i.e., instead of defining the value in the start of JVM, can i define it in the .properties file? – SuRa Dec 09 '14 at 12:45
  • if you use System.setProperty("logfilename", "a_cool_logname"); make sure you set this before you log anything – James Mar 05 '17 at 15:24
  • 3
    If you're using log4j2, I believe you need `${sys:logfilename}` in the XML instead – automaton Mar 07 '19 at 19:08
  • Can we give the path also in the filename like "D:/Test/my_fancy_filename" so that it can create my_fancy_filename.log in the specified directory? – manikanta nvsr Apr 06 '20 at 06:48
10

Below is my code for using Log4J for dynamically generate filename. It changes its name according to input file name and current date-time. (So helpful in case you run same file multiple times.)

public class LogClass {

    private static Logger log =  Logger.getLogger(LogClass.class);
    private static boolean initializationFlag = false;
    private static String fileName;

    private static void intializeLogger(){
        log.setLevel(Level.DEBUG);

        DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
        Date date = new Date();

        RollingFileAppender appender = new RollingFileAppender();
        appender.setAppend(true);
        appender.setMaxFileSize("1MB");
        appender.setMaxBackupIndex(1);
        appender.setFile(fileName + "_" + dateFormat.format(date) + ".log");
        appender.activateOptions();

        PatternLayout layOut = new PatternLayout();
        layOut.setConversionPattern("%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n");
        appender.setLayout(layOut);

        log.addAppender(appender);
    }

    public static Logger getLogger(){
        if(initializationFlag == false){
            intializeLogger();
            initializationFlag = true;
            return LogClass.log;
        }
        else{
            return LogClass.log;
        }
    }

    public static void setFileName(String fileName){
        LogClass.fileName = fileName;
    }
}

Now whenever you want to use logger in your program, Just write these two lines :

LogClass.setFileName(yourFileName);
LogClass.getLogger().debug("hello!!");

Happy Coding.

doer_uvc
  • 1,108
  • 1
  • 9
  • 27
4

It makes more sense to extend FileAppender with your own class, in which you override setOptions() method. Then in your log4j.properties you configure root to log to yourpackage.yourFileAppender, which is much cleaner.

pankar
  • 1,563
  • 1
  • 10
  • 20
Nik
  • 51
  • 2
0

In your class containing main method set the name of your class to some system property. In following example I used log_dir as property name.

class ABC{
 public static void main(String s[]){
  System.setProperty("log_dir", ABC.class.getSimpleName());
 }
}

And in your log4j.xml file use log_dir property in File param's value attribute

<appender name="FA" class="org.apache.log4j.DailyRollingFileAppender">
  <param name="DatePattern" value="'_'yyyyMMdd"/>
  <param name="File" value="D:/logFiles/${log_dir}"/>
  <layout class="com.dnb.genericpreprocessor.common.log.AppXMLLayout"/>
</appender>

Works like a charm

Bopsi
  • 1,244
  • 2
  • 25
  • 45
0

Before executing anything, log4j thoroughly checks the class path for log4j.xml configuration file. Let'say, by chance, if there is any log4j.xml configuration file in the library jars you referenced in your project, log4j loads that file as the configuration file and starts logging. In this context, when you are setting log file location in your FileAppender dynamically by getting the value from System properties as suggested by @Big B, it will not work since log4j had already loaded the configuration file it discovered first.

To prevent this, you can use DOMConfigurator to inform log4j what configuration file it should load and when it should load. So, as soon as you set the system property of LogFileLocation in your program use DOMConfigurator to load intended properties file in the following way:

System.setProperty("LogFileLocation", "D:Test/Logdetails"));
DOMConfigurator.configure("log4j.xml");

By doing this way, you will load log4j.xml after you set the system property LogFileLocation in your program. (It will also override the already loaded configuration)

Inside the log4j.xml configuration, you set the file location in the param tag 'File':

<appender name="fileAppender"
        class="org.apache.log4j.FileAppender">
        <param name="File" value="${LogFileLocation}.log" />
        <param name="Append" value="false" /> 
<!-- false will make the log to override the file. true will make the log to append to the file -->
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern"
                value="%d{dd/MM/yyyy HH:mm:ss} %-5p %c{2} 
        - %m%n" />
        </layout>
    </appender>

To understand whatever I said better, provide -Dlog4j.debug=true in your VM arguments and see the log of log4j execution in your console.