Recently I got a question from my blog reader Kuruba, regarding log4j logging. Kuruba is having a batch program with Log4j logging and he wants to send the log messages to a new log file each time his batch runs. This can be achieved by extending Log4j’s FileAppender, which is used for logging to a file, and adding our own customization to the file appender. Below I’m explaining how to do it.
Extending FileAppender to create a new log file for each application run:
Here’s the pseudo code for the logic we are going to implement.
- Create a new Class NewLogForEachRunFileAppender (or any name as you wish), and extend it from the class org.apache.log4j.FileAppender.
- Override the activateOptions() function for setting the new log file name every time the logger is instantiated.
- For simplicity, we will append the current timestamp to each log file name. So, each time when you run the application, you will get a fresh log file.
Customized FileAppender: NewLogForEachRunFileAppender:
Here is the code for the customize FileAppender, which will create a new log file, appender with the current timestamp, for each run of the application. Please note that this code is tested in Windows environment. So, please be cautious and do a testing when running this code in Unix or other environment.
package com.veerasundar.dynamiclogger;
import java.io.File;
import java.io.IOException;
import org.apache.log4j.FileAppender;
import org.apache.log4j.Layout;
import org.apache.log4j.spi.ErrorCode;
/**
* This is a customized log4j appender, which will create a new file for every
* run of the application.
*
* @author veera | http://veerasundar.com
*
*/
public class NewLogForEachRunFileAppender extends FileAppender {
public NewLogForEachRunFileAppender() {
}
public NewLogForEachRunFileAppender(Layout layout, String filename,
boolean append, boolean bufferedIO, int bufferSize)
throws IOException {
super(layout, filename, append, bufferedIO, bufferSize);
}
public NewLogForEachRunFileAppender(Layout layout, String filename,
boolean append) throws IOException {
super(layout, filename, append);
}
public NewLogForEachRunFileAppender(Layout layout, String filename)
throws IOException {
super(layout, filename);
}
public void activateOptions() {
if (fileName != null) {
try {
fileName = getNewLogFileName();
setFile(fileName, fileAppend, bufferedIO, bufferSize);
} catch (Exception e) {
errorHandler.error("Error while activating log options", e,
ErrorCode.FILE_OPEN_FAILURE);
}
}
}
private String getNewLogFileName() {
if (fileName != null) {
final String DOT = ".";
final String HIPHEN = "-";
final File logFile = new File(fileName);
final String fileName = logFile.getName();
String newFileName = "";
final int dotIndex = fileName.indexOf(DOT);
if (dotIndex != -1) {
// the file name has an extension. so, insert the time stamp
// between the file name and the extension
newFileName = fileName.substring(0, dotIndex) + HIPHEN
+ +System.currentTimeMillis() + DOT
+ fileName.substring(dotIndex + 1);
} else {
// the file name has no extension. So, just append the timestamp
// at the end.
newFileName = fileName + HIPHEN + System.currentTimeMillis();
}
return logFile.getParent() + File.separator + newFileName;
}
return null;
}
}
log4j.properties file
Since we created a custom file appender, we need to tell the Log4j to use our custom file appender. For demo purpose, I configured this custom FileAppender as a rootLogger. So, all log messages will go to our file appender. Below is the sample log4j.properties file.
log4j.rootLogger = DEBUG, fileout
log4j.appender.fileout = com.veerasundar.dynamiclogger.NewLogForEachRunFileAppender
log4j.appender.fileout.layout.ConversionPattern = %d{ABSOLUTE} %5p %c - %m%n
log4j.appender.fileout.layout = org.apache.log4j.PatternLayout
log4j.appender.fileout.File = D:/temp/dynamiclogger/logs.log
If you look at the property log4j.appender.fileout, our customized file appender is associated with this appender. We have also given a log file name “log.log” in the above configuration file. So, with the above configuration, when you run your application, the log files will be generated in this fashion: logs-1250696128437.log, logs-1250696142828.log.



{ 15 comments… read them below or add one }
Thanks Veer,
@Govind
Welcome. I hope that I answered your question.:)
Hi Veera,
This is really a very useful content.
Thanks for posting it.
Well i have a query regarding this.
How about if i want to use MaxBackupIndex properties. Can we do it? if yes then how?
Thanks,
Tanzy.
@Tanzy
Yes. It’s possible but with a small code change in the above solution. We just need delete the old log files if the total number of log files reached the maxBackupIndex threshold. This is doable. Will try to post the solution for this later.
Thanks for making this code publicly available. It`s very useful and works straight ‘out of the box’ for me on Ubuntu.
Regards
you are welcome.
Hi Veera,
The code works to create multiple log files each time it is called. But am using a Thread java class which calls this log fiel genrate everytime a thread starts, say for example my code is used to run 5 threads parallely and inside my process i tried calling this NewLogForEachRunFileAppender class it generates 5 different log files but writes all the logger.info into single log file inside of writing each process logger.info into its specific log files. Please let me what needs to be done?
Hi Kiran,
The above example code was made for different runs of the application, without having threads in mind. That’s why it didn’t work properly to you.
Anyway, I’ll work out a solution and will inform u soon.
Hello,
I couldn’t find the log4j.properties file in any of the log4j jar files, so I created one, but I am not sure where to place it. I put it in the same directory as the one that has the log4j jar files, but my logger would still log out to the console instead to the customized appender. I am not sure what the fix to this issue is, but I created the same customized appender that you have and created a logger in my class that I want to log. It still did not log out to the appender. It seems the logger is not tied to the appender yet. Is there a fix to this issue?
Thanks
Nancy,
Initially you need to create the log4j.properties file for yourself, which you already did correctly. After creating the file, place it inside the WEB-INF folder (if your’s is a web application), otherwise place it inside the source/src folder so that log4j can pick up this file and configures the logging accordingly.
actually, the easiest way to do this is just write:
log4j.appender.FILE.append = false
in log4j.properties!!! I have been googling it for a 20 already, and then i got it, and it worked perfectly! nobody writes about this solution and suggests some brainfucking stuff!
Thank you very much Veera….i understand very clearly through this …Thank you once again..
Mikka nandri Veera, it was so use full for me to meet the requirements. once again thanks much.
Thanks a lot man. It helped me a lot as I had the same requirement for my project
Hi Veera, i was wondering how you can disable this custom file appender of yours at runtime. I tried removeAppender, but still the logger uses this appender. I’m stuck on this.