[英]How do I change java logging console output from std err to std out?
我正在使用java.util.logging
的標准ConsoleHandler
並且默認情況下控制台輸出被定向到錯誤流(即System.err
)。
如何將控制台輸出更改為輸出流(即System.out
)?
我到了
SimpleFormatter fmt = new SimpleFormatter();
StreamHandler sh = new StreamHandler(System.out, fmt);
logger.addHandler(sh);
嗯,我只是被咬了幾次腳,試圖完成這個壯舉。 在谷歌搜索我的方式之前,我設法召喚了以下黑客。 丑陋,但它似乎完成了工作。
public class StdoutConsoleHandler extends ConsoleHandler {
protected void setOutputStream(OutputStream out) throws SecurityException {
super.setOutputStream(System.out); // kitten killed here :-(
}
}
注意:從構造函數調用 setOutputStream() 很誘人,但它確實(正如 Jon Skeet 已經指出的那樣)關閉 System.err。 瘋狂的技能!
我想出了一種方法。 首先刪除默認的控制台處理程序:
setUseParentHandlers(false);
然后子類 ConsoleHandler 並在構造函數中:
setOutputStream(System.out);
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(){}
};
我有一個類似的問題。 我想將 INFO 及以下記錄到System.out
,將 WARNING 及以上記錄到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
的提示非常有用。)
查看ConsoleHandler的文檔和源代碼 - 我相信您可以輕松編寫一個僅使用 System.err 而不是 System.out 的版本。 (說實話,ConsoleHandler 不允許配置它,這是一種恥辱。)
然后,這只是將日志系統配置為以正常方式使用新的 StdoutHandler(或任何您稱之為)的情況。
第 1 步:將父處理程序設置為 false。
log.setUseParentHandlers(false);
第 2 步:添加一個寫入 System.out 的處理程序
log.addHandler(new StreamHandler(System.out, new SimpleFormatter()));
就是這樣..
import java.io.IOException;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
import java.util.logging.StreamHandler;
public class App {
static final Logger log = Logger.getLogger("com.sample.app.App");
static void processData() {
log.info("Started Processing Data");
log.info("Finished processing data");
}
public static void main(String args[]) throws IOException {
log.setUseParentHandlers(false);
log.addHandler(new StreamHandler(System.out, new SimpleFormatter()));
processData();
}
}
如果仍然有人在那里尋找解決此問題的方法。 這是我最后想到的:我只是繼承了 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();
}
}
主類
現在要在 stdout 中顯示一些事件,在 stderr 中顯示一些事件,只需設置兩個 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() 以確保立即顯示消息。 之前,我遇到了日志消息總是顯示在最后的問題。 它現在是上面代碼的一部分。
如果您使用 Java 日志記錄,則可以更改默認處理程序:
例如,對於文件:Handler fh = new FileHandler(FILENAME); Logger.getLogger(LOGGER_NAME).addHandler(fh);
如果你想輸出到流,你可以使用StreamHandler,我想你可以用你喜歡的任何輸出流配置它,包括系統流。
ConsoleHandler 將在構建期間抓取System.err
的快照。 一種選擇是將全局錯誤流與全局輸出流交換,然后創建 ConsoleHandler。
ConsoleHandler h = null;
final PrintStream err = System.err;
System.setErr(System.out);
try {
h = new ConsoleHandler(); //Snapshot of System.err
} finally {
System.setErr(err);
}
這假設代碼有權修改錯誤流,並且沒有其他正在運行的代碼正在訪問錯誤流。 簡而言之,這是一種選擇,但還有更安全的選擇。
當我們創建一個新的 ConsoleHandler 對象時,默認的輸出流是“system.err”。 遺憾的是,Java 沒有為 ConsoleHandler 類提供任何公共方法來設置輸出流。 所以只能在創建對象的時候設置。 由於 ConsoleHandler 類擴展了 StreamHandler,它有一個受保護的方法“setOutputStream”來顯式設置輸出流。 要為 ConsoleHandler 設置輸出流,只需在創建對象的新調用時覆蓋此方法。
ConsoleHandler consoleHandler = new ConsoleHandler (){
@Override
protected synchronized void setOutputStream(OutputStream out) throws SecurityException {
super.setOutputStream(System.out);
}
};
如果你設置了 setUseParentHandlers(false); 只有那個班級設置了它。 應用程序中的其他類仍會將其傳遞給 stderr。
只需在構造函數調用 Super(System.out,) 中擴展 StreamHandler &。 這將避免關閉 System.err - 謝謝
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.