[logback-dev] svn commit: r1792 - in logback/trunk: logback-classic/src/main/java/ch/qos/logback/classic/pattern logback-classic/src/test/java/ch/qos/logback/classic/pattern logback-classic/src/test/java/ch/qos/logback/classic/pattern/lru logback-core/src/main/java/ch/qos/logback/core/helpers logback-core/src/test/java/ch/qos/logback/core/helpers

noreply.ceki at qos.ch noreply.ceki at qos.ch
Wed Sep 3 22:28:08 CEST 2008


Author: ceki
Date: Wed Sep  3 22:28:08 2008
New Revision: 1792

Added:
   logback/trunk/logback-core/src/main/java/ch/qos/logback/core/helpers/PackageInfo.java
      - copied, changed from r1790, /logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/PackageInfo.java
   logback/trunk/logback-core/src/main/java/ch/qos/logback/core/helpers/StackTraceElementProxy.java
   logback/trunk/logback-core/src/main/java/ch/qos/logback/core/helpers/ThrowableDataPoint.java
   logback/trunk/logback-core/src/main/java/ch/qos/logback/core/helpers/ThrowableToDataPointArray.java
   logback/trunk/logback-core/src/test/java/ch/qos/logback/core/helpers/
   logback/trunk/logback-core/src/test/java/ch/qos/logback/core/helpers/ThrowableToDataPointTest.java
Removed:
   logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/PackageInfo.java
Modified:
   logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/LRUCache.java
   logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/ThrowableInformationConverter.java
   logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/Util.java
   logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/LRUCacheTest.java
   logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/Simulator.java
   logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/UtilTest.java
   logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/lru/T_LRUCache.java
   logback/trunk/logback-core/src/main/java/ch/qos/logback/core/helpers/ThrowableToStringArray.java

Log:
LBGENERAL-23

Reworking Throwable to string conversion. Instead of simply converting StackTraceElement 
(STE) array into just strings, we convert them to a little more sophisticated objects,
namely ThrowableDataPoints which support PackageInformation.

This is ongoing work, unit test may not pass. 

Modified: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/LRUCache.java
==============================================================================
--- logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/LRUCache.java	(original)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/LRUCache.java	Wed Sep  3 22:28:08 2008
@@ -40,6 +40,8 @@
   }
   
   List<K> keyList() {
-    return new ArrayList<K>(keySet());
+    ArrayList<K> al = new ArrayList<K>();
+    al.addAll(keySet());
+    return al;
   }
 }

Modified: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/ThrowableInformationConverter.java
==============================================================================
--- logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/ThrowableInformationConverter.java	(original)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/ThrowableInformationConverter.java	Wed Sep  3 22:28:08 2008
@@ -98,6 +98,7 @@
     int length = (lengthOption > stringRep.length) ? stringRep.length
         : lengthOption;
 
+    // an evaluator match will cause stack printing to be skipped 
     if (evaluatorList != null) {
       boolean printStack = true;
       for (int i = 0; i < evaluatorList.size(); i++) {

Modified: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/Util.java
==============================================================================
--- logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/Util.java	(original)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/Util.java	Wed Sep  3 22:28:08 2008
@@ -15,6 +15,8 @@
 
 import org.slf4j.Marker;
 
+import ch.qos.logback.core.helpers.PackageInfo;
+
 /**
  * 
  * @author James Strachan
@@ -77,12 +79,14 @@
    * Uses the context class path or the current global class loader to deduce
    * the file that the given class name comes from
    */
-  static String getJarNameOfClass(String className) {
+  static String getJarNameOfClass0(String className) {
     try {
       Class type = findClass(className);
       if (type != null) {
         URL resource = type.getClassLoader().getResource(
             type.getName().replace('.', '/') + ".class");
+         
+         
         // "jar:file:/C:/java/../repo/groupId/artifact/1.3/artifact-1.3.jar!/com/some/package/Some.class
         if (resource != null) {
           String text = resource.toString();
@@ -107,7 +111,41 @@
     }
     return "na";
   }
-
+  
+  static String getJarNameOfClass1(String className) {
+    try {
+      Class type = findClass(className);
+      if (type != null) {
+        
+        
+        // file:/C:/java/maven-2.0.8/repo/com/icegreen/greenmail/1.3/greenmail-1.3.jar
+        URL resource = type.getProtectionDomain().getCodeSource().getLocation();
+        if (resource != null) {
+          String text = resource.toString();
+            // now lets remove all but the file name
+          int  idx = text.lastIndexOf('/');
+          if (idx > 0) {
+            text = text.substring(idx + 1);
+          }
+          idx = text.lastIndexOf('\\');
+          if (idx > 0) {
+            text = text.substring(idx + 1);
+          }
+           return text;
+        }
+      }
+    } catch (Exception e) {
+      // ignore
+    }
+    return "na";
+  }
+  
+  
+  
+  static String getJarNameOfClass(String className) {
+    return getJarNameOfClass1(className);
+  }
+  
   static private Class findClass(String className) {
     try {
       return Thread.currentThread().getContextClassLoader()

Modified: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/LRUCacheTest.java
==============================================================================
--- logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/LRUCacheTest.java	(original)
+++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/LRUCacheTest.java	Wed Sep  3 22:28:08 2008
@@ -5,8 +5,6 @@
 import java.util.LinkedList;
 import java.util.List;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
 
@@ -15,17 +13,9 @@
 
 public class LRUCacheTest {
 
-  @Before
-  public void setUp() throws Exception {
-  }
-
-  @After
-  public void tearDown() throws Exception {
-
-  }
-
   @Test
   public void smoke() {
+    
     LRUCache<String, String> cache = new LRUCache<String, String>(2);
     cache.put("a", "a");
     cache.put("b", "b");
@@ -38,34 +28,84 @@
 
   @Test
   public void typicalScenarioTest() {
-    int simulationLen = 1000 * 20;
-    int cacheSize = 500;
-    int worldSize = 10000;
+    int simulationLen = 1000 * 10;
+    int cacheSize = 100;
+    int worldSize = 1000;
     doScenario(simulationLen, cacheSize, worldSize);
   }
 
   @Test
   public void scenarioCoverageTest() {
-    int simulationLen = 1000 * 20;
-    int[] cacheSizes = new int[] {1,5,10,100,1000,5000,10000};
-    int[] worldSizes = new int[] {1,10,100,1000,20000};
+    int simulationLen = 1000 * 10;
+
+    int[] cacheSizes = new int[] { 1, 10, 100};
+    // tests with large worldSizes are slow because with a large
+    // world size the probability of a cache miss is high.
+    int[] worldSizes = new int[] { 1, 10, 100 };
+
     for (int i = 0; i < cacheSizes.length; i++) {
       for (int j = 0; j < worldSizes.length; j++) {
-        System.out.println("cacheSize="+cacheSizes[i]+", worldSize="+worldSizes[j]);
         doScenario(simulationLen, cacheSizes[i], worldSizes[j]);
       }
     }
   }
 
-  void doScenario(int simulationLen, int chacheSize, int worldSize) {
-    int cacheSize = 500;
+  void doScenario(int simulationLen, int cacheSize, int worldSize) {
     int get2PutRatio = 10;
-
-    Simulator simulator = new Simulator(worldSize, get2PutRatio);
+    Simulator simulator = new Simulator(worldSize, get2PutRatio, false);
     List<Event> scenario = simulator.generateScenario(simulationLen);
     LRUCache<String, String> lruCache = new LRUCache<String, String>(cacheSize);
     T_LRUCache<String> tlruCache = new T_LRUCache<String>(cacheSize);
+    long start = System.nanoTime();
     simulator.simulate(scenario, lruCache, tlruCache);
-    assertEquals(tlruCache.ketList(), lruCache.keyList());
+    //assertEquals(tlruCache.keyList(), lruCache.keyList());
+    long end = System.nanoTime();
+    System.out.println("cacheSize=" + cacheSize + ", worldSize=" + worldSize
+        + ", elapsed time=" + ((end - start) / (1000 * 1000)) + " in millis");
+  }
+  
+  
+  
+  @Test
+  @Ignore // slow test that is known to pass
+  public void multiThreadedScenario() throws InterruptedException {
+    int cacheSize = 100;
+    int worldSize = cacheSize*2;
+    LRUCache<String, String> lruCache = new LRUCache<String, String>(cacheSize);
+    T_LRUCache<String> tlruCache = new T_LRUCache<String>(cacheSize);
+    SimulatorRunnable[] simulatorArray = new SimulatorRunnable[5];
+    for(int i = 0; i < simulatorArray.length; i++) {
+      simulatorArray[i] = new SimulatorRunnable(lruCache, tlruCache, worldSize);
+    }
+    for(int i = 0; i < simulatorArray.length; i++) {
+      simulatorArray[i].start();
+    }
+    for(int i = 0; i < simulatorArray.length; i++) {
+      simulatorArray[i].join();
+    }
+    assertEquals(tlruCache.keyList(), lruCache.keyList());
+  }
+  
+  private class SimulatorRunnable extends Thread {
+
+    LRUCache<String, String> lruCache;
+    T_LRUCache<String> tlruCache;
+    int worldSize;
+    
+    SimulatorRunnable(LRUCache<String, String> lruCache, T_LRUCache<String> tlruCache, int worldSize) {
+      this.lruCache = lruCache;
+      this.tlruCache = tlruCache;
+      this.worldSize = worldSize;
+    }
+    
+    public void run() {
+      int get2PutRatio = 10;
+      int simulationLen = 1000*50;
+      Simulator simulator = new Simulator(worldSize, get2PutRatio, true);
+      List<Event> scenario = simulator.generateScenario(simulationLen);
+      simulator.simulate(scenario, lruCache, tlruCache);
+      System.out.println("done");
+    }
   }
+  
 }

Modified: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/Simulator.java
==============================================================================
--- logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/Simulator.java	(original)
+++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/Simulator.java	Wed Sep  3 22:28:08 2008
@@ -11,28 +11,29 @@
 
 public class Simulator {
 
-  
   Random random;
-  
+
   int worldSize;
   int get2PutRatio;
-  
-  public Simulator(int worldSize, int get2PutRatio) {
+  boolean multiThreaded;
+
+  public Simulator(int worldSize, int get2PutRatio, boolean multiThreaded) {
     this.worldSize = worldSize;
     this.get2PutRatio = get2PutRatio;
     long seed = System.nanoTime();
-    System.out.println("seed is "+seed);
+    // System.out.println("seed is "+seed);
     random = new Random(seed);
+    this.multiThreaded = multiThreaded;
   }
-  
+
   public List<Event> generateScenario(int len) {
     List<Event> scenario = new ArrayList<Event>();
-    
-    for(int i = 0; i < len; i++) {
-      
+
+    for (int i = 0; i < len; i++) {
+
       int r = random.nextInt(get2PutRatio);
       boolean put = false;
-      if(r == 0) {
+      if (r == 0) {
         put = true;
       }
       r = random.nextInt(worldSize);
@@ -41,30 +42,40 @@
     }
     return scenario;
   }
-  
-  public void simulate(List<Event> scenario, LRUCache<String, String> lruCache, T_LRUCache<String> tlruCache) {
-    for(Event<String> e: scenario) {
-      if(e.put) {
+
+  public void simulate(List<Event> scenario, LRUCache<String, String> lruCache,
+      T_LRUCache<String> tlruCache) {
+    for (Event<String> e : scenario) {
+      if (e.put) {
         lruCache.put(e.k, e.k);
         tlruCache.put(e.k);
       } else {
+        @SuppressWarnings("unused")
         String r0 = lruCache.get(e.k);
+        @SuppressWarnings("unused")
         String r1 = tlruCache.get(e.k);
-        if(r0 != null) {
-          assertEquals(r0, e.k);
+        if (!multiThreaded) {
+          // if the simulation is used in a multi-threaded
+          // context, then the state of lruCache may be different than
+          // that of tlruCache. In single threaded mode, they should
+          // return the same values all the time
+          if (r0 != null) {
+            assertEquals(r0, e.k);
+          }
+          assertEquals(r0, r1);
         }
-        assertEquals(r0, r1);
       }
     }
   }
-  
-//  void compareAndDumpIfDifferent(LRUCache<String, String> lruCache, T_LRUCache<String> tlruCache) {
-//    lruCache.dump();
-//    tlruCache.dump();
-//    if(!lruCache.keyList().equals(tlruCache.ketList())) {
-//      lruCache.dump();
-//      tlruCache.dump();
-//      throw new AssertionFailedError("s");
-//    }
-//  }
+
+  // void compareAndDumpIfDifferent(LRUCache<String, String> lruCache,
+  // T_LRUCache<String> tlruCache) {
+  // lruCache.dump();
+  // tlruCache.dump();
+  // if(!lruCache.keyList().equals(tlruCache.ketList())) {
+  // lruCache.dump();
+  // tlruCache.dump();
+  // throw new AssertionFailedError("s");
+  // }
+  // }
 }

Modified: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/UtilTest.java
==============================================================================
--- logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/UtilTest.java	(original)
+++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/UtilTest.java	Wed Sep  3 22:28:08 2008
@@ -4,9 +4,10 @@
 
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 
+import ch.qos.logback.core.helpers.PackageInfo;
+
 import com.icegreen.greenmail.util.GreenMail;
 import com.icegreen.greenmail.util.ServerSetup;
 
@@ -37,7 +38,7 @@
         PackageInfo pi = Util.getPackageInfo(className);
         System.out.println("  at " + className + "." + ste.getMethodName()
             + "(" + ste.getFileName() + ":" + ste.getLineNumber() + ") ["
-            + pi.jarName + ":" + pi.version + "]");
+            + pi.getJarName() + ":" + pi.getVersion() + "]");
       }
     }
   }
@@ -68,17 +69,16 @@
   }
 
   @Test
-  @Ignore
   public void perfTest() {
     int len = 1000;
     loop(len, false);
     double d0 = loop(len, false);
 
-    System.out.println("false " + d0);
+    System.out.println("ve=false " + d0);
 
     loop(len, true);
     double d1 = loop(len, true);
 
-    System.out.println("false " + d1);
+    System.out.println("ve=true " + d1);
   }
 }

Modified: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/lru/T_LRUCache.java
==============================================================================
--- logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/lru/T_LRUCache.java	(original)
+++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/lru/T_LRUCache.java	Wed Sep  3 22:28:08 2008
@@ -31,7 +31,7 @@
   }
 
   @SuppressWarnings("unchecked")
-  public void put(K k) {
+  synchronized public void put(K k) {
     sequenceNumber++;
     T_Entry<K> te = getEntry(k);
     if (te != null) {
@@ -47,7 +47,7 @@
   }
 
   @SuppressWarnings("unchecked")
-  public K get(K k) {
+  synchronized public K get(K k) {
     T_Entry<K> te = getEntry(k);
     if (te == null) {
       return null;
@@ -58,7 +58,7 @@
     }
   }
 
-  public List<K> ketList() {
+  synchronized public List<K> keyList() {
     List<K> keyList = new ArrayList<K>();
     for (T_Entry<K> e : cacheList) {
       keyList.add(e.k);
@@ -86,3 +86,4 @@
   }
 
 }
+

Copied: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/helpers/PackageInfo.java (from r1790, /logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/PackageInfo.java)
==============================================================================
--- /logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/PackageInfo.java	(original)
+++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/helpers/PackageInfo.java	Wed Sep  3 22:28:08 2008
@@ -1,13 +1,29 @@
-package ch.qos.logback.classic.pattern;
+/**
+ * Logback: the generic, reliable, fast and flexible logging framework.
+ * 
+ * Copyright (C) 2000-2008, QOS.ch
+ * 
+ * This library is free software, you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation.
+ */
+package ch.qos.logback.core.helpers;
 
 public class PackageInfo {
 
-  
   String jarName;
   String version;
   
-  PackageInfo(String jarName, String version) {
+  public PackageInfo(String jarName, String version) {
     this.jarName = jarName;
     this.version = version;
   }
+
+  public String getJarName() {
+    return jarName;
+  }
+
+  public String getVersion() {
+    return version;
+  }
 }

Added: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/helpers/StackTraceElementProxy.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/helpers/StackTraceElementProxy.java	Wed Sep  3 22:28:08 2008
@@ -0,0 +1,25 @@
+package ch.qos.logback.core.helpers;
+
+public class StackTraceElementProxy {
+
+  final StackTraceElement ste;
+  private String steAsString;
+  private PackageInfo pi;
+  
+  StackTraceElementProxy(StackTraceElement ste) {
+    this.ste = ste;
+  }
+  
+  public String getSTEAsString() {
+    if(steAsString == null) {
+      steAsString = "\tat "+ste.toString();
+    }
+    return steAsString;
+  }
+  
+  public PackageInfo getPI() {
+    // compute pi from ste
+    return pi;
+  }
+  
+}

Added: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/helpers/ThrowableDataPoint.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/helpers/ThrowableDataPoint.java	Wed Sep  3 22:28:08 2008
@@ -0,0 +1,45 @@
+/**
+ * Logback: the generic, reliable, fast and flexible logging framework.
+ * 
+ * Copyright (C) 2000-2008, QOS.ch
+ * 
+ * This library is free software, you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation.
+ */
+package ch.qos.logback.core.helpers;
+
+public class ThrowableDataPoint {
+
+  enum ThrowableDataPointType {
+    RAW, STEP;
+  }
+
+  String rawString;
+  StackTraceElementProxy step;
+  final ThrowableDataPointType type;
+
+  ThrowableDataPoint(String rawString) {
+    this.rawString = rawString;
+    this.type = ThrowableDataPointType.RAW;
+  }
+
+  ThrowableDataPoint(StackTraceElement ste) {
+    this.step = new StackTraceElementProxy(ste);
+    this.type = ThrowableDataPointType.STEP;
+  }
+
+  public ThrowableDataPointType getType() {
+    return type;
+  }
+  
+  @Override
+  public String toString() {
+    switch(type) {
+    case RAW: return rawString;
+    case STEP: return step.getSTEAsString();
+    }
+    throw new IllegalStateException("Unreachable code");
+  }
+
+}

Added: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/helpers/ThrowableToDataPointArray.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/helpers/ThrowableToDataPointArray.java	Wed Sep  3 22:28:08 2008
@@ -0,0 +1,87 @@
+/**
+ * Logback: the generic, reliable, fast and flexible logging framework.
+ * 
+ * Copyright (C) 2000-2008, QOS.ch
+ * 
+ * This library is free software, you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation.
+ */
+
+package ch.qos.logback.core.helpers;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import ch.qos.logback.core.CoreGlobal;
+
+public class ThrowableToDataPointArray {
+
+  static final ThrowableDataPoint[] TEMPLATE_ARRAY = new ThrowableDataPoint[0];
+
+  public static ThrowableDataPoint[] convert(Throwable t) {
+    List<ThrowableDataPoint> tdpList = new LinkedList<ThrowableDataPoint>();
+    extract(tdpList, t, null);
+    return tdpList.toArray(TEMPLATE_ARRAY);
+  }
+
+  private static void extract(List<ThrowableDataPoint> tdpList, Throwable t,
+      StackTraceElement[] parentSTE) {
+    StackTraceElement[] ste = t.getStackTrace();
+    final int numberOfcommonFrames = findNumberOfCommonFrames(ste, parentSTE);
+
+    tdpList.add(firstLineToDataPoint(t, parentSTE));
+    for (int i = 0; i < (ste.length - numberOfcommonFrames); i++) {
+      tdpList.add(new ThrowableDataPoint(ste[i]));
+    }
+    
+    //   buf.append("\tat ");
+    
+    
+    if (numberOfcommonFrames != 0) {
+      tdpList.add(new ThrowableDataPoint("\t... "+numberOfcommonFrames
+          + " common frames omitted"));
+    }
+
+    Throwable cause = t.getCause();
+    if (cause != null) {
+      extract(tdpList, cause, ste);
+    }
+  }
+
+  private static ThrowableDataPoint firstLineToDataPoint(Throwable t,
+      StackTraceElement[] parentSTE) {
+    String prefix = "";
+    if (parentSTE != null) {
+      prefix = CoreGlobal.CAUSED_BY;
+    }
+
+    String result = prefix + t.getClass().getName();
+    if (t.getMessage() != null) {
+      result += ": " + t.getMessage();
+    }
+    return new ThrowableDataPoint(result);
+  }
+
+  private static int findNumberOfCommonFrames(StackTraceElement[] ste,
+      StackTraceElement[] parentSTE) {
+    if (parentSTE == null) {
+      return 0;
+    }
+
+    int steIndex = ste.length - 1;
+    int parentIndex = parentSTE.length - 1;
+    int count = 0;
+    while (steIndex >= 0 && parentIndex >= 0) {
+      if (ste[steIndex].equals(parentSTE[parentIndex])) {
+        count++;
+      } else {
+        break;
+      }
+      steIndex--;
+      parentIndex--;
+    }
+    return count;
+  }
+
+}

Modified: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/helpers/ThrowableToStringArray.java
==============================================================================
--- logback/trunk/logback-core/src/main/java/ch/qos/logback/core/helpers/ThrowableToStringArray.java	(original)
+++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/helpers/ThrowableToStringArray.java	Wed Sep  3 22:28:08 2008
@@ -18,31 +18,22 @@
     String[] result;
 
     StackTraceElement[] ste = t.getStackTrace();
-    final int commonFrames = findCommonFrames(ste, parentSTE);
+    final int numberOfcommonFrames = findNumberOfCommonFrames(ste, parentSTE);
 
     final String[] firstArray;
-    if (commonFrames == 0) {
+    if (numberOfcommonFrames == 0) {
       firstArray = new String[ste.length + 1];
     } else {
-      firstArray = new String[ste.length - commonFrames + 2];
+      firstArray = new String[ste.length - numberOfcommonFrames + 2];
     }
 
-    String prefix = "";
-    if (parentSTE != null) {
-      prefix = CoreGlobal.CAUSED_BY;
-    }
-
-    firstArray[0] = prefix + t.getClass().getName();
-    if (t.getMessage() != null) {
-      firstArray[0] += ": " + t.getMessage();
-    }
-
-    for (int i = 0; i < (ste.length - commonFrames); i++) {
+    firstArray[0] = formatFirstLine(t, parentSTE);
+    for (int i = 0; i < (ste.length - numberOfcommonFrames); i++) {
       firstArray[i + 1] = ste[i].toString();
     }
 
-    if (commonFrames != 0) {
-      firstArray[firstArray.length - 1] = commonFrames
+    if (numberOfcommonFrames != 0) {
+      firstArray[firstArray.length - 1] = numberOfcommonFrames
           + " common frames omitted";
     }
 
@@ -60,7 +51,20 @@
     return result;
   }
   
-  private static int findCommonFrames(StackTraceElement[] ste,
+  private static String formatFirstLine(Throwable t, StackTraceElement[] parentSTE) {
+    String prefix = "";
+    if (parentSTE != null) {
+      prefix = CoreGlobal.CAUSED_BY;
+    }
+
+    String result = prefix + t.getClass().getName();
+    if (t.getMessage() != null) {
+      result += ": " + t.getMessage();
+    }
+    return result;
+  }
+  
+  private static int findNumberOfCommonFrames(StackTraceElement[] ste,
       StackTraceElement[] parentSTE) {
     if (parentSTE == null) {
       return 0;

Added: logback/trunk/logback-core/src/test/java/ch/qos/logback/core/helpers/ThrowableToDataPointTest.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-core/src/test/java/ch/qos/logback/core/helpers/ThrowableToDataPointTest.java	Wed Sep  3 22:28:08 2008
@@ -0,0 +1,81 @@
+package ch.qos.logback.core.helpers;
+
+import static org.junit.Assert.*;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import ch.qos.logback.core.Layout;
+
+public class ThrowableToDataPointTest {
+
+  StringWriter sw = new StringWriter();
+  PrintWriter pw = new PrintWriter(sw);
+
+  @Before
+  public void setUp() throws Exception {
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  public void verify(Throwable t) {
+    t.printStackTrace(pw);
+    
+    ThrowableDataPoint[] tdpArray = ThrowableToDataPointArray.convert(t);
+    StringBuilder sb = new StringBuilder();
+    for (ThrowableDataPoint tdp : tdpArray) {
+      sb.append(tdp.toString());
+      sb.append(Layout.LINE_SEP);
+    }
+    String expected = sw.toString();
+    String result = sb.toString().replace("common frames omitted", "more");
+    
+    assertEquals(expected, result);
+  }
+  
+  @Test
+  public void smoke() {
+    Exception e = new Exception("smoke");
+    verify(e);
+  }
+
+  @Test
+  public void nested() {
+    Exception w = null;
+    try {
+      someMethod();
+    } catch (Exception e) {
+      w = new Exception("wrapping", e);
+    }
+    verify(w);
+  }
+
+  @Test
+  public void multiNested() {
+    Exception w = null;
+    try {
+      someOtherMethod();
+    } catch (Exception e) {
+      w = new Exception("wrapping", e);
+    }
+    verify(w);
+  }
+  
+  void someMethod() throws Exception {
+    throw new Exception("someMethod");
+  }
+
+  void someOtherMethod() throws Exception {
+    try {
+      someMethod();
+    } catch (Exception e) {
+      throw new Exception("someOtherMethod", e);
+    }
+  }
+}


More information about the logback-dev mailing list