Log4j在删除文件后不会重新创建文件

5

我有一个在Tomcat中使用log4j进行日志记录的Web应用程序。
如果我在Web应用程序运行时删除日志文件,文件不会重新创建?
如何配置log4j在删除后重新创建文件而无需重新启动Tomcat?


这个问题的一个重复问题的评论指出,如果你可以替换文件的内容而不删除它,日志记录仍将正常工作(在Linux上)。例如,在测试某些东西并希望清除日志中的“噪音”以便关注由测试引起的日志时,这可能非常有用。一种方法是 cat /dev/null > /path/to/log/file(或者如果该文件不可写,则为 echo "cat /dev/null > /path/to/log/file" | sudo -s)。 - Lambart
5个回答

3
如果您的Tomcat在Linux服务器上,并且使用一个特定的用户启动它,而该用户没有对日志文件夹的执行权限,那么您的Log4j将无法重新创建日志,因为可能只有读/写权限。
如果情况是这样的,请尝试在包含文件夹上运行“chmod 755”。
编辑:
第二种可能性是,某些操作系统仅在文件不再使用时才完成“删除”操作。如果是这种情况,您的Tomcat仍然可以“看到”日志。
编辑2:
在这种情况下,可以创建一个cron作业,每隔几分钟检查文件是否存在。如果不存在,只需重新创建它。我将在几分钟内提供解决方案。
因此,应该在您的crontab中设置类似以下内容的bash:
if [ ! -f /tomcat_dir/log4j.log ]
then
  `touch /tomcat_dir/log4j.log`;
fi

它在 Linux 系统上,包含日志的目录对于运行 Tomcat 的用户和组具有可执行 (x) 权限。 - Jim
我明白你的意思,但是我该如何避免第二种情况(+1)? - Jim
你可以配置log4j按日志记录,并编写一个shell脚本来备份和归档旧日志。http://www.tutorialspoint.com/log4j/log4j_logging_files.htm - Bogdan Emil Mariesan
为什么要备份和归档?我只想让日志文件在用户删除后自动重新创建。 - Jim
在这种情况下,可以创建一个 cron 作业,每隔几分钟检查文件是否存在。如果不存在,就重新创建它。我会在几分钟内提供一个解决方案。 - Bogdan Emil Mariesan

1
在log4j.properties文件中,配置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

配置一个每日的cron job(在/etc/crond.daily/中的sh脚本),清理超过$DAYS天的日志

find $LOG_ROOT/log/server.log* -mtime +$DAYS -exec rm {} \;

我有一个滚动的 appender。我想在删除日志时自动重新创建它们。 - Jim
我不知道这是否是解决Web容器写入文件系统问题的方法。在我的情况下,即使是“touch”文件也似乎无法工作。必须重新启动容器。该死。 - prayagupa

0

我找到了关于Log4j2的解决方案。

简述:
当检测到文件删除时,我们可以手动初始化滚动过程。

可以使用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();
}

更长的内容在这里


0

我仔细研究了log4j的源代码。当初始化FileAppender/RollingFileAppender时,会创建一个指向文件的FileOutputStream实例。创建一个新的FileDescriptor对象来表示此文件连接。这就是为什么其他解决方案,如通过Cron监视文件和通过覆盖append方法创建文件,对我没有用处的原因,因为新文件被分配给新文件描述符。Log4j Writer仍然指向旧的FileDescriptor。

解决方案是检查文件是否存在,如果不存在,则调用FileAppender类中的activeOptions方法。

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();
        }
    }
}

最后将此添加到log4j.properties文件中:

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

注意:我已经测试过这个log4j 1.2.17版本。


0
您可以拥有一个定制的RollingFileAppender并检查文件是否存在。 此代码在每次记录日志之前都会检查文件是否存在,并在缺失时创建该文件。
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);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接