在较大的程序中,我使用静态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();
}
}
这是输出:
test1.log:
about to log 1
Jan 28, 2014 4:34:20 PM TestRedirect test
INFO: at step 1
test2.log:
about to log 2
我以为我会在 test2.log 中看到Logger
生成的消息。为什么Logger
停止工作,我该怎么办呢?
答案 0 :(得分:2)
默认情况下,JRE配置为在根记录器上加载ConsoleHandler。默认情况下,您的日志消息将传递到根记录器处理程序。根记录器处理程序按需加载。在您当前的程序中,根记录器ConsoleHandler的延迟加载正在捕获您的第一个重定向的System.err。之后,永远不会重新加载根记录器处理程序,这就是您永远不会在日志2中看到日志消息的原因。再加上第一个重定向流已关闭,所以现在根ConsoleHandler正在写入一个封闭的流。
为了证明这一点,请将以下内容添加为测试用例main方法的第一行并运行该程序。
Logger.getLogger("").getHandlers(); //Force load root logger handlers.
Logger.getLogger("").removeHandler((Handler) null);
您将看到现在没有记录任何记录器消息。如果您很好奇为什么会这样,您可以阅读java.util.logging.LogManager$RootLogger
源代码以获取详细信息。
您需要做的是使用重定向的System.err流创建StreamHandler,然后使用记录器中的add和remove StreamHandler创建。您还可以在记录器配置上切换parent handlers的使用,以避免写入原始的System.err。
另一种可能的解决方案是找到所有ConsoleHandler实例。删除并关闭所有这些。执行重映射System.err。然后创建并附加新的ConsoleHandlers。
JDK明智地说,ConsoleHandler和ErrorManager应该被设计为使用从未重定向的java.io.FileDescriptor。