即使在设置 System.setErr() 后也无法使用自定义 PrintStream 打印错误
Errors not printing using custom PrintStream even after setting System.setErr()
基本上,我希望控制台做两件事:
- 我想要控制台对代码错误和一般信息消息进行颜色显示(错误为红色,其他所有内容为绿色)。
- 我想将所有控制台消息保存到日志文件中。
所以,我创建了一个看起来像这样的打印流:
public static class GeneralStream extends PrintStream {
public GeneralStream(OutputStream out) {
super(out);
}
@Override
public void println(String string) {
String time = DateTimeFormatter.ofPattern("HH:mm:ss").format(LocalDateTime.now());
String output = "["+time+"] ["+type.n()+"] "+string;
Logs.logToFile(output);
String coloredOutput = ANSI_RESET+ANSI_WHITE+"["+ANSI_CYAN+time+ANSI_WHITE+"] "+
ANSI_WHITE+"["+ANSI_RESET+type.c()+type.n()+ANSI_WHITE+"] "+type.c()+string+ANSI_RESET;
super.println(coloredOutput);
}
}
太棒了。然后我在程序开始时将此打印流设置为默认 PrintStream 使用:
// Set console output settings
System.setOut(new Console.GeneralStream(System.out));
System.setErr(new Console.GeneraStream(System.err));
太棒了。最后,在执行 System.out.println("Hello World") 后,我得到了预期的结果。我的消息是彩色的。它们被记录到一个文件中。伟大的!事实上,即使我执行 System.err.println("Error!"),我仍然会得到预期的结果。 但是,“自动”异常不会通过我设置的 System.err 打印。
这是一个例子:
// Set console output settings
System.setOut(new Console.GeneralStream(System.out));
System.setErr(new Console.ErrorStream(System.err));
System.out.println("Hello world!");
System.err.println("Printing an error!");
// Real exception (NPE)
Integer nullInteger = null;
System.out.println(nullInteger.toString()); // won't print and will produce a NullPointException
结果如下:
As you can see, my System.out and System.err print fine but as soon as there is a real exception, it prints regularly.
所以我的问题是如何为此类错误设置自定义 PrintStream,以便将它们记录到文件中(最好遵循我的自定义消息格式)。
如果你深入了解 Throwable
class 如何打印堆栈跟踪,你会发现它使用了 println(Object)
方法,因此你需要将此方法添加到您的自定义 ErrorStream class:
@Override
public void println(Object object) {
println(String.valueOf(object));
}
即便如此,您也可能想要更改“未捕获的异常处理程序”以更改它记录异常的方式。似乎默认处理程序首先调用 System.err.print
以输出 Exception in thread "{ThreadName}"
,然后是 Throwable.printStackTrace
,因此您最终会在消息中间得到时间戳和其他内容。例如:
Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
System.err.println("Uncaught exception in thread " + thread.getName());
throwable.printStackTrace(System.err);
});
基本上,我希望控制台做两件事:
- 我想要控制台对代码错误和一般信息消息进行颜色显示(错误为红色,其他所有内容为绿色)。
- 我想将所有控制台消息保存到日志文件中。
所以,我创建了一个看起来像这样的打印流:
public static class GeneralStream extends PrintStream {
public GeneralStream(OutputStream out) {
super(out);
}
@Override
public void println(String string) {
String time = DateTimeFormatter.ofPattern("HH:mm:ss").format(LocalDateTime.now());
String output = "["+time+"] ["+type.n()+"] "+string;
Logs.logToFile(output);
String coloredOutput = ANSI_RESET+ANSI_WHITE+"["+ANSI_CYAN+time+ANSI_WHITE+"] "+
ANSI_WHITE+"["+ANSI_RESET+type.c()+type.n()+ANSI_WHITE+"] "+type.c()+string+ANSI_RESET;
super.println(coloredOutput);
}
}
太棒了。然后我在程序开始时将此打印流设置为默认 PrintStream 使用:
// Set console output settings
System.setOut(new Console.GeneralStream(System.out));
System.setErr(new Console.GeneraStream(System.err));
太棒了。最后,在执行 System.out.println("Hello World") 后,我得到了预期的结果。我的消息是彩色的。它们被记录到一个文件中。伟大的!事实上,即使我执行 System.err.println("Error!"),我仍然会得到预期的结果。 但是,“自动”异常不会通过我设置的 System.err 打印。
这是一个例子:
// Set console output settings
System.setOut(new Console.GeneralStream(System.out));
System.setErr(new Console.ErrorStream(System.err));
System.out.println("Hello world!");
System.err.println("Printing an error!");
// Real exception (NPE)
Integer nullInteger = null;
System.out.println(nullInteger.toString()); // won't print and will produce a NullPointException
结果如下: As you can see, my System.out and System.err print fine but as soon as there is a real exception, it prints regularly.
所以我的问题是如何为此类错误设置自定义 PrintStream,以便将它们记录到文件中(最好遵循我的自定义消息格式)。
如果你深入了解 Throwable
class 如何打印堆栈跟踪,你会发现它使用了 println(Object)
方法,因此你需要将此方法添加到您的自定义 ErrorStream class:
@Override
public void println(Object object) {
println(String.valueOf(object));
}
即便如此,您也可能想要更改“未捕获的异常处理程序”以更改它记录异常的方式。似乎默认处理程序首先调用 System.err.print
以输出 Exception in thread "{ThreadName}"
,然后是 Throwable.printStackTrace
,因此您最终会在消息中间得到时间戳和其他内容。例如:
Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
System.err.println("Uncaught exception in thread " + thread.getName());
throwable.printStackTrace(System.err);
});