java - Redirigir System.out.println
logging redirectstandardoutput (6)
A continuación, se indica cómo capturar impresiones en System.out y luego volver a ponerlas en orden:
// Start capturing
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
System.setOut(new PrintStream(buffer));
// Run what is supposed to output something
...
// Stop capturing
System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out)));
// Use captured content
String content = buffer.toString();
buffer.reset();
Mi aplicación tiene muchas declaraciones System.out.println ().
Quiero capturar mensajes de println y enviarlos al registrador estándar (Log4j, JUL, etc.).
Como hacer eso ?
Apliqué la idea base de esto y funciona bien. No es necesario cambiar todas las cosas de System.out. ### y System.err. ###.
import java.io.OutputStream;
import java.io.PrintStream;
import de.msg.pm.designer.services.simulation.junit.base.Defines;
public class Interceptor extends PrintStream
{
/** the logger */
private Logger log;
/** the origin output stream */
PrintStream orig;
/**
* Initializes a new instance of the class Interceptor.
*
* @param out the output stream to be assigned
* @param log the logger
*/
public Interceptor( OutputStream out, Logger log )
{
super( out, true );
this.log = log;
}
/**
* {@inheritDoc}
*/
@Override
protected void finalize() throws Throwable
{
detachOut();
super.finalize();
}
/**
* {@inheritDoc}
*/
@Override
public void print( String s )
{
//do what ever you like
orig.print( s );
log.logO( s, true );
}
/**
* {@inheritDoc}
*/
@Override
public void println( String s )
{
print( s + Defines.LF_GEN );
}
/**
* Attaches System.out to interceptor.
*/
public void attachOut()
{
orig = System.out;
System.setOut( this );
}
/**
* Attaches System.err to interceptor.
*/
public void attachErr()
{
orig = System.err;
System.setErr( this );
}
/**
* Detaches System.out.
*/
public void detachOut()
{
if( null != orig )
{
System.setOut( orig );
}
}
/**
* Detaches System.err.
*/
public void detachErr()
{
if( null != orig )
{
System.setErr( orig );
}
}
}
public class InterceptionManager
{
/** out */
private Interceptor out;
/** err */
private Interceptor err;
/** log */
private Logger log;
/**
* Initializes a new instance of the class InterceptionManager.
*
* @param logFileName the log file name
* @param append the append flag
*/
public InterceptionManager( String logFileName, boolean append )
{
log = new Logger();
log.setLogFile( logFileName, append );
this.out = new Interceptor( System.out, log );
this.out.attachOut();
this.err = new Interceptor( System.err, log );
this.err.attachErr();
}
/**
* {@inheritDoc}
*/
@Override
protected void finalize() throws Throwable
{
if( null != log )
{
log.closeLogFile();
}
super.finalize();
}
}
Estas pocas líneas permitirán el registro sin más cambios de código:
if( writeLog )
{
this.logFileName = this.getClassName() + "_Log.txt";
this.icMan = new InterceptionManager( this.logFileName, false );
System.out.format( "Logging to ''%s''/n", this.logFileName );
}
La mejor solución es pasar y cambiar todas las instrucciones println para usar una biblioteca de registro adecuada. Lo que estás tratando de hacer es un gran truco.
Una vez tuve una necesidad similar. Necesitaba interceptar el resultado de un componente de terceros y reaccionar ante un mensaje de error. El concepto se ve así:
private class Interceptor extends PrintStream
{
public Interceptor(OutputStream out)
{
super(out, true);
}
@Override
public void print(String s)
{//do what ever you like
super.print(s);
}
}
public static void main(String[] args)
{
PrintStream origOut = System.out;
PrintStream interceptor = new Interceptor(origOut);
System.setOut(interceptor);// just add the interceptor
}
extender PrintStream es una mala solución, ya que tendrá que anular todos los métodos print()
e println()
. En cambio, puedes capturar la transmisión:
public class ConsoleInterceptor {
public interface Block {
void call() throws Exception;
}
public static String copyOut(Block block) throws Exception {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
PrintStream printStream = new PrintStream(bos, true);
PrintStream oldStream = System.out;
System.setOut(printStream);
try {
block.call();
}
finally {
System.setOut(oldStream);
}
return bos.toString();
}
}
Ahora puedes capturarlo así:
String result = ConsoleInterceptor.copyOut(() ->{
System.out.print("hello world");
System.out.print(''!'');
System.out.println();
System.out.println("foobar");
});
assertEquals("hello world!/nfoobar/n", result);
La clase System tiene un setOut
y setErr
que pueden usarse para cambiar el flujo de salida a, por ejemplo, un nuevo PrintStream
con un File
respaldo o, en este caso, probablemente otro flujo que use su subsistema de registro de elección.
Tenga en cuenta que puede meterse en problemas si alguna vez configura su biblioteca de inicio de sesión para generar un resultado o error estándar (del tipo de recursión infinita, posiblemente).
Si ese es el caso, puede ir y reemplazar sus declaraciones System.out.print
type con llamadas de registro reales.