Log4j FileAppender recreando archivos eliminados

I am using Log4j as logging framework in a project I am working on. I have the following situation: Log4j is configured to write the logs into a log file. At some point, this log file is copied to another destination and deleted. Logging framework keeps working, but the logs are not written to the log file because it is deleted. Is there any way to tell Log4j to recreate the file and keep writing the logs into the log file.

Best regards, Rashid

preguntado el 24 de agosto de 12 a las 10:08

5 Respuestas

Revisé el código fuente de log4j. Cuando se inicializa un FileAppender / RollingFileAppender, FileOutputStream La instancia se crea apuntando al Archivo. Un nuevo FileDescriptor El objeto se crea para representar esta conexión de archivo. Esta es la razón, las otras soluciones como Monitorear el archivo a través de Cron y Crear el archivo en el método de adición anulando no funcionaron para mí, porque se asigna un nuevo descriptor de archivo al nuevo archivo. Log4j Writer todavía apunta al antiguo FileDescriptor.

La solución fue verificar si el archivo está presente y, si no, llamar al método activeOptions presente en la clase FileAppender.

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

Finalmente agregue esto al archivo 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

Nota:: He probado esto para log4j 1.2.17

Respondido 31 Jul 18, 06:07

I study the source of log4j and find log4j can't create new log file, it just print the error message to system.err when the log file was deleted

    /** 
     This method determines if there is a sense in attempting to append. 

     <p>It checks whether there is a set output target and also if 
     there is a set layout. If these checks fail, then the boolean 
     value <code>false</code> is returned. */  

  protected   boolean checkEntryConditions() {  
    if(this.closed) {  
      LogLog.warn("Not allowed to write to a closed appender.");  
      return false;  
    }  

    if(this.qw == null) {  
      errorHandler.error("No output stream or file set for the appender named ["+  
            name+"].");  
      return false;  
    }  

    if(this.layout == null) {  
      errorHandler.error("No layout set for the appender named ["+ name+"].");  
      return false;  
    }  
    return true;  
  }  

I think there are two workaround

  1. create another cron thread to monitor the log file
  2. add judge in getLog or getInstance (singleton), check the log file does exist, if not then init log4j

Respondido 24 ago 12, 10:08

Thanks for providing this code snipet. The first workaround you suggested is not simple enough. I think I will try to implement the second workaround you suggested. The methods, you mentioned, getLog and getInstance, in which class are they located? - rashid.rashidov

Make sure you can declare this line in your log4j file

    log4j.appender.rollingFile.File=D:/myapp/mylog.log

If you already declared it, you log file can delete or replace as you like. Then you rerun your program and new log file is created in this path.

Respondido 24 ago 12, 10:08

thanks for the suggestion, but it won't work for me. I do not want to restart the application. - rashid.rashidov

You don't need to restart. You can configure RollingFileAppender to create new log files. That means log4j will rename and move them as soon as they are "full" and it will then create a new log file. - Aarón Digulla

I do not understand how this will work for me. As you say, new files are created when the existing file is full. In my case, I need new files to be created when the existing file is deleted. - rashid.rashidov

Try This Class

package wodong.test;
import java.io.File;
import java.io.IOException;

import org.apache.log4j.FileAppender;
import org.apache.log4j.spi.LoggingEvent;

public class LastFileAppender extends FileAppender {
    @Override
    public void append(LoggingEvent event) {
        checkLogFileExist();
        super.append(event);
    }
    private void checkLogFileExist(){
        File logFile = new File(super.fileName);
        if (!logFile.exists()) {
            try {
                logFile.createNewFile();
            } catch (IOException e) {
                System.out.println("Error while create new log file.");
            }
        }
    }
}

Also edit the log4j config file

log4j.appender.R=wodong.test.LastFileAppender

Respondido 24 ago 12, 13:08

I tried it already. It works, but there is significant performance degradation. Logging with such appender is roughly 10 times slower. - rashid.rashidov

Try This one. I do not have a Linux machine right now, so I'm not sure if it can resolve the performance issue.

package wodong.test;
import java.io.File;
import java.io.IOException;

import org.apache.log4j.FileAppender;
import org.apache.log4j.spi.LoggingEvent;

public class LastFileAppender extends FileAppender {
    @Override
    public void append(LoggingEvent event) {

        checkLogFileExist();
        super.append(event);
    }

    private void checkLogFileExist() {
        if (qw == null) {
            File logFile = new File(super.fileName);
            if (!logFile.exists()) {
                try {
                    logFile.createNewFile();
                } catch (IOException e) {
                    System.out.println("Error while create new log file.");
                }
            }
        }
    }
}

Respondido 25 ago 12, 16:08

Hello. Thanks. Actually the performance degradation is not so significant. I checked Apache Tomcat. The similar code is used in access log implementation there. - rashid.rashidov

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.