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?
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?
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.
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))); –
@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
@neuralmer sicuro, che funziona pure –
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.
Forse sta provando a reindirizzare il sistema.verso un logger ;-) – Riduidel
+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. –
E questo non * difficile *. +1 – Nivas
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
}
Buona idea. Grazie – Jacky
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);
}
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();
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);
Bella soluzione * riutilizzabile *. Inoltre penso che l'interfaccia di blocco possa essere sostituita con Runnable. –
possibile duplicato del [Rimozione dell'accesso al System.out in java] (http://stackoverflow.com/questions/1710914/remove-access-to-system-out-in-java) –
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