System.setErr() 干扰 Logger

2024-02-18

在较大的程序中,我使用静态java.util.logging.Logger实例,但重定向System.err连续到几个不同的文件。这Logger第二次尝试重定向时无法记录System.err.

这是一个显示问题的测试程序:

import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.util.logging.Logger;

class TestRedirect {
    static final Logger logger = Logger.getLogger("test");

    public static void main(String[] args) throws FileNotFoundException {
        for (int i = 1; i <= 2; i++) {
            TestRedirect ti = new TestRedirect();
            ti.test(i);
        }
    }

    void test(int i) throws FileNotFoundException {
        PrintStream filePrintStream = new PrintStream("test" + i + ".log");
        PrintStream stderr = System.err; // Save stderr stream.
        System.setErr(filePrintStream);  // Redirect stderr to file.
        System.err.println("about to log " + i);
        logger.info("at step " + i);
        System.setErr(stderr);           // Restore stderr stream.
        filePrintStream.close();
    }
}

这是输出:

测试1.log:

about to log 1
Jan 28, 2014 4:34:20 PM TestRedirect test
INFO: at step 1

测试2.日志:

about to log 2

我以为我会看到一个Logger- 生成的消息测试2.log以及。为什么Logger停止工作,我能做些什么呢?


默认情况下,JRE 配置为在根记录器上加载 ConsoleHandler。默认情况下,您的日志消息将传输到根记录器处理程序。根记录器处理程序是按需加载的。在您当前的程序中,根记录器 ConsoleHandler 的延迟加载正在捕获您的第一个重定向的 System.err。之后,根记录器处理程序永远不会重新加载,这就是为什么您永远不会在日志 2 中看到日志消息的原因。加上第一个重定向流已关闭,因此现在根 ConsoleHandler 正在写入关闭的流。

为了证明这一点,请将以下内容添加为测试用例主方法的第一行并运行该程序。

Logger.getLogger("").getHandlers(); //Force load root logger handlers.
Logger.getLogger("").removeHandler((Handler) null);

您会看到现在没有记录任何记录器消息。如果您好奇为什么会这样,您可以阅读java.util.logging.LogManager$RootLogger源代码了解详细信息。

你需要做的是创建一个流处理器 http://docs.oracle.com/javase/7/docs/api/java/util/logging/StreamHandler.html使用重定向的 System.err 流,然后add http://docs.oracle.com/javase/7/docs/api/java/util/logging/Logger.html#addHandler%28java.util.logging.Handler%29 and remove http://docs.oracle.com/javase/7/docs/api/java/util/logging/Logger.html#removeHandler%28java.util.logging.Handler%29来自记录器的 StreamHandler。您还可以切换使用父处理程序 http://docs.oracle.com/javase/7/docs/api/java/util/logging/Logger.html#setUseParentHandlers%28boolean%29在您的记录器配置上以避免写入原始 System.err。

Another possible solution would be to find all ConsoleHandler instances. Remove and close all of them. Perform the remap System.err. Then create and attach new ConsoleHandlers.

JDK 方面,ConsoleHandler 和 ErrorManager 应该被设计为使用java.io.FileDescriptor http://docs.oracle.com/javase/7/docs/api/java/io/FileDescriptor.html永远不会被重定向。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

System.setErr() 干扰 Logger 的相关文章

随机推荐