log4j:ERROR Failed to rename

log4j:ERROR Failed to rename

重命名日誌文件時錯誤。

log4j.properties配置如下:

log4j.rootLogger=INFO

log4j.logger.access= INFO,reg
log4j.appender.reg=org.apache.log4j.DailyRollingFileAppender
log4j.appender.reg.layout=org.apache.log4j.PatternLayout
log4j.appender.reg.File=D:\\secureCRT\\sync.log
log4j.appender.reg.DatePattern='.'yyyy-MM-dd
log4j.appender.reg.layout.ConversionPattern=%d - [%p] - [%F\:%L] %m%n

log4j.logger.access2= INFO,A3
log4j.appender.A3=org.apache.log4j.RollingFileAppender
log4j.appender.A3.layout=org.apache.log4j.PatternLayout
log4j.appender.A3.File=D:\\secureCRT\\sync.log
log4j.appender.A3.MaxFileSize=500KB
log4j.appender.A3.layout.ConversionPattern=%d - [%p] - [%F\:%L] %m%n

運行時只使用了reg,沒有使用A3。

原因:reg日誌記錄器配置的是DailyRollingFileAppender,每天產生新文件,而產生新文件是用的File.renameTo(),

在這出錯了。google發現,在windows原因是有其他的進程在佔用該日誌文件,檢查發現我用記事本打開了這個文件(D:\\secureCRT\\sync.log),於是關掉記事本,再次運行,仍然報這個錯誤。有點奇怪了,除了reg還會有什麼進程在佔用這個文件呢?

然後又檢查log4j.properties,發現reg和A3的日誌文件時配置的同一個(見上面配置文件),會不會這個導致的?

於是,把A3暫且註釋掉,運行通過,產生了新的文件!

也就是說,雖然沒有用到A3,但log4j仍然會加載該配置並實例化了。


爲了驗證,查看源碼(版本1.2.16):

log4j的使用是從如下地方開始的:

Logger logger = Logger.getLogger(Test.class);

進入Logger.getLogger(Test.class):

static public  Logger getLogger(Class clazz) {
    return LogManager.getLogger(clazz.getName());
}
進入LogManager類,注意有一段static代碼區,是用於在第一次加載該類時初始化log4j的:

static {
    // By default we use a DefaultRepositorySelector which always returns 'h'.
    // 以DEBUG級別生成RootLogger
    Hierarchy h = new Hierarchy(new RootLogger((Level) Level.DEBUG));
    repositorySelector = new DefaultRepositorySelector(h);
    ......
    //加載系統變量"log4j.configuration",已不推薦使用
    String configurationOptionStr = OptionConverter.getSystemProperty(DEFAULT_CONFIGURATION_KEY,  null);

      String configuratorClassName = OptionConverter.getSystemProperty( CONFIGURATOR_CLASS_KEY,  null);

      URL url = null;

      // 先加載log4j.xml,如果失敗,則加載log4j.properties(推薦使用xml)
      // if the user has not specified the log4j.configuration
      // property, we search first for the file "log4j.xml" and then
      // "log4j.properties"
      if(configurationOptionStr == null) { 
         url = Loader.getResource(DEFAULT_XML_CONFIGURATION_FILE);
         if(url == null) {
           url = Loader.getResource(DEFAULT_CONFIGURATION_FILE);
         }
      } else {
 try {
   url = new URL(configurationOptionStr);
 } catch (MalformedURLException ex) {
   // so, resource is not a URL:
   // attempt to get the resource from the class path
   url = Loader.getResource(configurationOptionStr); 
 } 
      }
      
        ......
         // 加載配置文件
            OptionConverter.selectAndConfigure(url, configuratorClassName,
    LogManager.getLoggerRepository());
      ......
  } 
進入OptionConverter.selectAndConfigure():

void selectAndConfigure(URL url, String clazz, LoggerRepository hierarchy) {
   Configurator configurator = null;
   String filename = url.getFile();

   if(clazz == null && filename != null && filename.endsWith(".xml")) {
     clazz = "org.apache.log4j.xml.DOMConfigurator";
   }


   if(clazz != null) {
     LogLog.debug("Preferred configurator class: " + clazz);
     configurator = (Configurator) instantiateByClassName(clazz,
   Configurator.class,
   null);
     if(configurator == null) {
      LogLog.error("Could not instantiate configurator ["+clazz+"].");
      return;
     }
   } else {
     configurator = new PropertyConfigurator();
   }

   configurator.doConfigure(url, hierarchy);
  }

根據配置文件類型,選擇不同的加載類,xml則爲DOMConfigurator,properties則爲PropertyConfigurator

然後調用doConfigure()來加載。

以PropertyConfigurator來看,進入PropertyConfigurator.doConfigure():

public void doConfigure(String configFileName, LoggerRepository hierarchy) {
    Properties props = new Properties();
    FileInputStream istream = null;
    try {
      istream = new FileInputStream(configFileName);
      props.load(istream);
      istream.close();
    }
   
   ......
    // 加載propertie配置文件
    // If we reach here, then the config file is alright.
    doConfigure(props, hierarchy);
  }

進入加粗的方法裏,最後會看到三行代碼:

configureRootCategory(properties, hierarchy);//加載RootLogger
configureLoggerFactory(properties);// 加載LoggerFactory(用於後面生成Logger)
parseCatsAndRenderers(properties, hierarchy);//加載其他日誌記錄器(自定義的)

從上面的源碼可以看出,log4j在第一次調用時,即加載整個配置文件並初始化,所有就可以理解上面這個問題了,雖然A3沒有使用,

但仍然加載初始化了,並佔有日誌文件,導致reg無法rename。





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章