如果你有一个无头构建机制,ant或类似的那样你可以将CheckStyle添加到构建并配置checkstyle以使构建失败,如果它在代码中找到任何System.out.println或e.printStackTrace。
如果你没有无头构建,我会建议你构建一个,因为这意味着你有可重复的,可预测的构建。
关闭System.out和System.err流。
将System.out和System.err流转换为每次写入字符时抛出RuntimeException(“使用日志而不是System.out”)的特殊实现。
如果你的容器很重要,他们会很快得到这个想法:)
(对于额外的奖励抛出OutOfMemoryException而不是;-))
我们使用log4j技巧但是登录到单独的文件(stdout.log,stderr.log)。将其输出与实际了解日志记录的部分混合在一起是没有用的...
假设您可以控制容器输出,您可以执行以下操作:
import java.io.*; public class SysOut { public static void main(String[] args) throws Exception { PrintStream pw = new PrintStream(new FileOutputStream("a.txt")); PrintStream realout = System.out; System.setOut(pw); System.out.println("junk"); realout.print("useful"); } } $ java SysOut useful $ cat a.txt junk
这里的关键是配置log4j 之前 重定向输出流,例如
BasicConfigurator.configure(); System.setOut(...); System.setErr(...); System.out.println("I fail"); Logger.getLogger(...).info("I work");
在替换它们之前,您实际上可以获取并存储System.out / err。
OutputStream out=System.getOut(); // I think the names are right System.setOut(some predefined output stream, null won't work); out.println("Hey, this still goes to the output"); System.out.println("Oh noes, this does not");
我用它拦截代码库中的所有System.out.println,并在每行输出前面加上它来自的方法名称/行号。
我所做的是将PrintStream for System.out和System.err重定向到commons-logging分别作为INFO和ERROR级别日志记录。
如果您希望某些线程能够写入控制台,或者您希望日志也可以转到控制台,那么这会变得更加棘手,但是可以完成。
您可以使用 System.setOut() 和 System.setErr() 重定向 stdout 和 stderr 到实例 PrintStream 。
System.setOut()
System.setErr()
stdout
stderr
PrintStream
System.setOut 将 重定向所有输出 - 但您提供的PrintStream可以决定如何处理输出。因此,我确信您可以提供只会实际打印应用程序语句的流。
System.setOut
唯一棘手的部分实际上是能够检测到什么是有效的呼叫,什么不是。一个工作但可能很慢的方法是打电话 Thread.currentThread().getStackTrace() 并查看哪些代码(或包,至少)正在呼叫您(如果它不是有效代码,则返回)。我不建议这样做,因为性能命中将是惊人的,特别是在读取的每个字节上执行此操作。
Thread.currentThread().getStackTrace()
更好的想法可能是在所有有效的容器线程中设置ThreadLocal标志。然后,您可以实现类似以下内容的PrintStream:
public class ThreadValidity extends ThreadLocal<Boolean> { private static final INSTANCE = new ThreadValidity(); @Override Boolean initialValue() { return false; } public static ThreadValidity getInstance() { return INSTANCE; } } class VerifyingPrintStream extends PrintStream { private boolean isValidThread() { return ThreadValidity.instance().get(); } public void println(String s) { if (!isValidThread()) return; super.println(s); } public void println(Object o) { if (!isValidThread()) return; super.println(o); } // etc }
或者,如果你能够改变 println 在容器代码中,事情变得更容易。您可以将所有控制台写入权交给特定的工作人员;并让这个worker“窃取”System.out(将它存储在自己的字段中并直接用它来写输出),同时将实际的System.out设置为无操作的编写器。
println
使用厌恶疗法。每当检查包含令人不快的构造的任何代码时,就会安排“检查员”的访问。
Nice cubicle you got ere, be shame if anyfing appened to it.