You are viewing a plain text version of this content. The canonical link for it is here.
Posted to log4j-user@logging.apache.org by Gunter Sammet <Gu...@sammet.net> on 2001/09/07 16:31:27 UTC

Capture System.err in log file

Hello all:
I implemented the LoggingOutputStream class from Jim Moore. It works fine
except that the logging includes a lot of invisible characters. One error
(see attached log file) and a few info logs create a 120 KB file (I deleted
most of the rows, because I got the mail bounced back). Is there a way to
get rid of these characters?

This is my implementation code:
      //This is a test to redirect System.err to log4j:
      // make sure everything sent to System.err is logged
      System.setErr(new PrintStream(new
LoggingOutputStream(Category.getRoot(), Priority.WARN), true));
      // make sure everything sent to System.out is also logged
      System.setOut(new PrintStream(new
LoggingOutputStream(Category.getRoot(), Priority.INFO), true));

Is there anything I have to watch out for?
TIA

Gunter

Following the code for the class:

List:     log4j-user
Subject:  RE: Capturing System.err
From:     Jim Moore <ji...@veritas.com>
Date:     2001-01-31 21:29:38
[Download message RAW]

I got it working, with a twist to your suggestion.  For anybody that wants
to do it also, here's the code:

import java.io.*;
import org.apache.log4j.*;

/**
 * An OutputStream that flushes out to a Category.<p>
 *
 * Note that no data is written out to the Category until the stream is
 *   flushed or closed.<p>
 *
 * Example:<pre>
 * // make sure everything sent to System.err is logged
 * System.setErr(new PrintStream(new LoggingOutputStream(Category.getRoot(),
Priority.WARN), true));
 *
 * // make sure everything sent to System.out is also logged
 * System.setOut(new PrintStream(new LoggingOutputStream(Category.getRoot(),
Priority.INFO), true));
 * </pre>
 *
 * @see Category
 * @author <a href="mailto://Jim.Moore@rocketmail.com">Jim Moore</a>
 */
public class LoggingOutputStream extends OutputStream {

  /**
   * Used to maintain the contract of {@link #close()}.
   */
  protected boolean hasBeenClosed = false;

  /**
   * The internal buffer where data is stored.
   */
  protected byte[] buf;

  /**
   * The number of valid bytes in the buffer. This value is always
   *   in the range <tt>0</tt> through <tt>buf.length</tt>; elements
   *   <tt>buf[0]</tt> through <tt>buf[count-1]</tt> contain valid
   *   byte data.
   */
  protected int count;

  /**
   * Remembers the size of the buffer for speed.
   */
  private int bufLength;

  /**
   * The default number of bytes in the buffer. =2048
   */
  public static final int DEFAULT_BUFFER_LENGTH = 2048;


  /**
   * The category to write to.
   */
  protected Category category;

  /**
   * The priority to use when writing to the Category.
   */
  protected Priority priority;


  private LoggingOutputStream() {
    // illegal
  }


  /**
   * Creates the LoggingOutputStream to flush to the given Category.
   *
   * @param cat        the Category to write to
   *
   * @param priority   the Priority to use when writing to the Category
   *
   * @exception IllegalArgumentException
   *                   if cat == null or priority == null
   */
  public LoggingOutputStream(Category cat, Priority priority)
  throws IllegalArgumentException {
    if (cat == null) {
      throw new IllegalArgumentException("cat == null");
    }
    if (priority == null) {
      throw new IllegalArgumentException("priority == null");
    }

    this.priority = priority;
    category = cat;
    bufLength = DEFAULT_BUFFER_LENGTH;
    buf = new byte[DEFAULT_BUFFER_LENGTH];
    count = 0;
  }


  /**
   * Closes this output stream and releases any system resources
   *   associated with this stream. The general contract of
<code>close</code>
   *   is that it closes the output stream. A closed stream cannot perform
   *   output operations and cannot be reopened.
   */
  public void close() {
    flush();
    hasBeenClosed = true;
  }


  /**
   * Writes the specified byte to this output stream. The general
   * contract for <code>write</code> is that one byte is written
   * to the output stream. The byte to be written is the eight
   * low-order bits of the argument <code>b</code>. The 24
   * high-order bits of <code>b</code> are ignored.
   *
   * @param b          the <code>byte</code> to write
   *
   * @exception IOException
   *                   if an I/O error occurs. In particular,
   *                   an <code>IOException</code> may be thrown if the
   *                   output stream has been closed.
   */
  public void write(final int b) throws IOException {
    if (hasBeenClosed) {
      throw new IOException("The stream has been closed.");
    }

    // would this be writing past the buffer?
    if (count == bufLength) {
      // grow the buffer
      final int newBufLength = bufLength+DEFAULT_BUFFER_LENGTH;
      final byte[] newBuf = new byte[newBufLength];

      System.arraycopy(buf, 0, newBuf, 0, bufLength);

      buf = newBuf;
      bufLength = newBufLength;
    }

    buf[count] = (byte)b;
    count++;
  }


  /**
   * Flushes this output stream and forces any buffered output bytes
   *   to be written out. The general contract of <code>flush</code> is
   *   that calling it is an indication that, if any bytes previously
   *   written have been buffered by the implementation of the output
   *   stream, such bytes should immediately be written to their
   *   intended destination.
   */
  public void flush() {
    if (count == 0)  {
      return;
    }

    // don't print out blank lines; flushing from PrintStream puts out these
    if (count == 1 && ((char)buf[0]) == '\n')  {
      reset();
      return;
    }

    final byte[] theBytes = new byte[buf.length];

    System.arraycopy(buf, 0, theBytes, 0, count);

    category.log(priority, new String(theBytes));

    reset();
  }


  private void reset() {
    // not resetting the buffer -- assuming that if it grew then it
    //   will likely grow similarly again
    count = 0;
  }

}


Works perfectly.

-Jim Moore


-----Original Message-----
From: Ceki Gülcü [mailto:cgu@urbanet.ch]
Sent: Tuesday, January 30, 2001 12:28 PM
To: LOG4J Users Mailing List
Subject: Re: Capturing System.err



Jim,

How about creating a PrintStream, say X, that captures System.err. You can
do this by invoking System.setErr(x) where x is an instance of X.

The print(String s) and println(String s) methods of X would then redirect
to log4j by calling root.info(s) where root is the root category. I have not
tried this but the idea has been suggested by a number of log4j users. Do
you think that would work? Ceki

---------------------------------------------------------------------
To unsubscribe, e-mail: log4j-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: log4j-user-help@jakarta.apache.org