Java System.setErr()会干扰记录器
在一个更大的程序中,我使用了一个静态的Java System.setErr()会干扰记录器,java,java.util.logging,Java,Java.util.logging,在一个更大的程序中,我使用了一个静态的java.util.logging.Logger实例,但将System.err连续重定向到几个不同的文件。当我第二次尝试重定向系统时,记录器无法记录。错误 下面是一个测试程序来说明问题: import java.io.FileNotFoundException; import java.io.PrintStream; import java.util.logging.Logger; class TestRedirect { static final
java.util.logging.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();
}
}
test2.log:
about to log 1
Jan 28, 2014 4:34:20 PM TestRedirect test
INFO: at step 1
about to log 2
我想我会在test2.log中看到
Logger
生成的消息。为什么记录器
停止工作,对此我能做些什么?默认情况下,JRE配置为在根记录器上加载ConsoleHandler。默认情况下,日志消息将传递到根记录器处理程序。根记录器处理程序按需加载。在您当前的程序中,根记录器ConsoleHandler的延迟加载正在捕获您的第一个重定向System.err。在此之后,根记录器处理程序永远不会重新加载,这就是为什么您永远不会在日志2中看到日志消息的原因。加上第一个重定向的流是关闭的,所以现在根控制台句柄正在写入一个关闭的流
为了证明这一点,添加以下内容作为测试用例main方法的第一行,然后运行程序
Logger.getLogger("").getHandlers(); //Force load root logger handlers.
Logger.getLogger("").removeHandler((Handler) null);
您将看到,现在没有记录记录器消息。如果您想知道为什么这样做,可以阅读java.util.logging.LogManager$RootLogger
源代码以了解详细信息
您需要做的是使用重定向的System.err流创建一个流,然后从记录器中创建和StreamHandler。您还可以在记录器配置上切换使用,以避免写入原始System.err
另一种可能的解决方案是查找所有ConsoleHandler实例。卸下并关闭所有这些部件。执行重新映射System.err。然后创建并连接新的控制台手柄
就JDK而言,ConsoleHandler和ErrorManager应该设计为使用从不重定向的。如果有其他可能的方法,我通常建议不要在Java中重定向标准流。是否确实需要使用
setErr()
?@Darkhogg:原始程序实际上使用了GroovySystemOutputCeptor
(基本上是基于FilteredOutputStream
)的“T”将stdout和stderr定向到日志文件以及控制台。SystemOutputInterceptor
在封面下调用setErr()
。程序中的一些部分使用了记录器,一些只是将信息和错误写入到stderr和stdout。