一、控制台输出:PrintStream类
Java输出日志到控制台主要是靠PrintStream来完成,如:
System.out
的源码就是个PrintStream
因此,想要截取控制台需要自己来接替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));
此时控制台的日志打印已由新建的工具类接替。