2009-08-12 108 views
13

我試圖配置Java Logging API的FileHandler以將我的服務器記錄到我主目錄中文件夾內的文件,但我不想創建這些目錄在它運行的每臺機器上。配置Java FileHandler日誌記錄以創建目錄(如果它們不存在)

例如在logging.properties文件我註明:

java.util.logging.FileHandler 
java.util.logging.FileHandler.pattern=%h/app-logs/MyApplication/MyApplication_%u-%g.log 

這將讓我收我的主目錄(%H)日誌MyApplication的,並會使用%u旋轉他們(和%g個變量)。

的Log4j支持這個時候我在我的log4j.properties註明:

log4j.appender.rolling.File=${user.home}/app-logs/MyApplication-log4j/MyApplication.log 

它看起來像有反對的日誌文件處理器中的錯誤: Bug 6244047: impossible to specify driectorys to logging FileHandler unless they exist

聽起來好像他們不打算修復它或暴露任何屬性以解決問題(除了讓應用程序解析logging.properties或硬編碼所需路徑):

它看起來像 java.util.logging.FileHandler不會 期望指定的目錄 可能不存在。通常情況下,它必須 無論如何檢查這個條件。此外,它還需要檢查寫入 權限的目錄。另一個問題 是如果其中一個檢查 沒有通過該怎麼辦。

如果 用戶具有適當的權限,則一種可能性是在路徑中創建 缺少的目錄。另一個 是拋出一個IOException和一個 明確的消息有什麼不對。後面的方法看起來更加一致。

回答

8

這似乎是log4j版本1.2.15做到了。

這裏是做它

public 
synchronized 
void setFile(String fileName, boolean append, boolean bufferedIO, int bufferSize) 
                 throws IOException { 
    LogLog.debug("setFile called: "+fileName+", "+append); 

    // It does not make sense to have immediate flush and bufferedIO. 
    if(bufferedIO) { 
     setImmediateFlush(false); 
    } 

    reset(); 
    FileOutputStream ostream = null; 
    try { 
      // 
      // attempt to create file 
      // 
      ostream = new FileOutputStream(fileName, append); 
    } catch(FileNotFoundException ex) { 
      // 
      // if parent directory does not exist then 
      //  attempt to create it and try to create file 
      //  see bug 9150 
      // 
      String parentName = new File(fileName).getParent(); 
      if (parentName != null) { 
      File parentDir = new File(parentName); 
      if(!parentDir.exists() && parentDir.mkdirs()) { 
       ostream = new FileOutputStream(fileName, append); 
      } else { 
       throw ex; 
      } 
      } else { 
      throw ex; 
      } 
    } 
    Writer fw = createWriter(ostream); 
    if(bufferedIO) { 
     fw = new BufferedWriter(fw, bufferSize); 
    } 
    this.setQWForFiles(fw); 
    this.fileName = fileName; 
    this.fileAppend = append; 
    this.bufferedIO = bufferedIO; 
    this.bufferSize = bufferSize; 
    writeHeader(); 
    LogLog.debug("setFile ended"); 
} 

這段代碼是從FileAppender代碼的片斷,RollingFileAppender進行延伸FileAppender。

這裏沒有檢查我們是否有權創建父文件夾,但是如果父文件夾不存在,那麼它會嘗試創建父文件夾。

EDITED

如果你想要一些額外的functionalily,你總是可以延長RollingFileAppender進行並覆蓋setFile()方法。

+3

如果我在log4j框架內但是我使用Java Logging框架,並且沒有攔截FileHandler創建調用的鉤子(除了首次訪問Logger時捕獲異常,例如記錄器.info(「test」)。 – Dougnukem 2009-08-12 05:24:31

+0

我的意思是你可以編寫自己的appender。 – 2009-08-12 05:50:26

+0

用戶沒有詢問Log4J。 – 2017-08-09 12:26:32

5

你可以寫這樣的東西。

package org.log; 

import java.io.IOException; 
import org.apache.log4j.RollingFileAppender; 

public class MyRollingFileAppender extends RollingFileAppender { 

    @Override 
    public synchronized void setFile(String fileName, boolean append, 
     boolean bufferedIO, int bufferSize) throws IOException { 
     //Your logic goes here 
     super.setFile(fileName, append, bufferedIO, bufferSize); 
    } 

} 

然後在你的配置

log4j.appender.fileAppender=org.log.MyRollingFileAppender 

這完全適用於我。

+0

我得看看我要做什麼來創建一個自定義的Logging處理程序在Java Logging框架中,但我敢打賭,它與Log4j框架相似 – Dougnukem 2009-08-12 05:56:56

4

要解決的Java日誌框架的限制,以及尚未解決的錯誤:Bug 6244047: impossible to specify driectorys to logging FileHandler unless they exist

我拿出2層的方法(雖然只有第一種方式將實際工作),都需要你的靜態無效的主要()方法來初始化日誌系統。

例如

public static void main(String[] args) {  

    initLogging(); 
    ... 
    } 

第一種方法對您希望存在的日誌目錄進行硬編碼,如果它們不存在,則創建它們。

private static void initLogging() { 
    try { 
     //Create logging.properties specified directory for logging in home directory 
     //TODO: If they ever fix this bug (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6244047) in the Java Logging API we wouldn't need this hack 
     File homeLoggingDir = new File (System.getProperty("user.home")+"/webwars-logs/weblings-gameplatform/"); 
     if (!homeLoggingDir.exists()) { 
      homeLoggingDir.mkdirs(); 
      logger.info("Creating missing logging directory: " + homeLoggingDir); 
     } 
    } catch(Exception e) { 
     e.printStackTrace(); 
    } 

    try { 
     logger.info("[GamePlatform] : Starting..."); 
    } catch (Exception exc) { 
     exc.printStackTrace(); 

    } 
} 

第二種方法可以趕上IOException異常並創建例外列出的目錄,這種方法的問題是,日誌框架已經無法創建文件處理器,以便捕捉和解決錯誤仍然留下記錄系統處於不良狀態。

+0

您認爲這種方法將會用於所有場景,例如登錄Web應用程序,我們需要在記錄器初始化之前調用攔截器。 由於我們可以編寫我們自己的logAppender,我認爲這將會b這是一個更好的選擇,它可以解決大部分情況。 – 2009-08-12 06:20:00

+0

我同意,我將在記錄框架中執行該操作,並將附加我的答案。 – Dougnukem 2009-08-12 15:28:53

+0

我剛剛嘗試通過複製java.util.logging.FileHandler創建自己的CustomFileHandler,這裏有一些初始問題。您需要位於java.util.logging。*包中以訪問Manager .getStringProperty方法。所以我嘗試使用該包創建一個類,但是在運行時加載該類時存在安全異常: 無法加載日誌處理程序「java.util.logging.CustomFileHandler」 java.lang.SecurityException:禁用的程序包名稱:java .util.logging – Dougnukem 2009-08-12 15:51:40

1

作爲一種可能的解決方案,我認爲有兩種方法(查看一些以前的答案)。我可以擴展Java日誌處理程序類並編寫我自己的自定義處理程序。我也可以複製log4j功能,並將其調整到Java Logging框架。

這裏的基本複印的FileHandler和創建CustomFileHandler看到pastebin for full class的例子:

的關鍵是openFiles散()方法,它試圖創建一個FileOutputStream和檢查,並創建父目錄,如果它不存在(我也有複製包保護日誌管理方法,爲什麼他們甚至讓那些包反正保護):

// Private method to open the set of output files, based on the 
// configured instance variables. 
private void openFiles() throws IOException { 
    LogManager manager = LogManager.getLogManager(); 

...

// Create a lock file. This grants us exclusive access 
    // to our set of output files, as long as we are alive. 
    int unique = -1; 
    for (;;) { 
     unique++; 
     if (unique > MAX_LOCKS) { 
      throw new IOException("Couldn't get lock for " + pattern); 
     } 
     // Generate a lock file name from the "unique" int. 
     lockFileName = generate(pattern, 0, unique).toString() + ".lck"; 
     // Now try to lock that filename. 
     // Because some systems (e.g. Solaris) can only do file locks 
     // between processes (and not within a process), we first check 
     // if we ourself already have the file locked. 
     synchronized (locks) { 
      if (locks.get(lockFileName) != null) { 
       // We already own this lock, for a different FileHandler 
       // object. Try again. 
       continue; 
      } 
      FileChannel fc; 
      try { 
       File lockFile = new File(lockFileName); 
       if (lockFile.getParent() != null) { 
        File lockParentDir = new File(lockFile.getParent()); 
        // create the log dir if it does not exist 
        if (!lockParentDir.exists()) { 
         lockParentDir.mkdirs(); 
        } 
       } 

       lockStream = new FileOutputStream(lockFileName); 
       fc = lockStream.getChannel(); 
      } catch (IOException ix) { 
       // We got an IOException while trying to open the file. 
       // Try the next file. 
       continue; 
      } 
      try { 
       FileLock fl = fc.tryLock(); 
       if (fl == null) { 
        // We failed to get the lock. Try next file. 
        continue; 
       } 
       // We got the lock OK. 
      } catch (IOException ix) { 
       // We got an IOException while trying to get the lock. 
       // This normally indicates that locking is not supported 
       // on the target directory. We have to proceed without 
       // getting a lock. Drop through. 
      } 
      // We got the lock. Remember it. 
      locks.put(lockFileName, lockFileName); 
      break; 
     } 
    } 

... }

1

我通常會盡量避免使用靜態代碼,但要解決這個限制,這裏是我的方法,在我的項目上工作。

我將子類java.util.logging.FileHandler與其超級調用實現了所有構造函數。我在該類中放置了一個靜態代碼塊,它在user.home文件夾中爲我的應用程序創建文件夾(如果它們不存在)。

在我的日誌記錄屬性文件中,我用我的新類替換了java.util.logging.FileHandler。

相關問題