Java 将System.out.println重定向到日志

Java 将System.out.println重定向到日志,java,logging,Java,Logging,在我的项目测试套件中,大量使用了 System.out.println 我正在尝试将这些输出重定向到日志文件(通过配置或从单点重定向,而不重构整个项目),以便在需要时禁用这些输出以提高性能。我使用log4j进行日志记录。 有人知道这可能吗?如果是,怎么做? 提前谢谢。如果可能的话,我的建议是重构。 对于可能的解决方案,请检查这些类似的问题 使用shell重定向。找出项目的“java”调用,如果您使用的是最模糊的类UNIX系统,那么ps aux | grep java将有所帮助 然后用>/p

在我的项目测试套件中,大量使用了

System.out.println 
我正在尝试将这些输出重定向到日志文件(通过配置或从单点重定向,而不重构整个项目),以便在需要时禁用这些输出以提高性能。我使用log4j进行日志记录。 有人知道这可能吗?如果是,怎么做?
提前谢谢。

如果可能的话,我的建议是重构。 对于可能的解决方案,请检查这些类似的问题


使用shell重定向。找出项目的“java”调用,如果您使用的是最模糊的类UNIX系统,那么ps aux | grep java将有所帮助

然后用>/path/to/logfile运行这个命令。例如:

java -jar myjar.jar -cp path/to/lib.jar:path/to/otherlib.jar com.bigcorp.myproject.Main > /var/log/myproject.log
我认为您可以使用将输出设置为文件输出流。然后您可以将这一行放在BeforeClass方法中。我喜欢使用BaseTest类,并将这行代码放在该类的beforeclass方法中。然后让所有测试用例扩展这个类。

公共类递归日志记录{
public class RecursiveLogging {
public static void main(String[] args) {
    System.setOut(new PrintStream(new CustomOutputStream()));

    TestMyException.testPrint();
}

}

class CustomOutputStream extends OutputStream {
private Logger logger = Logger.getLogger(this.getClass());

@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.info((char) b);
}

@Override
public void write(byte[] b, int off, int len) throws IOException {
    if (b == null) {
        throw new NullPointerException();
    } else if ((off < 0) || (off > b.length) || (len < 0) ||
               ((off + len) > b.length) || ((off + len) < 0)) {
        throw new IndexOutOfBoundsException();
    } else if (len == 0) {
        return;
    }
    byte[] pb = new byte[len];
    for (int i = 0 ; i < len ; i++) {
        pb[i] = (b[off + i]);
    }
    String str = new String(pb);
    logger.info(str);
}
}
公共静态void main(字符串[]args){ 系统设置(新的打印流(新的CustomOutputStream()); TestMyException.testPrint(); } } 类CustomOutputStream扩展了OutputStream{ 私有记录器=Logger.getLogger(this.getClass()); @凌驾 公共最终无效写入(int b)引发IOException{ //正确的方法是使用缓冲区 //要存储字符直到遇到换行符, //此实现仅用于说明 logger.info((char)b); } @凌驾 公共无效写入(字节[]b,int off,int len)引发IOException{ 如果(b==null){ 抛出新的NullPointerException(); }如果((关闭<0)| |(关闭>b.length)| |(len<0)|| ((关+长)>b.length)| |((关+长)<0)){ 抛出新的IndexOutOfBoundsException(); }else if(len==0){ 返回; } 字节[]pb=新字节[len]; 对于(int i=0;i
鉴于最好更换
System.out.println()
,有时我们别无选择。无论如何,我已经为此做了一些实用程序:

SystemOutToSlf4j.enableForClass(MyClass.class)
然后,来自MyClass的所有println将重定向到记录器。


不是这个问题。本页非常详细地解释了这一点:不要因为重定向系统而犹豫不决,而是咬紧牙关,使用一个像样的IDE,一次过重构整个代码库,用log.info(…)代替。在方法
println(String)
调用
getLogger(caller.getClass())
应替换为
getLogger(caller.getClassName())
,否则为SLF4J配置的日志框架将打印
stackTraceeElement的类名。
public class SystemOutToSlf4j extends PrintStream {

  private static final PrintStream originalSystemOut = System.out;
  private static SystemOutToSlf4j systemOutToLogger;

  /**
   * Enable forwarding System.out.println calls to the logger if the stacktrace contains the class parameter
   * @param clazz
   */
  public static void enableForClass(Class clazz) {
    systemOutToLogger = new SystemOutToSlf4j(originalSystemOut, clazz.getName());
    System.setOut(systemOutToLogger);
  }


  /**
   * Enable forwarding System.out.println calls to the logger if the stacktrace contains the package parameter
   * @param packageToLog
   */
  public static void enableForPackage(String packageToLog) {
    systemOutToLogger = new SystemOutToSlf4j(originalSystemOut, packageToLog);
    System.setOut(systemOutToLogger);
  }

  /**
   * Disable forwarding to the logger resetting the standard output to the console
   */
  public static void disable() {
    System.setOut(originalSystemOut);
    systemOutToLogger = null;
  }

  private String packageOrClassToLog;

  private SystemOutToSlf4j(PrintStream original, String packageOrClassToLog) {
    super(original);
    this.packageOrClassToLog = packageOrClassToLog;
  }

  @Override
  public void println(String line) {
    StackTraceElement[] stack = Thread.currentThread().getStackTrace();
    StackTraceElement caller = findCallerToLog(stack);
    if (caller == null) {
      super.println(line);
      return;
    }

    org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(caller.getClass());
    log.info(line);
  }

  public StackTraceElement findCallerToLog(StackTraceElement[] stack) {
    for (StackTraceElement element : stack) {
      if (element.getClassName().startsWith(packageOrClassToLog))
        return element;
    }

    return null;
  }

}