5

I have a web application in Tomcat that uses log4j for logging.
If I delete the log files while the web application is running the files are not recreated?
How can I configure log4j to recreate the files on deletion without having to restart Tomcat?

Jim
  • 18,826
  • 34
  • 135
  • 254
  • A comment on one of the questions which duplicates this one points out that if you can replace the _contents_ of the file without deleting it, logging will continue to function just fine (on Linux, anyway). This can be useful, for instance, when you're testing something and want to clear the "noise" from the log to focus on the logging caused by your test. One way to do this is `cat /dev/null > /path/to/log/file` (or `echo "cat /dev/null > /path/to/log/file" | sudo -s` if the file isn't writable by your user). – Lambart May 25 '17 at 19:52

5 Answers5

3

If your tomcat is on a linux server, and you start it with a specific user that doesn't have execute rights on the log folder, your log4j will not recreate your logs, because probably it has only read/write rights.

If this is the case try a:

chmod 755 on the containing folder

EDIT:

The second possibility is that some operating systems complete the "delete" operation only when the file is not in use anymore. If this is the case your tomcat can still "see" the log as there.

EDIT2:

In that case make a cron job that every several minutes checks if the file is there. If not just recreate it. I will provide a solution in a few minutes.

So the bash that should be in your crontab would have something like:

if [ ! -f /tomcat_dir/log4j.log ]
then
  `touch /tomcat_dir/log4j.log`;
fi
Bogdan Emil Mariesan
  • 5,529
  • 2
  • 33
  • 57
  • It is in Linux and the dir that has the logs has `x` for the user and the group that runs tomcat – Jim Mar 30 '12 at 06:13
  • I see what you mean, but how can I get arround the second case (+1 from me) – Jim Mar 30 '12 at 06:22
  • what you could do is configure your log4j to log on a daily basis and make a shell script to backup and archive your older logs. http://www.tutorialspoint.com/log4j/log4j_logging_files.htm – Bogdan Emil Mariesan Mar 30 '12 at 06:24
  • Why to back up and archive?All I want is if the user deletes the log files to be recreated automatically – Jim Mar 30 '12 at 07:11
  • In that case make a cron job that every several minutes checks if the file is there. If not just recreate it. I will provide a solution in a few minutes. – Bogdan Emil Mariesan Mar 30 '12 at 07:12
1

In log4j.properties, configure a RollingFileAppender

#------------------------------------------------------------------------------
#
#  Rolling File Appender
#
#------------------------------------------------------------------------------
log4j.appender.rfile = org.apache.log4j.RollingFileAppender
log4j.appender.rfile.File = logs/server.log
log4j.appender.rfile.Append = false
log4j.appender.rfile.MaxFileSize=10240KB
log4j.appender.rfile.MaxBackupIndex=10
log4j.appender.rfile.layout = org.apache.log4j.PatternLayout
log4j.appender.rfile.layout.ConversionPattern = %d %-5p [%C] (%t) %m (%F:%L)%n

Configure a daily cron job (sh script in /etc/crond.daily/) that cleans logs over $DAYS old

find $LOG_ROOT/log/server.log* -mtime +$DAYS -exec rm {} \;
Bruno Grieder
  • 28,128
  • 8
  • 69
  • 101
  • I have a rolling appender.I want to recreate the logs on deletion automatically – Jim Mar 30 '12 at 07:10
  • I don't know how is this a solution to the question with web-container writing to the filesystem. In my case, even `touch`ing a file does not seem to work. Have to restart the container. Dammit. – prayagupa Dec 23 '16 at 23:02
0

I went through the source code of log4j. When a FileAppender/RollingFileAppender is initialized, a FileOutputStream instance is created pointing to the File. A new FileDescriptor object is created to represent this file connection. This is the reason, the other solutions like Monitoring the file through Cron and Creating the File in append method by overriding didn't work for me, because a new file descriptor is assigned to the new file. Log4j Writer still points to the old FileDescriptor.

The solution was to check if the file is present and if not call the activeOptions method present in FileAppender Class.

package org.apache.log4j;

import java.io.File;
import org.apache.log4j.spi.LoggingEvent;

public class ModifiedRollingFileAppender extends RollingFileAppender {

    @Override 
    public void append(LoggingEvent event) {
        checkLogFileExist();
        super.append(event);
    }

    private void checkLogFileExist(){
        File logFile = new File(super.fileName);
        if (!logFile.exists()) {
            this.activateOptions();
        }
    }
}

Finally add this to the log4j.properties file:

log4j.rootLogger=DEBUG, A1
log4j.appender.A1=org.apache.log4j.ModifiedRollingFileAppender
log4j.appender.A1.File=/path/to/file
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss,SSS} %p %c{1}: %m%n

//Skip the below lines for FileAppender
log4j.appender.A1.MaxFileSize=10MB
log4j.appender.A1.MaxBackupIndex=2

Note: I have tested this for log4j 1.2.17

0

I found the solution for Log4j2.

Short:
We can manually initialize rollover process when detect file deletition.

Rollover can be initialized using RollingFileManager:

final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
// You should know only appender name.
RollingFileAppender appender = (RollingFileAppender) ctx.getConfiguration().getAppenders().get(appenderName);

if (appender != null) {
    // Manually start rollover logic.
    appender.getManager().rollover();
}

Longer is here.

Jagat Dave
  • 1,643
  • 3
  • 23
  • 30
dennydenny
  • 96
  • 1
  • 8
0

You can have a customized RollingFileAppender and check for file existence. This code checks for file existence before every logging and creates the file if it is missing.

public class CustomRollingFileAppender extends RollingFileAppender {

// ... Constructor

@Override
    public void append(LoggingEvent event) {
        if (!new File(this.fileName).exists()) {
            try {
                setFile(this.fileName, fileAppend, bufferedIO, bufferSize);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        super.append(event);
    }
}
m02ph3u5
  • 3,022
  • 7
  • 38
  • 51
mardanyan
  • 29
  • 7