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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/194165/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 11:09:40  来源:igfitidea点击:

How do I change java logging console output from std err to std out?

javalogging

提问by Obediah Stane

I'm using the standard ConsoleHandlerfrom java.util.loggingand by default the console output is directed to the error stream (i.e. System.err).

我正在使用标准ConsoleHandlerfromjava.util.logging并且默认情况下控制台输出被定向到错误流(即System.err)。

How do I change the console output to the output stream (i.e. System.out)?

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

回答by Jon Skeet

Have a look at the docs and source for ConsoleHandler- I'm sure you could easily write a version which just uses System.err instead of System.out. (It's a shame that ConsoleHandler doesn't allow this to be configured, to be honest.)

查看ConsoleHandler的文档和源代码- 我相信您可以轻松编写一个仅使用 System.err 而不是 System.out 的版本。(说实话,ConsoleHandler 不允许配置它,这是一种耻辱。)

Then it's just a case of configuring the logging system to use your new StdoutHandler (or whatever you call it) in the normal way.

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

回答by Uri

If you use Java logging, you can change the default handler:

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

For example, for files: Handler fh = new FileHandler(FILENAME); Logger.getLogger(LOGGER_NAME).addHandler(fh);

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

If you want to output to a stream you can use StreamHandler, I think you can configure it with any output stream that you woud like, including the system stream.

如果你想输出到流,你可以使用StreamHandler,我想你可以用你喜欢的任何输出流配置它,包括系统流。

回答by Obediah Stane

I figured out one way. First remove the default console handler:

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

setUseParentHandlers(false);

setUseParentHandlers(false);

Then subclass ConsoleHandler and in the constructor:

然后子类 ConsoleHandler 并在构造函数中:

setOutputStream(System.out);

setOutputStream(System.out);

回答by Obediah Stane

If you set setUseParentHandlers(false); only THAT class has it set. Other classes in the app will still pass it thru to stderr.

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

回答by Hema

Simply extend StreamHandler & in the constructor call Super(System.out,). This will avoid closing System.err - Thanks

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

回答by Jeremiah Jahn

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

回答by Frank Vlach

I've arrived at

我到了

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

回答by volley

Hmm I just got bit in the foot a few times, trying to accomplish this feat. Before googling my way here I managed to conjure the following hack. Ugly, but it seems to get the job done.

嗯,我只是被咬了几次脚,试图完成这个壮举。在谷歌搜索我的方式之前,我设法召唤了以下黑客。丑陋,但它似乎完成了工作。

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

Watch out: Calling setOutputStream() from the constructor is tempting, but it does (as Jon Skeet already pointed out) close System.err. Mad skills!

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

回答by Kai

If there is still someone out there looking for a solution to this problem. Here's what I came up with finally: I just subclassed StreamHandler and added an additional parameter MaxLevel, which is checked at the beginning of publish(). If the level of the logging event is larger than MaxLevel, publish won't be executed any further. Here are the details:

如果仍然有人在那里寻找解决此问题的方法。这是我最后想到的:我只是继承了 StreamHandler 并添加了一个额外的参数 MaxLevel,它在 publish() 的开头被检查。如果日志事件的级别大于 MaxLevel,则发布将不再执行。以下是详细信息:

MaxlevelStreamHandler.javaMain Class below.

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

Main Class

主类

To now show some events in stdout and some in stderr, simply setup two StreamLoggers, one for critical events and one for all others, and disable the standard console logger:

现在要在 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");

Hope this helps!

希望这可以帮助!

Update: I added super.flush() right after super.publish() to make sure that the message is shown immediately. Before, I had problems that the log-messages were always shown at the end. It's now part of the code above.

更新:我在 super.publish() 之后添加了 super.flush() 以确保立即显示消息。之前,我遇到了日志消息总是显示在最后的问题。它现在是上面代码的一部分。

回答by ocarlsen

I had a similar problem. I wanted to log INFO and below to System.out, and WARNING and above to System.err. Here is the solution I implemented:

我有一个类似的问题。我想将 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();
        }
    }
}

Of course, you could make it more flexible by factoring out the hard-coded reference to Level.INFO, for example. But this worked well for me to get some basic dual-stream logging. (BTW, the tips about not subclassing ConsoleHandler to avoid closing the System.errwere very useful.)

当然,例如,您可以通过分解对 的硬编码引用来使其更加灵活Level.INFO。但这对我来说很有效,可以得到一些基本的双流日志记录。(顺便说一句,关于不要子类化 ConsoleHandler 以避免关闭的提示System.err非常有用。)