一、控制台输出:PrintStream类

Java输出日志到控制台主要是靠PrintStream来完成,如:

System.out

的源码就是个PrintStream

java中tail 查看日志 查看java控制台日志_java中tail 查看日志


因此,想要截取控制台需要自己来接替PrintStream的部分工作。

二、替换输出流

首先,我们需要一个ByteArrayOutputStream类来代替PrintStream的工作,为了实现截取打印日志的功能这里我继承ByteArrayOutputStream类写了一个自定义的工具类ConsoleStream:

public class ConsoleStream extends ByteArrayOutputStream {

    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    private PrintStream oldPrintStream;
    private PrintStream newPrintStream;

    public ConsoleStream(PrintStream oldPrintStream){
        this.oldPrintStream=oldPrintStream;
        this.newPrintStream = new PrintStream(this);
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) {
            throw new OutOfMemoryError();
        }
        return (minCapacity > MAX_ARRAY_SIZE) ?
                Integer.MAX_VALUE :
                MAX_ARRAY_SIZE;
    }


    private void ensureCapacity(int minCapacity) {
        // overflow-conscious code
        if (minCapacity - buf.length > 0){
            grow(minCapacity);
        }
    }

    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = buf.length;
        int newCapacity = oldCapacity << 1;
        if (newCapacity - minCapacity < 0){
            newCapacity = minCapacity;
        }

        if (newCapacity - MAX_ARRAY_SIZE > 0){
            newCapacity = hugeCapacity(minCapacity);
        }

        buf = Arrays.copyOf(buf, newCapacity);
    }

    /**
     * Writes the specified byte to this byte array output stream.
     *
     * @param   b   the byte to be written.
     */
    @Override
    public synchronized void write(int b) {
        ensureCapacity(count + 1);
        buf[count] = (byte) b;
        count += 1;
    }

    /**
     * Writes <code>len</code> bytes from the specified byte array
     * starting at offset <code>off</code> to this byte array output stream.
     *
     * @param   b     the data.
     * @param   off   the start offset in the data.
     * @param   len   the number of bytes to write.
     */
    @Override
    public synchronized void write(byte b[], int off, int len) {
        String s = new String(b);
        //切换回原输出流输出日志到真控制台
        System.setOut(oldPrintStream);
        System.out.print("newStream:"+s);
        System.setOut(newPrintStream);
        if ((off < 0) || (off > b.length) || (len < 0) ||
                ((off + len) - b.length > 0)) {
            throw new IndexOutOfBoundsException();
        }
        ensureCapacity(count + len);
        System.arraycopy(b, off, buf, count, len);
        count += len;
    }

}

其中我们重写了 write(byte b[], int off, int len) 和它的构造方法,传参byte b[] 为写入的日志,你可以用它做你想做的事。其中:

//切换回原输出流输出日志到真控制台
 System.setOut(oldPrintStream);
 System.out.print("newStream:"+s);
 System.setOut(newPrintStream);

这部分代码是为了解决由于我们截取了PrintStream,导致真正的控制台以及依赖于控制台的日志插件无日志输出的问题。

同时我们需要将控制台输出流导向我们重写的这个工具类,在main方法中加入以下代码:

//备份原有输出流
  PrintStream old = System.out;
  ConsoleStream newStream= new ConsoleStream(old);
  //设置新的输出流
  System.setOut(new PrintStream(newStream));

此时控制台的日志打印已由新建的工具类接替。

java中tail 查看日志 查看java控制台日志_控制台_02