ceki 01/04/20 10:32:58 Modified: contribs CONTENTS Added: contribs/JimMoore LoggingOutputStream.java mail-2001-03-12T1326 mail-2001-03-12T1454 mail-2001-03-13T0646 Log: Added Jim Moore's LoggingOutputStream.java. Revision Changes Path 1.3 +8 -0 jakarta-log4j/contribs/CONTENTS Index: CONTENTS =================================================================== RCS file: /home/cvs/jakarta-log4j/contribs/CONTENTS,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- CONTENTS 2001/02/16 12:00:22 1.2 +++ CONTENTS 2001/04/20 17:32:44 1.3 @@ -25,6 +25,14 @@ LogTextPanelExample.java TextPanelAppender.java +JimMoore/ +======== + + LoggingOutputStream.java + + Allows the user to divert System.out and System.err to log4j. + + MarkDouglas/ =========== 1.1 jakarta-log4j/contribs/JimMoore/LoggingOutputStream.java Index: LoggingOutputStream.java =================================================================== /* * Copyright (C) The Apache Software Foundation. All rights reserved. * * This software is published under the terms of the Apache Software * License version 1.1, a copy of which has been included with this * distribution in the LICENSE.APL file. */ 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> * * @author <a href="mailto:[EMAIL PROTECTED]">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 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."); } // don't log nulls if (b == 0) { return; } // 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[count]; 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 that it // will likely grow similarly again count = 0; } } 1.1 jakarta-log4j/contribs/JimMoore/mail-2001-03-12T1326 Index: mail-2001-03-12T1326 =================================================================== Copied from: http://www.mail-archive.com/log4j-user@jakarta.apache.org/msg00430.html -------------------------------------------------------------------------------- diverting System.stderr/stdout into log4j -------------------------------------------------------------------------------- From: Joseph Panico Subject: diverting System.stderr/stdout into log4j Date: Mon, 12 Mar 2001 13:26:41 -0800 -------------------------------------------------------------------------------- Folks, We use a number of third-party packages that do stderr.print... at various random places in their code. I'm finding it quite useful to divert these messages into our log4j heirarchy. I do this by replacing stderr/stdout with my own PrintStreams that log the lines to a special log4j Category-- as suggested on this list a while back. The only fly-in-the-ointment with this scheme is LogLog. If there is a problem with log4j such that it cannot log for some reason, then log4j internals use LogLog to attempt to print an error message. This obviously leads to an infinite recursion. Has anyone else been bothered by this? Would it make sense to add interface to LogLog which would set the PrintStream it uses to log its error messages to? thanks for any ideas joe _________________________________________________________________ Get your FREE download of MSN Explorer at http://explorer.msn.com --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] 1.1 jakarta-log4j/contribs/JimMoore/mail-2001-03-12T1454 Index: mail-2001-03-12T1454 =================================================================== Copied from: http://www.mail-archive.com/log4j-user@jakarta.apache.org/msg00433.html -------------------------------------------------------------------------------- RE: diverting System.stderr/stdout into log4j -------------------------------------------------------------------------------- From: Jim Moore Subject: RE: diverting System.stderr/stdout into log4j Date: Mon, 12 Mar 2001 14:54:13 -0800 -------------------------------------------------------------------------------- It doesn't. I haven't worried about it, since log4j doesn't contain any bugs and therefore it would never happen... :) Probably the best way to handle it is to add a LogLog.setPrintStream(PrintStream) method, so you can do something like: // remember STDERR PrintStream se = System.err; // 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)); // prevent infinate recursion in LogLog LogLog.setPrintStream(se); I can't think of any other way to do it in the current version besides getting extremely kludgey by checking the stack to see if it's being called from LogLog and logging out the the "real" STDERR then in the LoggingOutputStream. It can be done on the theory that LogLog wouldn't be called very often, but still... -Jim Moore -----Original Message----- From: Ceki Gülcü [mailto:[EMAIL PROTECTED]] Sent: Monday, March 12, 2001 5:15 PM To: LOG4J Users Mailing List Subject: RE: diverting System.stderr/stdout into log4j Jim, Joseph, Here is a link containing Jim's code: http://marc.theaimsgroup.com/?l=log4j-user&m=98097669218571&w=2 How does this code handle the infinite recursion problem mentioned by Joseph? Ceki At 17:03 12.03.2001 -0500, Jim Moore wrote: >Go to the mailing list archives (theAimsGroup.com is the best) and search >for the thread with the subject of "Capturing System.err" > >-Jim Moore >"I think so, Brain; but if we gave peas a chance, won't the lima beans get >jealous?" - Pinky > > >-----Original Message----- >From: Joseph Panico [mailto:[EMAIL PROTECTED]] >Sent: Monday, March 12, 2001 4:43 PM >To: [EMAIL PROTECTED] >Subject: diverting System.stderr/stdout into log4j > > >Folks, > >We use a number of third-party packages that do stderr.print... at various >random places in their code. I'm finding it quite useful to divert these >messages into our log4j heirarchy. I do this by replacing stderr/stdout with > >my own PrintStreams that log the lines to a special log4j Category-- as >suggested on this list a while back. The only fly-in-the-ointment with this >scheme is LogLog. If there is a problem with log4j such that it cannot log >for some reason, then log4j internals use LogLog to attempt to print an >error message. This obviously leads to an infinite recursion. Has anyone >else been bothered by this? Would it make sense to add interface to LogLog >which would set the PrintStream it uses to log its error messages to? > >thanks for any ideas > >joe I hope to see you at my ApacheCon 2001 presentation entitled "Log4j, A Logging Package for Java". See http://ApacheCon.Com/2001/US/ for more details. ---- Ceki Gülcü Web: http://qos.ch av. de Rumine 5 email: [EMAIL PROTECTED] (preferred) CH-1005 Lausanne [EMAIL PROTECTED] Switzerland Tel: ++41 21 351 23 15 --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] 1.1 jakarta-log4j/contribs/JimMoore/mail-2001-03-13T0646 Index: mail-2001-03-13T0646 =================================================================== Copied from http://www.mail-archive.com/log4j-user@jakarta.apache.org/msg00445.html -------------------------------------------------------------------------------- RE: diverting System.stderr/stdout into log4j -------------------------------------------------------------------------------- From: Michael Smith Subject: RE: diverting System.stderr/stdout into log4j Date: Tue, 13 Mar 2001 06:46:04 -0800 -------------------------------------------------------------------------------- There is another way! In LogLog, completely ignore System.err. Instead, use the following to get the standard error stream: PrintStream err = new PrintStream(new FileOutputStream(FileDescriptor.err)); When you use System.setErr, it changes System.err, but not FileDescriptor.err, which maintains a descriptor for the original error stream. michael For a sample program to test this, see below: import java.io.*; public class Stderr { public static void main(String[] args) { // create a print stream to represent a redirect PrintStream nonStandardErr = new PrintStream(new ByteArrayOutputStream()); // Redirect standard out and standard err System.setOut(nonStandardErr); System.setErr(nonStandardErr); // attempt to print something System.err.println("You should *not* see this on the console!"); // the stuff that would appear in LogLog PrintStream logLogOut = new PrintStream(new FileOutputStream(FileDescriptor.err)); // attempt to print something logLogOut.println("You *should* see this on the console!"); } } > -----Original Message----- > From: Ceki Gülcü [mailto:[EMAIL PROTECTED]] > Sent: Monday, March 12, 2001 7:18 PM > To: LOG4J Users Mailing List > Subject: RE: diverting System.stderr/stdout into log4j > > > > Hate to follow up on myself, but the System.setErr method > reassigns the System.err variable. This can be deduced without > experimentation because the user calls the System.err variable > directly to print to the console, whatever it might be. Thus, the > reference itself must change to allow the System.err variable to > point to the new target stream. > > The funny part is that the err variable is declared 'public > final' in the JDK source code. The setErr method makes a call to > setErr0 which is declared as being 'native'. It looks like the > native part is circumventing the JDK restrictions. I find this > quite entertaining. Ceki > > At 00:58 13.03.2001 +0100, Ceki Gülcü wrote: > > >Running the risk of disappointing you here, although not full of > bugs, log4j is not bug-free as bugs creep out regularly. They > just get corrected quickly before many people are affected by them. > > > >The PrintStream se = System.err; LogLog.setPrintStream(see); > combination is simple and rather bright. I initially overlooked > the PrintStream se = System.err; part, making me think that a > lot of code needed to be modified to cater for the redirected > console case. The remedy looked worse than the illness. My fears > are largely unfounded and the solution should work quite well if > one is careful. > > > >Regards, Ceki > > > >ps: I wonder if System.err always refers to the real STDERR or > if really gets reassigned with the setErr call. It's easy to find out... > > > >At 23:20 12.03.2001 +0000, Joseph Panico wrote: > >>Of course log4j is completely bug free, but that doesn't > preclude user error. For instance, I neglected to add appenders > in my config file (actually I intentionally left them out, > thinking that would simply turn off logging) and then log4j went > into an infinite loop. The setPrintStream makes sense to me. > >> > >>joe > >> > >> > >>>From: Jim Moore <[EMAIL PROTECTED]> > >>>Reply-To: "LOG4J Users Mailing List" <[EMAIL PROTECTED]> > >>>To: 'LOG4J Users Mailing List' <[EMAIL PROTECTED]> > >>>Subject: RE: diverting System.stderr/stdout into log4j > >>>Date: Mon, 12 Mar 2001 18:10:37 -0500 > >>> > >>>It doesn't. I haven't worried about it, since log4j doesn't > contain any > >>>bugs and therefore it would never happen... :) > >>> > >>>Probably the best way to handle it is to add a > >>>LogLog.setPrintStream(PrintStream) method, so you can do > something like: > >>> > >>>// remember STDERR > >>>PrintStream se = System.err; > >>> > >>>// 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)); > >>> > >>>// prevent infinate recursion in LogLog > >>>LogLog.setPrintStream(se); > >>> > >>> > >>>I can't think of any other way to do it in the current version besides > >>>getting extremely kludgey by checking the stack to see if it's > being called > >>>from LogLog and logging out the the "real" STDERR then in the > >>>LoggingOutputStream. It can be done on the theory that LogLog > wouldn't be > >>>called very often, but still... > >>> > >>>-Jim Moore > >>> > >>> > >>>-----Original Message----- > >>>From: Ceki Gülcü [mailto:[EMAIL PROTECTED]] > >>>Sent: Monday, March 12, 2001 5:15 PM > >>>To: LOG4J Users Mailing List > >>>Subject: RE: diverting System.stderr/stdout into log4j > >>> > >>> > >>>Jim, Joseph, > >>> > >>>Here is a link containing Jim's code: > >>> > >>>http://marc.theaimsgroup.com/?l=log4j-user&m=98097669218571&w=2 > >>> > >>>How does this code handle the infinite recursion problem mentioned by > >>>Joseph? Ceki > >>> > >>>At 17:03 12.03.2001 -0500, Jim Moore wrote: > >>>>Go to the mailing list archives (theAimsGroup.com is the > best) and search > >>>>for the thread with the subject of "Capturing System.err" > >>>> > >>>>-Jim Moore > >>>>"I think so, Brain; but if we gave peas a chance, won't the > lima beans get > >>>>jealous?" - Pinky > >>>> > >>>> > >>>>-----Original Message----- > >>>>From: Joseph Panico [mailto:[EMAIL PROTECTED]] > >>>>Sent: Monday, March 12, 2001 4:43 PM > >>>>To: [EMAIL PROTECTED] > >>>>Subject: diverting System.stderr/stdout into log4j > >>>> > >>>> > >>>>Folks, > >>>> > >>>>We use a number of third-party packages that do > stderr.print... at various > >>>>random places in their code. I'm finding it quite useful to > divert these > >>>>messages into our log4j heirarchy. I do this by replacing > stderr/stdout > >>>with > >>>> > >>>>my own PrintStreams that log the lines to a special log4j > Category-- as > >>>>suggested on this list a while back. The only > fly-in-the-ointment with this > >>> > >>>>scheme is LogLog. If there is a problem with log4j such that > it cannot log > >>>>for some reason, then log4j internals use LogLog to attempt > to print an > >>>>error message. This obviously leads to an infinite recursion. > Has anyone > >>>>else been bothered by this? Would it make sense to add > interface to LogLog > >>>>which would set the PrintStream it uses to log its error messages to? > >>>> > >>>>thanks for any ideas > >>>> > >>>>joe --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]