java - 重定向 System.out 和 System.err

标签 java logging log4j

我有一些遗留代码(或者更确切地说是一些我们无法控制但我们必须使用的代码)将大量语句写入 system.out/err。

与此同时,我们正在使用一个框架,该框架使用围绕 log4j 的自定义日志记录系统(同样,很遗憾,我们无法控制它)。

所以我试图将 out 和 err 流重定向到将使用日志系统的自定义 PrintStream。我正在阅读有关 System.setLog()System.setErr() 方法的内容,但问题是我需要编写自己的 PrintStream 类来包装日志记录系统在使用中。那将是一个巨大的头痛。

有没有简单的方法可以做到这一点?

最佳答案

为了补充 Rick 和 Mikhail 的解决方案(在这种情况下确实是唯一的选择),我想举例说明创建自定义 OutputStream 如何可能导致问题检测/修复变得不那么容易。这是一些代码:

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import org.apache.log4j.Logger;

public class RecursiveLogging {
  /**
   * log4j.properties file:
   * 
   * log4j.rootLogger=DEBUG, A1
   * log4j.appender.A1=org.apache.log4j.ConsoleAppender
   * log4j.appender.A1.layout=org.apache.log4j.PatternLayout
   * log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
   * 
   */
  public static void main(String[] args) {
    // Logger.getLogger(RecursiveLogging.class).info("This initializes log4j!");
    System.setOut(new PrintStream(new CustomOutputStream()));
    System.out.println("This message causes a stack overflow exception!");
  }
}

class CustomOutputStream extends OutputStream {
  @Override
  public final void write(int b) throws IOException {
    // the correct way of doing this would be using a buffer
    // to store characters until a newline is encountered,
    // this implementation is for illustration only
    Logger.getLogger(CustomOutputStream.class).info((char) b);
  }
}

这个例子展示了使用自定义输出流的缺陷。为简单起见,write() 函数使用 log4j 记录器,但这可以替换为任何自定义日志记录工具(例如我的场景中的那个)。 main 函数创建一个包装 CustomOutputStream 的 PrintStream 并将输出流设置为指向它。然后它执行 System.out.println() 语句。此语句被重定向到 CustomOutputStream,CustomOutputStream 将其重定向到记录器。不幸的是,由于记录器是惰性初始化的,它将获取控制台输出流的副本(根据定义 ConsoleAppender 的 log4j 配置文件)为时已晚,即输出流将指向我们刚刚创建的 CustomOutputStream 导致重定向循环,因此在运行时出现 StackOverflowError。

现在,使用 log4j,这很容易解决:我们只需要在调用 System.setOut() 之前初始化 log4j 框架,例如,通过取消注释 main 函数的第一行。对我来说幸运的是,我必须处理的自定义日志记录工具只是 log4j 的包装器,我知道它会在为时已晚之前进行初始化。但是,对于在幕后使用 System.out/err 的完全自定义日志记录工具,除非可以访问源代码,否则无法判断是否以及在何处直接调用 System.out/err 而不是调用初始化期间获取的 PrintStream 引用。对于这种特殊情况,我能想到的唯一解决方法是检索函数调用堆栈并检测重定向循环,因为 write() 函数不应该是递归的。

关于java - 重定向 System.out 和 System.err,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14715748/

相关文章:

java - 防止 REST 客户端同时执行具有相同参数的相同方法

java - 包装 log4j 或创建自定义记录器?

python - Flask 请求的日志表单数据

python - 如何使用 Python 包分发日志配置

java - 仅排除一级 Log4j Logger

java - 如何确定使用 Spring Logging 扫描哪些包

java - 两个imageView Android之间的碰撞

Java日历添加问题

java - 如何将比较器传递给类的构造函数

logging - Sinatra 在日志文件中不显示异常