2010-07-12 6 views
30

Mon application contient de nombreuses instructions System.out.println().Redirect System.out.println

Je veux attraper des messages de println et les envoyer à l'enregistreur standard (Log4j, JUL etc.).

Comment faire?

+0

double possible de [Suppression de l'accès à System.out en java] (http://stackoverflow.com/questions/1710914/remove-access-to-system-out-in-java) –

+0

Bien qu'il y ait des croisements dans les réponses pour cette dupe possible, je ne pense pas que ce soit assez proche pour mériter une correspondance. C'est plus demander des moyens de bloquer la production tout à fait - celui-ci est pour le capturer ailleurs. – paxdiablo

Répondre

33

La classe System a un setOut et setErr qui peut être utilisé pour changer le flux de sortie, par exemple, une nouvelle PrintStream avec un support File ou, dans ce cas, probablement un autre cours d'eau qui utilise votre sous-système d'enregistrement de choix.


Gardez à l'esprit que vous pourriez bien vous avoir des ennuis si vous configurez jamais votre bibliothèque de journalisation à la sortie sur la sortie standard ou une erreur (du type de récursion infinie, peut-être).

Si c'est le cas, vous pouvez simplement remplacer vos instructions de type System.out.print par des appels de consignation réels.

+0

Pour compléter votre solution, je vous suggère d'ajouter des instructions sur la façon de revenir à la sortie standard lorsque vous avez intercepté tout ce qui est requis, par exemple System.setOut (nouveau PrintStream (nouveau FileOutputStream (FileDescriptor.out))); –

+0

@VicSeedoubleyew ne serait-il pas préférable de stocker l'original 'PrintStream' et de le restaurer ensuite - si quelque chose d'autre redirige également' System.out', cela ne le restaurera pas nécessairement correctement. – neuralmer

+0

@neuralmer sûr, cela fonctionne aussi bien –

8

La meilleure solution consiste à parcourir et modifier toutes les instructions println pour utiliser une bibliothèque de journalisation appropriée. Ce que vous essayez de faire est un gros bidouillage.

+0

Peut-être qu'il essaie de rediriger le système.à un Logger ;-) – Riduidel

+1

+1: le * point * entier d'un framework de journalisation doit être capable de résumer où vous enregistrez la sortie, vous devriez appeler ses méthodes de journalisation comme votre sortie "définitive" du code. Sans oublier que rediriger 'System.out' pour appeler le logger * semble * fonctionner; Jusqu'au jour où vous configurez le logger pour la sortie vers stdout, et ** bam ** - débordement de pile. –

+0

Et ce n'est pas * difficile *. +1 – Nivas

28

J'avais un besoin semblable une fois. Je devais intercepter la sortie d'un composant tiers et réagir sur un message d'erreur. Le concept ressemble à ceci:

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

Bonne idée. Merci – Jacky

-1

J'ai appliqué l'idée de base de cette situation et il workes bien. Pas besoin de changer tous les trucs System.out. ### et 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(); 
    } 
} 

Ce quelques lignes permettent l'exploitation forestière sans autre modification du code:

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

Voici comment capturer des impressions à System.out, puis de remettre les choses dans l'ordre:

// 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

extension PrintStream est une mauvaise solution car vous devrez remplacer toutes les méthodes print() et println(). Au lieu de cela, vous pouvez capturer le flux:

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

Maintenant vous pouvez capturer comme ceci:

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

Belle solution * réutilisable *. Aussi je pense que l'interface de bloc pourrait être remplacée par Runnable. –