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 Henrik Engert <he...@axiell.com> on 2005/11/17 11:21:40 UTC

Redirecting System.err to log4j

Hi,

This subject has been upp before, but I can not get it to work in our
app. We need/want to make sure that runtime exceptions such as
NullPointerException etc. should be logged together in our log file that
is managed by log4j. I have found some old emails on this mailing list
where the suggestion was to write your own Outputstream to get it to
work. I have tried to use that code, but we get a bunch of
space-characters in our logfile.

Is there any easier way in redirecting System.err to log4j?

Any suggestion would help.

Code below.

Thanks.

************************
import java.io.*;

import org.apache.log4j.*;

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

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 Logger logger;

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


    private LoggingOutputStream() {
        // illegal
    }


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

        this.level = level;
        logger = log;
        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
     * @throws 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);

        logger.log(level, 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;
    }

}
************************

************************
// remember STDERR
PrintStream se = System.err;

// make sure everything sent to System.err is logged
System.setErr(new PrintStream(new
        LoggingOutputStream(Logger.getRootLogger(),
          Level.WARN), true));

// make sure everything sent to System.out is also logged
System.setOut(new PrintStream(new
  LoggingOutputStream(Logger.getRootLogger(),
              Level.INFO), true));
***********************
###########################################

This message has been scanned by F-Secure Anti-Virus for Microsoft Exchange.
For more information, connect to http://www.f-secure.com/

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


Re: Redirecting System.err to log4j

Posted by Xavier Outhier <xa...@siemens.com>.
Xavier Outhier wrote:

> Try the modified code below, it should help to have a better output : 
> no blank,
> no empty line and should be valid on the 3 systems: linux, win and mac.
>
> Cheers,
>
> Xavier.
> [...]

The line below is of course useless. I used it for my own tests.

>  static Logger myLogger = 
> Logger.getLogger(JscLoggingOutputStream.class.getName());

[...]

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


Re: Redirecting System.err to log4j

Posted by Xavier Outhier <xa...@siemens.com>.
Try the modified code below, it should help to have a better output : no 
blank,
no empty line and should be valid on the 3 systems: linux, win and mac.

Cheers,

Xavier.

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;

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

//
public class JscLoggingOutputStream extends OutputStream {
  static Logger myLogger = 
Logger.getLogger(JscLoggingOutputStream.class.getName());
 
  /**
   * 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 Logger logger;
 
  /**
   * The priority to use when writing to the Category.
   */
  protected Level level;
 
 
  private JscLoggingOutputStream() {
    // illegal
  }
 
 
  /**
   * Creates the JscLoggingOutputStream to flush to the given Category.
   *
   * @param log      the Logger to write to
   * @param level the Level to use when writing to the Logger
   * @throws IllegalArgumentException if cat == null or priority ==
   * null
   */
  public JscLoggingOutputStream(Logger log, Level level)
  throws IllegalArgumentException {
    if (log == null) {
      throw new IllegalArgumentException("cat == null");
    }
    if (level == null) {
      throw new IllegalArgumentException("priority == null");
    }
   
    this.level = level;
    logger = log;
    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
   * @throws 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
   
    // For linux system
    if (count == 1 && ((char) buf[0]) == '\n') {
      reset();
      return;
    }
   
    // For mac system
    if (count == 1 && ((char) buf[0]) == '\r') {
      reset();
      return;
    }
   
   
    // On windows system
    if (count==2 && (char)buf[0]=='\r' && (char)buf[1]=='\n') {
      reset();
      return;
    }
   
    final byte[] theBytes = new byte[count];
   
    System.arraycopy(buf, 0, theBytes, 0, count);
   
    logger.log(level, 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;
  }
 
}
Henrik Engert wrote:

>Hi,
>
>This subject has been upp before, but I can not get it to work in our
>app. We need/want to make sure that runtime exceptions such as
>NullPointerException etc. should be logged together in our log file that
>is managed by log4j. I have found some old emails on this mailing list
>where the suggestion was to write your own Outputstream to get it to
>work. I have tried to use that code, but we get a bunch of
>space-characters in our logfile.
>
>Is there any easier way in redirecting System.err to log4j?
>
>Any suggestion would help.
>
>Code below.
>
>Thanks.
>
>************************
>import java.io.*;
>
>import org.apache.log4j.*;
>
>/**
> * An OutputStream that flushes out to a Category.<p>
> * <p/>
> * Note that no data is written out to the Category until the stream is
> * flushed or closed.<p>
> * <p/>
> * Example:<pre>
> * // make sure everything sent to System.err is logged
> * System.setErr(new PrintStream(new
>LoggingOutputStream(Category.getRoot(),
> * Priority.WARN), true));
> * <p/>
> * // make sure everything sent to System.out is also logged
> * System.setOut(new PrintStream(new
>LoggingOutputStream(Category.getRoot(),
> * Priority.INFO), true));
> * </pre>
> *
> * @author <a href="mailto://Jim.Moore@rocketmail.com">Jim Moore</a>
> * @see Category
> */
>
>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 Logger logger;
>
>    /**
>     * The priority to use when writing to the Category.
>     */
>    protected Level level;
>
>
>    private LoggingOutputStream() {
>        // illegal
>    }
>
>
>    /**
>     * Creates the LoggingOutputStream to flush to the given Category.
>     *
>     * @param log      the Logger to write to
>     * @param level the Level to use when writing to the Logger
>     * @throws IllegalArgumentException if cat == null or priority ==
>null
>     */
>    public LoggingOutputStream(Logger log, Level level)
>            throws IllegalArgumentException {
>        if (log == null) {
>            throw new IllegalArgumentException("cat == null");
>        }
>        if (level == null) {
>            throw new IllegalArgumentException("priority == null");
>        }
>
>        this.level = level;
>        logger = log;
>        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
>     * @throws 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);
>
>        logger.log(level, 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;
>    }
>
>}
>************************
>
>************************
>// remember STDERR
>PrintStream se = System.err;
>
>// make sure everything sent to System.err is logged
>System.setErr(new PrintStream(new
>        LoggingOutputStream(Logger.getRootLogger(),
>          Level.WARN), true));
>
>// make sure everything sent to System.out is also logged
>System.setOut(new PrintStream(new
>  LoggingOutputStream(Logger.getRootLogger(),
>              Level.INFO), true));
>***********************
>###########################################
>
>This message has been scanned by F-Secure Anti-Virus for Microsoft Exchange.
>For more information, connect to http://www.f-secure.com/
>
>---------------------------------------------------------------------
>To unsubscribe, e-mail: log4j-user-unsubscribe@logging.apache.org
>For additional commands, e-mail: log4j-user-help@logging.apache.org
>
>
>
>  
>


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