You are viewing a plain text version of this content. The canonical link for it is here.
Posted to log4j-dev@logging.apache.org by ca...@apache.org on 2007/02/21 22:38:44 UTC

svn commit: r510242 - in /logging/log4j/trunk: src/java/org/apache/log4j/spi/ tests/src/java/org/apache/log4j/spi/

Author: carnold
Date: Wed Feb 21 13:38:44 2007
New Revision: 510242

URL: http://svn.apache.org/viewvc?view=rev&rev=510242
Log:
Bug 41219: Stacktraces of exceptions disappear occassionally

Added:
    logging/log4j/trunk/src/java/org/apache/log4j/spi/NullWriter.java
    logging/log4j/trunk/src/java/org/apache/log4j/spi/VectorWriter.java
Modified:
    logging/log4j/trunk/src/java/org/apache/log4j/spi/ThrowableInformation.java
    logging/log4j/trunk/tests/src/java/org/apache/log4j/spi/ThrowableInformationTest.java

Added: logging/log4j/trunk/src/java/org/apache/log4j/spi/NullWriter.java
URL: http://svn.apache.org/viewvc/logging/log4j/trunk/src/java/org/apache/log4j/spi/NullWriter.java?view=auto&rev=510242
==============================================================================
--- logging/log4j/trunk/src/java/org/apache/log4j/spi/NullWriter.java (added)
+++ logging/log4j/trunk/src/java/org/apache/log4j/spi/NullWriter.java Wed Feb 21 13:38:44 2007
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j.spi;
+import java.io.Writer;
+
+/**
+  * NullWriter is an obsolete class provided only for
+  *  binary compatibility with earlier versions of log4j and should not be used.
+  *
+  * @deprecated
+  */
+class NullWriter extends Writer {
+
+  public void close() {
+    // blank
+  }
+
+  public void flush() {
+    // blank
+  }
+
+  public void write(char[] cbuf, int off, int len) {
+    // blank
+  }
+}

Modified: logging/log4j/trunk/src/java/org/apache/log4j/spi/ThrowableInformation.java
URL: http://svn.apache.org/viewvc/logging/log4j/trunk/src/java/org/apache/log4j/spi/ThrowableInformation.java?view=diff&rev=510242&r1=510241&r2=510242
==============================================================================
--- logging/log4j/trunk/src/java/org/apache/log4j/spi/ThrowableInformation.java (original)
+++ logging/log4j/trunk/src/java/org/apache/log4j/spi/ThrowableInformation.java Wed Feb 21 13:38:44 2007
@@ -16,14 +16,16 @@
 
 package org.apache.log4j.spi;
 
-import java.io.PrintWriter;
-import java.io.Writer;
+import org.apache.log4j.helpers.PlatformInfo;
 
+import java.io.IOException;
+import java.io.LineNumberReader;
+import java.io.PrintWriter;
+import java.io.StringReader;
+import java.io.StringWriter;
 import java.lang.reflect.Method;
-
-import java.util.Vector;
-
-import org.apache.log4j.helpers.PlatformInfo;
+import java.util.ArrayList;
+import java.util.List;
 
 
 /**
@@ -45,9 +47,10 @@
 
   public ThrowableInformation(final Throwable throwable) {
     this.throwable = throwable;
-    VectorWriter vw = new VectorWriter();
-    extractStringRep(throwable, vw);
-    rep = vw.toStringArray();
+    ArrayList lines = new ArrayList();
+    extractStringRep(throwable, lines);
+    rep = new String[lines.size()];
+    lines.toArray(rep);
   }
 
   public ThrowableInformation(String[] rep) {
@@ -63,8 +66,27 @@
      return throwable;
   }
 
-  public void extractStringRep(Throwable t, VectorWriter vw) {
-    t.printStackTrace(vw);
+    /**
+     * Extract string representation of throwable.
+     * @param t throwable, may not be null.
+     * @param lines list to receive stack trace, may not be null.
+     */
+  private static void extractStringRep(final Throwable t, final List lines) {
+      StringWriter sw = new StringWriter();
+      PrintWriter pw = new PrintWriter(sw);
+      t.printStackTrace(pw);
+      pw.flush();
+      LineNumberReader reader = new LineNumberReader(
+              new StringReader(sw.toString()));
+      try {
+        String line = reader.readLine();
+        while(line != null) {
+          lines.add(line);
+          line = reader.readLine();
+        }
+      } catch(IOException ex) {
+          lines.add(ex.toString());
+      }
 
     // Check if the Throwable t has a nested Throwable. If so, invoke
     // extractStringRep recursively.
@@ -95,8 +117,8 @@
         Throwable nextT =
           (Throwable) nextThrowableMethod.invoke(t, new Object[0]);
         if (nextT != null) {
-          vw.print("Root cause follows.");
-          extractStringRep(nextT, vw);
+          lines.add("Root cause follows.");
+          extractStringRep(nextT, lines);
         }
       }
     } catch (Exception e) {
@@ -124,11 +146,7 @@
     ThrowableInformation r = (ThrowableInformation) o;
 
     if (rep == null) {
-      if (r.rep != null) {
-        return false;
-      } else {
-        return true;
-      }
+      return (r.rep == null);
     }
 
     // at this point we know that both rep and r.rep are non-null.
@@ -144,92 +162,5 @@
     }
 
     return true;
-  }
-}
-
-
-/**
- * VectorWriter is a seemingly trivial implemtantion of PrintWriter. The
- * throwable instance that we are trying to represnt is asked to print itself to
- * a VectorWriter.
- *
- * By our design choice, r string representation of the throwable does not
- * contain any line separators. It follows that println() methods of
- * VectorWriter ignore the 'ln' part.
- */
-class VectorWriter extends PrintWriter {
-  private Vector v;
-
-  VectorWriter() {
-    super(new NullWriter());
-    v = new Vector();
-  }
-
-  public void print(Object o) {
-    v.addElement(o.toString());
-  }
-
-  public void print(char[] chars) {
-    v.addElement(new String(chars));
-  }
-
-  public void print(String s) {
-    v.addElement(s);
-  }
-
-  public void println(Object o) {
-      v.addElement(String.valueOf(o));
-  }
-
-  // JDK 1.1.x apprenly uses this form of println while in
-  // printStackTrace()
-  public void println(char[] chars) {
-    v.addElement(new String(chars));
-  }
-
-  public void println(String s) {
-    v.addElement(s);
-  }
-
-  public void write(char[] chars) {
-    v.addElement(new String(chars));
-  }
-
-  public void write(char[] chars, int off, int len) {
-    v.addElement(new String(chars, off, len));
-  }
-
-  public void write(String s, int off, int len) {
-    v.addElement(s.substring(off, off + len));
-  }
-
-  public void write(String s) {
-    v.addElement(s);
-  }
-
-  public String[] toStringArray() {
-    int len = v.size();
-    String[] sa = new String[len];
-
-    for (int i = 0; i < len; i++) {
-      sa[i] = (String) v.elementAt(i);
-    }
-
-    return sa;
-  }
-}
-
-
-class NullWriter extends Writer {
-  public void close() {
-    // blank
-  }
-
-  public void flush() {
-    // blank
-  }
-
-  public void write(char[] cbuf, int off, int len) {
-    // blank
   }
 }

Added: logging/log4j/trunk/src/java/org/apache/log4j/spi/VectorWriter.java
URL: http://svn.apache.org/viewvc/logging/log4j/trunk/src/java/org/apache/log4j/spi/VectorWriter.java?view=auto&rev=510242
==============================================================================
--- logging/log4j/trunk/src/java/org/apache/log4j/spi/VectorWriter.java (added)
+++ logging/log4j/trunk/src/java/org/apache/log4j/spi/VectorWriter.java Wed Feb 21 13:38:44 2007
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j.spi;
+
+import java.io.PrintWriter;
+import java.util.Vector;
+
+/**
+  * VectorWriter is an obsolete class provided only for
+  *  binary compatibility with earlier versions of log4j and should not be used.
+  *
+  * @deprecated
+  */
+class VectorWriter extends PrintWriter {
+
+  private Vector v;
+
+    /**
+     * @deprecated
+     */
+  VectorWriter() {
+    super(new NullWriter());
+    v = new Vector();
+  }
+
+  public void print(Object o) {
+    v.addElement(String.valueOf(o));
+  }
+
+  public void print(char[] chars) {
+    v.addElement(new String(chars));
+  }
+
+  public void print(String s) {
+    v.addElement(s);
+  }
+
+  public void println(Object o) {
+    v.addElement(String.valueOf(o));
+  }
+
+  // JDK 1.1.x apprenly uses this form of println while in
+  // printStackTrace()
+  public
+  void println(char[] chars) {
+    v.addElement(new String(chars));
+  }
+
+  public
+  void println(String s) {
+    v.addElement(s);
+  }
+
+  public void write(char[] chars) {
+    v.addElement(new String(chars));
+  }
+
+  public void write(char[] chars, int off, int len) {
+    v.addElement(new String(chars, off, len));
+  }
+
+  public void write(String s, int off, int len) {
+    v.addElement(s.substring(off, off+len));
+  }
+
+  public void write(String s) {
+     v.addElement(s);
+  }
+
+  public String[] toStringArray() {
+    int len = v.size();
+    String[] sa = new String[len];
+    for(int i = 0; i < len; i++) {
+      sa[i] = (String) v.elementAt(i);
+    }
+    return sa;
+  }
+
+}
+

Modified: logging/log4j/trunk/tests/src/java/org/apache/log4j/spi/ThrowableInformationTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/trunk/tests/src/java/org/apache/log4j/spi/ThrowableInformationTest.java?view=diff&rev=510242&r1=510241&r2=510242
==============================================================================
--- logging/log4j/trunk/tests/src/java/org/apache/log4j/spi/ThrowableInformationTest.java (original)
+++ logging/log4j/trunk/tests/src/java/org/apache/log4j/spi/ThrowableInformationTest.java Wed Feb 21 13:38:44 2007
@@ -18,6 +18,8 @@
 
 import junit.framework.TestCase;
 
+import java.io.PrintWriter;
+
 /**
  * 
  * @author Ceki G&uuml;lc&uuml;
@@ -44,19 +46,19 @@
   public void testEqualsObject() {
     Throwable e1 = new Exception("exeption 1");
     Throwable e2 = new Exception("exeption 2");
-    
+
     ThrowableInformation te1 = new ThrowableInformation(e1);
     ThrowableInformation te2 = new ThrowableInformation(e2);
-    
+
     assertEquals(te1, te1);
     assertEquals(te2, te2);
-    
+
     boolean eq1 = te1.equals(te2);
     assertEquals(false, eq1);
 
     boolean eq2 = te1.equals(null);
     assertEquals(false, eq2);
-    
+
     assertEquals(te1.hashCode(), te1.hashCode());
     assertEquals(te2.hashCode(), te2.hashCode());
   }
@@ -67,5 +69,257 @@
   {
     super(arg0);
   }
-  
+
+    /**
+     * Custom throwable that only calls methods
+     * overridden by VectorWriter in log4j 1.2.14 and earlier.
+     */
+    private static final class OverriddenThrowable extends Throwable {
+        /**
+         * Create new instance.
+         */
+        public OverriddenThrowable() {
+        }
+
+        /**
+         * Print stack trace.
+         *
+         * @param s print writer.
+         */
+        public void printStackTrace(final PrintWriter s) {
+            s.print((Object) "print(Object)");
+            s.print("print(char[])".toCharArray());
+            s.print("print(String)");
+            s.println((Object) "println(Object)");
+            s.println("println(char[])".toCharArray());
+            s.println("println(String)");
+            s.write("write(char[])".toCharArray());
+            s.write("write(char[], int, int)".toCharArray(), 2, 8);
+            s.write("write(String, int, int)", 2, 8);
+        }
+    }
+
+    /**
+     * Test capturing stack trace from a throwable that only uses the
+     * PrintWriter methods overridden in log4j 1.2.14 and earlier.
+     */
+    public void testOverriddenBehavior() {
+        ThrowableInformation ti = new ThrowableInformation(new OverriddenThrowable());
+        String[] rep = ti.getThrowableStrRep();
+        assertEquals(4, rep.length);
+        assertEquals("print(Object)print(char[])print(String)println(Object)", rep[0]);
+        assertEquals("println(char[])", rep[1]);
+        assertEquals("println(String)", rep[2]);
+        assertEquals("write(char[])ite(charite(Stri", rep[3]);
+    }
+
+    /**
+     * Custom throwable that calls methods
+     * not overridden by VectorWriter in log4j 1.2.14 and earlier.
+     */
+    private static final class NotOverriddenThrowable extends Throwable {
+        /**
+         * Create new instance.
+         */
+        public NotOverriddenThrowable() {
+        }
+
+        /**
+         * Print stack trace.
+         *
+         * @param s print writer.
+         */
+        public void printStackTrace(final PrintWriter s) {
+            s.print(true);
+            s.print('a');
+            s.print(1);
+            s.print(2L);
+            s.print(Float.MAX_VALUE);
+            s.print(Double.MIN_VALUE);
+            s.println(true);
+            s.println('a');
+            s.println(1);
+            s.println(2L);
+            s.println(Float.MAX_VALUE);
+            s.println(Double.MIN_VALUE);
+            s.write('C');
+        }
+    }
+
+    /**
+     * Test capturing stack trace from a throwable that uses the
+     * PrintWriter methods not overridden in log4j 1.2.14 and earlier.
+     */
+    public void testNotOverriddenBehavior() {
+        ThrowableInformation ti = new ThrowableInformation(new NotOverriddenThrowable());
+        String[] rep = ti.getThrowableStrRep();
+        assertEquals(7, rep.length);
+        StringBuffer buf = new StringBuffer(String.valueOf(true));
+        buf.append('a');
+        buf.append(String.valueOf(1));
+        buf.append(String.valueOf(2L));
+        buf.append(String.valueOf(Float.MAX_VALUE));
+        buf.append(String.valueOf(Double.MIN_VALUE));
+        buf.append(String.valueOf(true));
+        assertEquals(buf.toString(), rep[0]);
+        assertEquals("a", rep[1]);
+        assertEquals(String.valueOf(1), rep[2]);
+        assertEquals(String.valueOf(2L), rep[3]);
+        assertEquals(String.valueOf(Float.MAX_VALUE), rep[4]);
+        assertEquals(String.valueOf(Double.MIN_VALUE), rep[5]);
+        assertEquals("C", rep[6]);
+    }
+
+    /**
+     * Custom throwable that calls methods of VectorWriter
+     * with null.
+     */
+    private static final class NullThrowable extends Throwable {
+        /**
+         * Create new instance.
+         */
+        public NullThrowable() {
+        }
+
+        /**
+         * Print stack trace.
+         *
+         * @param s print writer.
+         */
+        public void printStackTrace(final PrintWriter s) {
+            s.print((Object) null);
+            s.print((String) null);
+            s.println((Object) null);
+            s.println((String) null);
+        }
+    }
+
+    /**
+     * Test capturing stack trace from a throwable that passes
+     * null to PrintWriter methods.
+     */
+
+    public void testNull() {
+        ThrowableInformation ti = new ThrowableInformation(new NullThrowable());
+        String[] rep = ti.getThrowableStrRep();
+        assertEquals(2, rep.length);
+        String nullStr = String.valueOf((Object) null);
+        assertEquals(nullStr + nullStr + nullStr, rep[0]);
+        assertEquals(nullStr, rep[1]);
+    }
+
+    /**
+     * Custom throwable that does nothing in printStackTrace.
+     */
+    private static final class EmptyThrowable extends Throwable {
+        /**
+         * Create new instance.
+         */
+        public EmptyThrowable() {
+        }
+
+        /**
+         * Print stack trace.
+         *
+         * @param s print writer.
+         */
+        public void printStackTrace(final PrintWriter s) {
+        }
+    }
+
+    /**
+     * Test capturing stack trace from a throwable that
+     * does nothing on a call to printStackTrace.
+     */
+
+    public void testEmpty() {
+        ThrowableInformation ti = new ThrowableInformation(new EmptyThrowable());
+        String[] rep = ti.getThrowableStrRep();
+        assertEquals(0, rep.length);
+    }
+
+    /**
+     * Custom throwable that emits a specified string in printStackTrace.
+     */
+    private static final class StringThrowable extends Throwable {
+        /**
+         * Stack trace.
+         */
+        private final String stackTrace;
+        /**
+         * Create new instance.
+         * @param trace stack trace.
+         */
+        public StringThrowable(final String trace) {
+            stackTrace = trace;
+        }
+
+        /**
+         * Print stack trace.
+         *
+         * @param s print writer.
+         */
+        public void printStackTrace(final PrintWriter s) {
+            s.print(stackTrace);
+        }
+    }
+
+    /**
+     * Test capturing stack trace from throwable that just has a line feed.
+     */
+    public void testLineFeed() {
+        ThrowableInformation ti = new ThrowableInformation(new StringThrowable("\n"));
+        String[] rep = ti.getThrowableStrRep();
+        assertEquals(1, rep.length);
+        assertEquals("", rep[0]);
+    }
+
+    /**
+     * Test capturing stack trace from throwable that just has a carriage return.
+     */
+    public void testCarriageReturn() {
+        ThrowableInformation ti = new ThrowableInformation(new StringThrowable("\r"));
+        String[] rep = ti.getThrowableStrRep();
+        assertEquals(1, rep.length);
+        assertEquals("", rep[0]);
+    }
+
+    /**
+     * Test parsing of line breaks.
+     */
+    public void testParsing() {
+        ThrowableInformation ti = new ThrowableInformation(
+                new StringThrowable("Line1\rLine2\nLine3\r\nLine4\n\rLine6"));
+        String[] rep = ti.getThrowableStrRep();
+        assertEquals(6, rep.length);
+        assertEquals("Line1", rep[0]);
+        assertEquals("Line2", rep[1]);
+        assertEquals("Line3", rep[2]);
+        assertEquals("Line4", rep[3]);
+        assertEquals("", rep[4]);
+        assertEquals("Line6", rep[5]);
+    }
+
+    /**
+     * Test capturing stack trace from throwable that a line feed followed by blank.
+     */
+    public void testLineFeedBlank() {
+        ThrowableInformation ti = new ThrowableInformation(new StringThrowable("\n "));
+        String[] rep = ti.getThrowableStrRep();
+        assertEquals(2, rep.length);
+        assertEquals("", rep[0]);
+        assertEquals(" ", rep[1]);
+    }
+
+    /**
+     * Test that getThrowable returns the throwable provided to the constructor.
+     * @deprecated
+     */
+    public void testGetThrowable() {
+        Throwable t = new StringThrowable("Hello, World");
+        ThrowableInformation ti = new ThrowableInformation(t);
+        assertSame(t, ti.getThrowable());
+    }
+
+
  }



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