为Log4j未捕获的STDERR输出异常添加时间戳
给未捕获异常的STDERR输出添加时间戳的实现方案
你的思路完全没问题!用自定义PrintStream来给未被Log4j捕获的System.err输出加时间戳,确实是解决这类问题的有效方案。不过你给出的代码片段有点不完整,我帮你补全并优化一下,确保能稳定实现需求:
完整代码实现
1. 自定义PrintStream类 (MyPrintStream.java)
这个类负责给所有System.err的输出前缀加上格式化的时间戳:
import java.io.PrintStream; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; public class MyPrintStream extends PrintStream { // 统一时间格式,你可以根据需求调整 private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"); public MyPrintStream(PrintStream originalStream) { super(originalStream); } // 重写字符串类型的println方法 @Override public void println(String content) { super.printf("[%s] %s%n", getCurrentTime(), content); } // 重写对象类型的println方法,覆盖异常栈追踪的输出场景 @Override public void println(Object obj) { super.printf("[%s] %s%n", getCurrentTime(), obj); } // 重写基础print方法,确保所有输出都带上时间戳 @Override public void print(String content) { super.printf("[%s] %s", getCurrentTime(), content); } @Override public void print(Object obj) { super.printf("[%s] %s", getCurrentTime(), obj); } // 封装时间获取逻辑,方便统一修改 private String getCurrentTime() { return LocalDateTime.now().format(TIME_FORMATTER); } }
2. 主类调用示例 (Main.java)
在应用启动时替换默认的System.err为自定义实现:
public class Main { public static void main(String[] args) { // 替换System.err,保留原输出目的地的同时添加时间戳 System.setErr(new MyPrintStream(System.err)); // 模拟未捕获的NullPointerException,测试时间戳输出 Integer i = null; String str = i.toString(); } }
关键细节说明
- 重写多个输出方法:未捕获异常的栈追踪会调用不同的
print/println方法,只重写部分方法可能导致某些输出缺失时间戳,所以尽量覆盖常用的输出重载。 - 时间格式化:用Java 8+的
LocalDateTime和DateTimeFormatter是线程安全且更简洁的选择,避免了旧Date类的线程安全问题。 - 保留原输出目的地:构造自定义
PrintStream时传入原System.err,这样原本重定向到其他文件的STDERR输出不会被改变,只是内容前多了时间戳。
额外优化建议
如果希望把这些未捕获的异常也统一纳入Log4j的日志管理(而不是单独的文件),可以直接在自定义PrintStream中调用Log4j的日志接口,利用Log4j自带的时间戳和日志归档能力:
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.io.PrintStream; public class MyPrintStream extends PrintStream { private static final Logger ERROR_LOGGER = LogManager.getLogger("UncaughtExceptionLogger"); public MyPrintStream(PrintStream originalStream) { super(originalStream); } @Override public void println(String content) { ERROR_LOGGER.error(content); // 写入Log4j的错误日志 super.println(content); // 可选:保留原STDERR输出 } @Override public void println(Object obj) { ERROR_LOGGER.error(obj.toString()); super.println(obj); } }
内容的提问来源于stack exchange,提问作者Skartt
相关产品推荐
相关产品推荐

