Redirect System.out.println - PullRequest
       23

Redirect System.out.println

31 голосов
/ 12 июля 2010

В моем приложении много операторов System.out.println ().

Я хочу отлавливать сообщения из println и отправлять их в стандартный регистратор (Log4j, JUL и т. Д.).

Как это сделать?

Ответы [ 6 ]

35 голосов
/ 12 июля 2010

Системный класс имеет setOut и setErr, которые можно использовать для изменения выходного потока, например, на новый PrintStream с подложкой File или, в данном случае, возможно, другой поток, который использует выбранную вами подсистему журналирования.


Имейте в виду, что у вас могут возникнуть проблемы, если вы когда-нибудь сконфигурируете свою библиотеку журналов для вывода на стандартный вывод или с ошибкой (возможно, с бесконечной рекурсией).

Если это так, вы можете просто заменить свои операторы типа System.out.print реальными вызовами регистрации.

30 голосов
/ 13 июля 2010

У меня была похожая потребность однажды. Мне нужно было перехватить вывод какого-либо стороннего компонента и отреагировать на сообщение об ошибке. Концепция выглядит так:

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
}
9 голосов
/ 12 июля 2010

Лучшее решение состоит в том, чтобы пройти и изменить все операторы println, чтобы использовать правильную библиотеку журналов.То, что вы пытаетесь сделать, это большой взлом.

2 голосов
/ 25 августа 2017

расширение PrintStream - плохое решение, так как вам придется переопределить все print() и println() методы. Вместо этого вы можете захватить поток:

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

Теперь вы можете захватить его так:

   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);
2 голосов
/ 11 апреля 2016

Вот как захватить отпечатки в System.out, а затем привести их в порядок:

// 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();
0 голосов
/ 04 июля 2013

Я применил базовую идею этого, и она отлично работает. Нет необходимости менять все содержимое System.out. ### и 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();
  }
}

Эти несколько строк включат ведение журнала без дальнейших изменений кода:

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