捕获Java中特定线程的控制台输出

时间:2009-04-12 13:29:54

标签: java multithreading console

我意识到SO上有类似的问题,但它们并没有完全解决我的问题。

我想要一个方法,给定一个Class对象,将调用该类上的“main”方法,即public static void main(如果存在)并捕获该main方法的控制台输出。执行调用的类是非守护程序线程。

我已经有了部分代码,但是我不知道如何捕获控制台输出,最重要的是,如何只为这个特定的线程捕获它。这是我到目前为止所做的:

public class Output extends Thread {
    private Class testClass;

    public Output(Class clazz) {
        this.testClass = clazz;
    }

    private Method getMainMethod(Class clazz) {
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            if (isMainMethod(method)) { 
                return method;
            }
        }

        return null;
    }

    private Boolean isMainMethod(Method method) {
        return (method.getName().equals("main") &&
                Modifier.isStatic(method.getModifiers()) &&
                method.getReturnType().equals(Void.class));
    }

    public void run() {
        Method mainMethod = null;

        if ((mainMethod = getMainMethod(this.testClass)) == null) {
            //if there's no static void main method, throw exception
            throw new YouFuckedItUpException();
        }

        mainMethod.invoke(this.testClass, new String[0]);

        return heresWhereImStuckIWantToCaptureTheConsoleOutputAndReturnIt();
    }
}

我需要的只是一些代码,或者是如何捕获所调用方法的System.out和System.err输出的答案的链接。任何人都可以给予的帮助将不胜感激。

提前致谢!

编辑:这不仅仅用于测试,最终会投入生产。

编辑2 :这需要是线程安全的。其他线程可能会同时调用多个主要方法,我希望每个线程只捕获自己的特定输出。

3 个答案:

答案 0 :(得分:5)

使用System.setOut,然后编写一个printstream的子类,它覆盖所有打印/写入方法,并记录数据,如果它来自您要监视的线程。

伪代码:

public class HackedPrintStream extends PrintStream {
    private PrintStream originalStream;
    private HashMap<Thread, PrintStream> loggerStreams = new HashMap<Thread, PrintStream>();

    public HackedPrintStream(PrintStream originalStream) {
        this.originalStream = originalStream;
    }

    public synchronized void logForThread(Thread threadToLogFor, PrintStream streamToLogTo) {
        loggerStreams.put(threadToLogFor, streamToLogTo);
    }

    /** example overridden print method, you need to override all */
    public synchronized void println(String ln) {
        PrintStream logPS = loggerStreams.get(Thread.currentThread());
        if (logPS != null) { logPS.println(ln); }
        originalStream.println(ln);
    }
}

然后您可以使用

创建和使用此流
HackedPrintStream hps = new HackedPrintStream(System.out);
System.setOut(hps);

我真的建议你努力寻找另一种解决方案,因为这不是很好。

答案 1 :(得分:2)

由于您使用main()方法 - 您是否需要它在同一个过程中?如果没有,您可以尝试将其创建为新流程(java.lang.Process)。

Process类提供了捕获StdOutStdErr和/或StdIn的必要方法。

注意因为一切都在它自己的进程中运行,所以线程安全应该没有问题。但是,您仍然需要找到位置,.class文件(或至少是根目录),以便您可以使用java here.goes.your.ClassName运行/创建流程。

答案 2 :(得分:-1)

您可以使用System.setOut()和System.setErr(),但当然,输出也将被捕获用于程序的其余部分。