如何将java日志控制台输出从std err更改为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。 疯狂的技能!

 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(){} }; 

我想出了一个方法。 首先删除默认控制台处理程序:

setUseParentHandlers(假);

然后inheritanceConsoleHandler并在构造函数中:

setOutputStream(System.out的);

我有类似的问题。 我想将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来使其更加灵活。 但这对我来说很有效,可以获得一些基本的双流记录。 (顺便说一下,关于不inheritanceConsoleHandler以避免关闭System.err的提示非常有用。)

看看ConsoleHandler的文档和源代码 – 我相信你可以轻松编写一个只使用System.err而不是System.out的版本。 (遗憾的是,ConsoleHandler不允许这样配置,说实话。)

然后,这只是一个配置日志系统以正常方式使用新的StdoutHandler(或任何你称之为)的情况。

如果还有人在那里寻找解决这个问题的方法。 以下是我最终提出的内容:我只是将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中显示一些事件,只需设置两个StreamLogger,一个用于关键事件,一个用于所有其他事件,并禁用标准控制台记录器:

 // 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”。 遗憾的是,Java没有为ConsoleHandler类提供任何公共方法来设置输出流。 所以它只能在对象创建时设置。 由于ConsoleHandler类扩展了StreamHandler,它具有受保护的方法“setOutputStream”以显式设置输出流。 要为ConsoleHandler设置输出流,只需在新的对象创建调用时覆盖此方法。

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

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); } 

这假定代码具有修改错误流的权限,并且没有其他正在运行的代码正在访问错误流。 简而言之,这是一种选择,但有更安全的替代方案。

如果设置setUseParentHandlers(false); 只有那个类设置它。 应用程序中的其他类仍将通过它传递给stderr。

只需扩展StreamHandler并在构造函数中调用Super(System.out,)。 这将避免关闭System.err – 谢谢