2014-01-28 61 views
0

在較大的程序中,我使用靜態java.util.logging.Logger實例,但將System.err連續重定向到幾個不同的文件。 Logger未能第二次登錄,我嘗試重定向System.errSystem.setErr()干擾記錄器

這是一個測試程序,以顯示該問題:

import java.io.FileNotFoundException; 
import java.io.PrintStream; 
import java.util.logging.Logger; 

class TestRedirect { 
    static final Logger logger = Logger.getLogger("test"); 

    public static void main(String[] args) throws FileNotFoundException { 
     for (int i = 1; i <= 2; i++) { 
      TestRedirect ti = new TestRedirect(); 
      ti.test(i); 
     } 
    } 

    void test(int i) throws FileNotFoundException { 
     PrintStream filePrintStream = new PrintStream("test" + i + ".log"); 
     PrintStream stderr = System.err; // Save stderr stream. 
     System.setErr(filePrintStream); // Redirect stderr to file. 
     System.err.println("about to log " + i); 
     logger.info("at step " + i); 
     System.setErr(stderr);   // Restore stderr stream. 
     filePrintStream.close(); 
    } 
} 

這裏的輸出:

test1.log:

about to log 1 
Jan 28, 2014 4:34:20 PM TestRedirect test 
INFO: at step 1 

test2.log:

about to log 2 

我想我會在test2.log看到Logger - 生成的消息也是如此。爲什麼Logger停止工作,我能做些什麼呢?

+0

我通常建議不要在Java中重定向標準流,如果有另一種可能的方法。你確定*你需要使用'setErr()'? – Darkhogg

+0

@Darkhogg:原來的程序實際上是使用Groovy'SystemOutputInterceptor'(基本上是一個基於'FilteredOutputStream'的「tee」)來將stdout和stderr指向日誌文件以及控制檯。 'SystemOutputInterceptor'調用'setErr()'。該程序的各個部分中有一些正在使用記錄器,有些只是將信息和錯誤寫入stderr和stdout。 –

回答

2

默認情況下,JRE配置爲加載上的根記錄器一個ConsoleHandler。默認情況下,您的日誌消息將傳遞到根記錄器處理程序。根記錄器處理程序按需加載。在您當前的程序中,根記錄器ConsoleHandler的延遲加載正在捕獲您的第一個重定向的System.err。在此之後,根記錄處理程序重新加載從未這就是爲什麼你永遠不會看到日誌消息日誌2加1號重定向流被關閉所以現在根本ConsoleHandler被寫​​入到一個封閉的流。

爲了證明這一點,添加以下內容作爲測試用例的主要方法的第一線和運行程序。

Logger.getLogger("").getHandlers(); //Force load root logger handlers. 
Logger.getLogger("").removeHandler((Handler) null); 

您會看到現在沒有記錄記錄器消息。如果您很好奇爲什麼這樣工作,您可以閱讀java.util.logging.LogManager$RootLogger源代碼以獲取詳細信息。

你需要做的是創建一個StreamHandler與您的重定向System.err流,然後addremove StreamHandler從您的記錄器。您還可以在記錄器配置上切換使用parent handlers以避免寫入原始System.err。

另一種可能的解決辦法是找到所有ConsoleHandler實例。刪除並關閉所有這些。執行重映射System.err。然後創建並附加新的ConsoleHandler。

明智的JDK,ConsoleHandler和ErrorManager應該被設計爲使用從未重定向的java.io.FileDescriptor