如何将java日志控制台输出从stderr更改为std out?

时间:2008-10-11 15:00:12

标签: java logging

我正在使用ConsoleHandler中的标准java.util.logging,默认情况下,控制台输出会定向到错误流(即System.err)。

如何将控制台输出更改为输出流(即System.out)?

13 个答案:

答案 0 :(得分:13)

我到了

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

答案 1 :(得分: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(){}
        };

答案 2 :(得分:9)

嗯,我只是踩了几下脚,试图完成这个壮举。在谷歌搜索之前,我设法让人想到以下黑客。丑陋,但它似乎完成了工作。

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

注意:从构造函数中调用setOutputStream()很诱人,但它确实(正如Jon Skeet已经指出的那样)关闭了System.err。疯狂的技能!

答案 3 :(得分:8)

我发现了一种方法。首先删除默认控制台处理程序:

setUseParentHandlers(假);

然后继承ConsoleHandler并在构造函数中:

setOutputStream(的System.out);

答案 4 :(得分:4)

我有类似的问题。我想将INFO及以下信息记录到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的提示非常有用。)

答案 5 :(得分:3)

查看ConsoleHandler的文档和来源 - 我确信你可以轻松编写一个只使用System.err而不是System.out的版本。 (遗憾的是,ConsoleHandler不允许配置它,说实话。)

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

答案 6 :(得分:3)

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

答案 7 :(得分: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();
    }
}

主要类

现在在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(),以确保立即显示该消息。之前,我遇到的问题是日志消息总是显示在最后。它现在是上面代码的一部分。

答案 8 :(得分:1)

如果使用Java日志记录,则可以更改默认处理程序:

例如,对于文件:     Handler fh = new FileHandler(FILENAME);     Logger.getLogger(LOGGER_NAME).addHandler(FH);

如果要输出到流,可以使用StreamHandler,我认为您可以使用您喜欢的任何输出流(包括系统流)对其进行配置。

答案 9 :(得分:1)

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

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

答案 10 :(得分:1)

当我们创建一个新的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);
            }
        };

答案 11 :(得分:0)

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

答案 12 :(得分:-1)

简单地扩展StreamHandler&amp;在构造函数中调用Super(System.out,)。这将避免关闭System.err - 谢谢