Tomcat6下Log4j的log4j:ERROR Failed to rename错误解决办法

Tomcat6下配置log4j

log4j配置到tomcat6可以看这里, tomcat6下配置log4j

引起log4j:ERROR Failed to rename的原因

引起log4j:ERROR Failed to rename的原因大致为

引用
因為他是採用renameTo檔名的方式,所以,有可能是因為有process咬住檔案(之前遇到的問題),或是對檔案讀寫的權限不足


关于使用renameTo需要注意的事项, 请看 请慎用java的File#renameTo(File)方法 , File.renameTo方法在linux下的问题

引起log4j:ERROR Failed to rename的条件

通常都是在配置文件采用Java代码
log4j.appender.A1=org.apache.log4j.DailyRollingFileAppender 

log4j.appender.A1=org.apache.log4j.DailyRollingFileAppender或者
Java代码
log4j.appender.A1=org.apache.log4j.RollingFileAppender 

log4j.appender.A1=org.apache.log4j.RollingFileAppender的情况下遇到"异常"提示.

和异常相关的log4j源代码

查看log4j的源代码,和log4j:ERROR Failed to rename异常相关的代码为
Java代码
/** 
     Rollover the current file to a new file. 
  */ 
  void rollOver() throws IOException {  
 
    /* Compute filename, but only if datePattern is specified */ 
    if (datePattern == null) {  
      errorHandler.error("Missing DatePattern option in rollOver().");  
      return;  
    }  
 
    String datedFilename = fileName+sdf.format(now);  
    // It is too early to roll over because we are still within the  
    // bounds of the current interval. Rollover will occur once the  
    // next interval is reached.  
    if (scheduledFilename.equals(datedFilename)) {  
      return;  
    }  
 
    // close current file, and rename it to datedFilename  
    this.closeFile();  
 
    File target  = new File(scheduledFilename);  
    if (target.exists()) {  
      target.delete();  
    }  
 
    File file = new File(fileName);  
    boolean result = file.renameTo(target);  
    if(result) {  
      LogLog.debug(fileName +" -> "+ scheduledFilename);  
    } else {  
      LogLog.error("Failed to rename ["+fileName+"] to ["+scheduledFilename+"].");  
    }  
 
    try {  
      // This will also close the file. This is OK since multiple  
      // close operations are safe.  
      this.setFile(fileName, false, this.bufferedIO, this.bufferSize);  
    }  
    catch(IOException e) {  
      errorHandler.error("setFile("+fileName+", false) call failed.");  
    }  
    scheduledFilename = datedFilename;  
  }  
 
  /** 
   * This method differentiates DailyRollingFileAppender from its 
   * super class. 
   * 
   * <p>Before actually logging, this method will check whether it is 
   * time to do a rollover. If it is, it will schedule the next 
   * rollover time and then rollover. 
   * */ 
  protected void subAppend(LoggingEvent event) {  
    long n = System.currentTimeMillis();  
    if (n >= nextCheck) {  
      now.setTime(n);  
      nextCheck = rc.getNextCheckMillis(now);  
      try {  
    rollOver();  
      }  
      catch(IOException ioe) {  
    LogLog.error("rollOver() failed.", ioe);  
      }  
    }  
    super.subAppend(event);  
   }  


/**
     Rollover the current file to a new file.
  */
  void rollOver() throws IOException {

    /* Compute filename, but only if datePattern is specified */
    if (datePattern == null) {
      errorHandler.error("Missing DatePattern option in rollOver().");
      return;
    }

    String datedFilename = fileName+sdf.format(now);
    // It is too early to roll over because we are still within the
    // bounds of the current interval. Rollover will occur once the
    // next interval is reached.
    if (scheduledFilename.equals(datedFilename)) {
      return;
    }

    // close current file, and rename it to datedFilename
    this.closeFile();

    File target  = new File(scheduledFilename);
    if (target.exists()) {
      target.delete();
    }

    File file = new File(fileName);
    boolean result = file.renameTo(target);
    if(result) {
      LogLog.debug(fileName +" -> "+ scheduledFilename);
    } else {
      LogLog.error("Failed to rename ["+fileName+"] to ["+scheduledFilename+"].");
    }

    try {
      // This will also close the file. This is OK since multiple
      // close operations are safe.
      this.setFile(fileName, false, this.bufferedIO, this.bufferSize);
    }
    catch(IOException e) {
      errorHandler.error("setFile("+fileName+", false) call failed.");
    }
    scheduledFilename = datedFilename;
  }

  /**
   * This method differentiates DailyRollingFileAppender from its
   * super class.
   *
   * <p>Before actually logging, this method will check whether it is
   * time to do a rollover. If it is, it will schedule the next
   * rollover time and then rollover.
   * */
  protected void subAppend(LoggingEvent event) {
    long n = System.currentTimeMillis();
    if (n >= nextCheck) {
      now.setTime(n);
      nextCheck = rc.getNextCheckMillis(now);
      try {
rollOver();
      }
      catch(IOException ioe) {
LogLog.error("rollOver() failed.", ioe);
      }
    }
    super.subAppend(event);
   }
}
重点在这里
Java代码
File file = new File(fileName);  
    boolean result = file.renameTo(target);  
    if(result) {  
      LogLog.debug(fileName +" -> "+ scheduledFilename);  
    } else {  
      LogLog.error("Failed to rename ["+fileName+"] to ["+scheduledFilename+"].");  
    } 

File file = new File(fileName);
    boolean result = file.renameTo(target);
    if(result) {
      LogLog.debug(fileName +" -> "+ scheduledFilename);
    } else {
      LogLog.error("Failed to rename ["+fileName+"] to ["+scheduledFilename+"].");
    }

解决办法

解决办法为修改log4j的源代码, 修改
Java代码
boolean result = file.renameTo(target); 

boolean result = file.renameTo(target);

Java代码
boolean result = copy(file, target); 

boolean result = copy(file, target);
然后再添加copy()方法.
Java代码
/** 
     * Copies src file to dst file. If the dst file does not exist, it is 
     * created.8KB cache 
     *  
     * @param src 
     * @param dst 
     * @throws IOException 
     */ 
    boolean copy(File src, File dst) throws IOException {  
        try {  
            InputStream in = new FileInputStream(src);  
 
            OutputStream out = new FileOutputStream(dst);  
 
            // Transfer bytes from in to out  
            byte[] buf = new byte[8192];  
            int len;  
            while ((len = in.read(buf)) > 0) {  
                out.write(buf, 0, len);  
            }  
            in.close();  
            out.close();  
            return true;  
        } catch (FileNotFoundException e) {  
            LogLog.error("源文件不存在,或者目标文件无法被识别." );  
            return false;  
        } catch (IOException e) {  
            LogLog.error("文件读写错误.");  
            return false;  
        }  
    } 

/**
* Copies src file to dst file. If the dst file does not exist, it is
* created.8KB cache
*
* @param src
* @param dst
* @throws IOException
*/
boolean copy(File src, File dst) throws IOException {
try {
InputStream in = new FileInputStream(src);

OutputStream out = new FileOutputStream(dst);

// Transfer bytes from in to out
byte[] buf = new byte[8192];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
return true;
} catch (FileNotFoundException e) {
LogLog.error("源文件不存在,或者目标文件无法被识别." );
return false;
} catch (IOException e) {
LogLog.error("文件读写错误.");
return false;
}
}
此方法借鉴自 File Copy in Java 和 Java File Copy

后面的话
修改后的代码可以正常运行在tomcat6下, log文件替换正常. 没有高负载和集群环境下测试. 如有问题,还请大家积极反馈. 如果你有更好的办法请告诉我.  

附件 : 包括修改后的org.apache.log4j.DailyRollingFileAppender类的源代码和已编译好的文件.
请用DailyRollingFileAppender.class替换log4j-1.2.15.jar包里相应的类.

你可能感兴趣的:(apache,log4j,linux,cache)