2008-10-11 84 views

回答

3

看看的文檔和來源 - 我相信你可以輕鬆地編寫一個只使用System.err而不是System.out的版本。 (可惜的是ConsoleHandler不允許這樣配置,說實話)

然後,它只是配置日誌記錄系統以正常方式使用新的StdoutHandler(或任何您稱之爲的)的情況。

+0

我認爲ConsoleHandler是默認的,有一個StreamHandler可以打印到任何其他流。 – Uri 2008-10-11 15:30:13

+3

是的,但你想要子類化StreamHandler,以避免嘗試關閉System.err,我懷疑。 – 2008-10-11 17:59:22

1

如果使用Java記錄,您可以更改默認的處理程序:

例如,對於文件: 處理器FH =新的FileHandler(文件名); Logger.getLogger(LOGGER_NAME).addHandler(fh);

如果你想輸出到一個流,你可以使用StreamHandler,我認爲你可以配置任何你喜歡的輸出流,包括系統流。

7

我想出了一種方法。首先刪除默認的控制檯處理程序:

setUseParentHandlers(false);

然後子類ConsoleHandler並在構造:

setOutputStream(System.out的);

+3

爲了避免在下次調用`setOutputStream(...)`或`LogManager.reset()`時關閉它,你最好使用自實現的`OutputStream`封裝`System.out`。 – amotzg 2012-09-27 03:54:24

+0

另外,請小心不要調用(ConsoleHandler`的超級構造函數),因爲它設置System.err,並在調用`setOutputStream(System.out)`時關閉它。或者,您可以繼承`StreamHandler`並調用`super(OutputStream,Formatter)`。 – amotzg 2012-09-27 03:58:00

0

如果你設置了setUseParentHandlers(false);只有這個班級設置了它。應用中的其他課程仍然會將其傳遞給stderr。

+0

如果有人爲根日誌記錄類(Logger.GLOBAL_LOGGER_NAME)執行此操作,則將禁用所有類的控制檯日誌記錄。 – koppor 2012-11-17 20:44:12

-1

在構造函數調用Super(System.out,)中簡單地擴展StreamHandler &。這將避免關閉System.err的 - 感謝

9
Handler consoleHandler = new Handler(){ 
     @Override 
      public void publish(LogRecord record) 
      { 
       if (getFormatter() == null) 
       { 
        setFormatter(new SimpleFormatter()); 
       } 

       try { 
        String message = getFormatter().format(record); 
        if (record.getLevel().intValue() >= Level.WARNING.intValue()) 
        { 
         System.err.write(message.getBytes());      
        } 
        else 
        { 
         System.out.write(message.getBytes()); 
        } 
       } catch (Exception exception) { 
        reportError(null, exception, ErrorManager.FORMAT_FAILURE); 
       } 

      } 

      @Override 
      public void close() throws SecurityException {} 
      @Override 
      public void flush(){} 
     }; 
+6

但是,在現代...有沒有辦法做到這一點,而不實施自定義處理程序? – Victor 2013-08-25 20:19:56

10

我來到

SimpleFormatter fmt = new SimpleFormatter(); 
StreamHandler sh = new StreamHandler(System.out, fmt); 
logger.addHandler(sh); 
7

的腳幾次嗯,我剛剛得到位,試圖完成這一壯舉。在Google之前,我設法召喚下面的黑客。醜陋,但它似乎完成了工作。

public class StdoutConsoleHandler extends ConsoleHandler { 
    protected void setOutputStream(OutputStream out) throws SecurityException { 
    super.setOutputStream(System.out); // kitten killed here :-(
    } 
} 

當心:調用setOutputStream()從構造函數是誘人的,但它確實(如喬恩斯基特已經指出的)密切System.err的。瘋狂的技能!

2

如果仍然有人在那裏尋找解決這個問題的方法。 下面是我最後想到的:我只是繼承了StreamHandler並添加了一個額外的參數 MaxLevel,它在publish()的開頭被選中。如果日誌事件的級別大於MaxLevel,則不會再執行發佈。 下面是詳細信息:

MaxlevelStreamHandler.java 主要下方類。

package helper; 

/** 
* The only difference to the standard StreamHandler is 
* that a MAXLEVEL can be defined (which then is not published) 
* 
* @author Kai Goergen 
*/ 

import java.io.PrintStream; 
import java.util.logging.Formatter; 
import java.util.logging.Level; 
import java.util.logging.LogRecord; 
import java.util.logging.StreamHandler; 

public class MaxlevelStreamHandler extends StreamHandler { 

    private Level maxlevel = Level.SEVERE; // by default, put out everything 

    /** 
    * The only method we really change to check whether the message 
    * is smaller than maxlevel. 
    * We also flush here to make sure that the message is shown immediately. 
    */ 
    @Override 
    public synchronized void publish(LogRecord record) { 
     if (record.getLevel().intValue() > this.maxlevel.intValue()) { 
      // do nothing if the level is above maxlevel 
     } else { 
      // if we arrived here, do what we always do 
      super.publish(record); 
      super.flush(); 
     } 
    } 

    /** 
    * getter for maxlevel 
    * @return 
    */ 
    public Level getMaxlevel() { 
     return maxlevel; 
    } 

    /** 
    * Setter for maxlevel. 
    * If a logging event is larger than this level, it won't be displayed 
    * @param maxlevel 
    */ 
    public void setMaxlevel(Level maxlevel) { 
     this.maxlevel = maxlevel; 
    } 

    /** Constructor forwarding */ 
    public MaxlevelStreamHandler(PrintStream out, Formatter formatter) { 
     super(out, formatter); 
    } 

    /** Constructor forwarding */ 
    public MaxlevelStreamHandler() { 
     super(); 
    } 
} 

主類

中現在顯示在標準輸出的一些事件和一些在標準錯誤,只是創建了兩個StreamLoggers,一個關鍵的事件,一個用於所有其他的,和禁用標準控制檯記錄器:

// setup all logs that are smaller than WARNINGS to stdout 
MaxlevelStreamHandler outSh = new MaxlevelStreamHandler(System.out, formatter); 
outSh.setLevel(Level.ALL); 
outSh.setMaxlevel(Level.INFO); 
logger.addHandler(outSh); 

// setup all warnings to stdout & warnings and higher to stderr 
StreamHandler errSh = new StreamHandler(System.err, formatter); 
errSh.setLevel(Level.WARNING); 
logger.addHandler(errSh); 

// remove default console logger 
logger.setUseParentHandlers(false); 

logger.info("info"); 
logger.warning("warning"); 
logger.severe("severe"); 

希望這有助於!

更新:我在super.publish()之後添加了super.flush(),以確保消息立即顯示。之前,我遇到了日誌消息總是顯示在最後的問題。它現在是上面代碼的一部分。

2

我有一個類似的問題。我想記錄信息及以下至System.out,警告及以上至System.err。下面是我實現的解決方案:

public class DualConsoleHandler extends StreamHandler { 

    private final ConsoleHandler stderrHandler = new ConsoleHandler(); 

    public DualConsoleHandler() { 
     super(System.out, new SimpleFormatter()); 
    } 

    @Override 
    public void publish(LogRecord record) { 
     if (record.getLevel().intValue() <= Level.INFO.intValue()) { 
      super.publish(record); 
      super.flush(); 
     } else { 
      stderrHandler.publish(record); 
      stderrHandler.flush(); 
     } 
    } 
} 

當然,你可以把通過分解出硬編碼引用Level.INFO,例如,它更加靈活。但是,這對我獲得一些基本的雙流日誌很有幫助。 (順便提一句,關於不通過子控制ConsoleHandler避免關閉System.err的提示非常有用。)

1

ConsoleHandler將在構建過程中抓取System.err的快照。一種選擇是將全局錯誤流與全局輸出流交換,然後創建ConsoleHandler。

final PrintStream err = System.err; 
System.setErr(System.out); 
ConsoleHandler h = new ConsoleHandler(); //Snapshot of System.err 
System.setErr(err); 

這假設代碼有權修改錯誤流,並且沒有其他正在運行的代碼正在訪問錯誤流。總之,這是一個選擇,但有更安全的選擇。

1

當我們創建一個新的ConsoleHandler對象時,默認輸出流是「system.err」。可悲的是,Java並沒有爲ConsoleHandler類提供任何公共方法來設置輸出流。所以它只能在創建對象時設置。由於ConsoleHandler類擴展了StreamHandler,它具有一個受保護的方法「setOutputStream」來顯式設置輸出流。要爲ConsoleHandler設置輸出Stream,只需在新的對象創建調用時重寫此方法即可。

ConsoleHandler consoleHandler = new ConsoleHandler(){ 
      @Override 
      protected synchronized void setOutputStream(OutputStream out) throws SecurityException { 
       super.setOutputStream(System.out); 
      } 
     }; 
相關問題