2010-07-12 17 views
30

La mia applicazione ha molte istruzioni System.out.println().Reindirizza System.out.println

Voglio catturare messaggi da println e inviarli al registratore standard (Log4j, JUL ecc.).

Come fare?

+0

possibile duplicato del [Rimozione dell'accesso al System.out in java] (http://stackoverflow.com/questions/1710914/remove-access-to-system-out-in-java) –

+0

Mentre ci sono crossover nelle risposte per quel possibile dupe, non penso che sia abbastanza vicino per meritare una corrispondenza. È più chiedere modi per bloccare del tutto l'output - questo è per catturarlo altrove. – paxdiablo

risposta

33

La classe System ha un setOut e setErr che può essere utilizzato per modificare il flusso di output, ad esempio, un nuovo PrintStream con un supporto File o, in questo caso, probabilmente, un altro flusso che utilizza il sottosistema di registrazione di scelta.


Tenete a mente si può anche farti nei guai se mai configurare la libreria di registrazione per l'output sullo standard output o di errore (di tipo ricorsione infinita, forse).

Se questo è il caso, si consiglia di andare e sostituire le istruzioni System.out.print -type con chiamate di registrazione reali.

+0

Per completare la soluzione, suggerisco di aggiungere istruzioni su come ripristinare il normale output standard dopo aver intercettato tutto ciò che è necessario, ovvero System.setOut (new PrintStream (new FileOutputStream (FileDescriptor.out))); –

+0

@VicSeedoubleyew non sarebbe meglio memorizzare l'originale 'PrintStream' e ripristinarlo in seguito - se qualcos'altro sta reindirizzando' System.out', questo non lo ripristinerà necessariamente correttamente. – neuralmer

+0

@neuralmer sicuro, che funziona pure –

8

La soluzione migliore è passare e modificare tutte le istruzioni println per utilizzare una libreria di registrazione appropriata. Quello che stai cercando di fare è un grande hack.

+0

Forse sta provando a reindirizzare il sistema.verso un logger ;-) – Riduidel

+1

+1: l'intero * punto * di un framework di registrazione deve essere in grado di astrarre dove si sta registrando l'output, è necessario chiamare i suoi metodi di registrazione come output "definitivo" dal codice. Per non parlare, il reindirizzamento di 'System.out' per chiamare il logger * sembra * funzionare; fino al punto in cui un giorno configuri il logger in output su stdout e ** bam ** - overflow dello stack. –

+0

E questo non * difficile *. +1 – Nivas

28

Ho avuto una necessità simile una volta. Avevo bisogno di intercettare l'output di alcuni componenti di terze parti e reagire su un messaggio di errore. Il concetto è simile al seguente:

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 
} 
+2

Buona idea. Grazie – Jacky

-1

ho applicato l'idea di base di questo ed è Workes bene. Non è necessario modificare tutti i file System.out. ### e 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(); 
    } 
} 

queste poche righe saranno abilitare la registrazione senza ulteriori modifiche al codice:

if(writeLog) 
    { 
    this.logFileName = this.getClassName() + "_Log.txt"; 
    this.icMan = new InterceptionManager(this.logFileName, false); 
    System.out.format("Logging to '%s'\n", this.logFileName); 
    } 
2

Ecco come catturare stampe a System.out, e poi mettere le cose in ordine:

// 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(); 
1

estendere PrintStream è una soluzione non valida in quanto sarà necessario eseguire l'override di tutti i metodi print() e println(). Invece, è possibile catturare il flusso:

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(); 
    } 
} 

Ora è possibile catturare in questo modo:

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); 
+0

Bella soluzione * riutilizzabile *. Inoltre penso che l'interfaccia di blocco possa essere sostituita con Runnable. –

Problemi correlati