You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by rg...@apache.org on 2012/10/02 09:15:58 UTC

svn commit: r1392762 - in /logging/log4j/log4j2/trunk: api/src/main/java/org/apache/logging/log4j/ core/src/main/java/org/apache/logging/log4j/core/appender/ core/src/main/java/org/apache/logging/log4j/core/impl/ core/src/main/java/org/apache/logging/l...

Author: rgoers
Date: Tue Oct  2 07:15:57 2012
New Revision: 1392762

URL: http://svn.apache.org/viewvc?rev=1392762&view=rev
Log:
Fix LOG-58 - Add support for filtering packages in stacktraces

Added:
    logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableTest.java
      - copied, changed from r1391705, logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/pattern/RegexReplacementTest.java
    logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowableTest.java
    logging/log4j/log4j2/trunk/core/src/test/resources/log4j-rootthrowablefilter.xml
    logging/log4j/log4j2/trunk/core/src/test/resources/log4j-throwablefilter.xml
      - copied, changed from r1391705, logging/log4j/log4j2/trunk/core/src/test/resources/log4j-test1.xml
Modified:
    logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/ThreadContext.java
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/pattern/AnsiEscape.java
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/pattern/HighlightConverter.java
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/pattern/StyleConverter.java
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java
    logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverterTest.java
    logging/log4j/log4j2/trunk/src/changes/changes.xml
    logging/log4j/log4j2/trunk/src/site/xdoc/manual/layouts.xml

Modified: logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/ThreadContext.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/ThreadContext.java?rev=1392762&r1=1392761&r2=1392762&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/ThreadContext.java (original)
+++ logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/ThreadContext.java Tue Oct  2 07:15:57 2012
@@ -39,6 +39,10 @@ public final class ThreadContext {
      */
     public static final Map<String, String> EMPTY_MAP = new ImmutableMap();
 
+    /**
+     * Empty, immutable ContextStack.
+     */
+    public static final ContextStack EMPTY_STACK = new ImmutableStack();
 
     private static final String DISABLE_MAP = "disableThreadContextMap";
 
@@ -52,11 +56,6 @@ public final class ThreadContext {
 
     private static boolean useStack = !(Boolean.getBoolean(DISABLE_STACK) || all);
 
-    /**
-     * Empty, immutable ContextStack.
-     */
-    public static final ContextStack EMPTY_STACK = new ImmutableStack();
-
     private static ThreadLocal<Map<String, String>> localMap =
         new InheritableThreadLocal<Map<String, String>>() {
             @Override

Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java?rev=1392762&r1=1392761&r2=1392762&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java Tue Oct  2 07:15:57 2012
@@ -27,8 +27,6 @@ import org.apache.logging.log4j.core.lay
 
 import java.io.OutputStream;
 import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
 
 /**
  * ConsoleAppender appends log events to <code>System.out</code> or

Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java?rev=1392762&r1=1392761&r2=1392762&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java Tue Oct  2 07:15:57 2012
@@ -26,6 +26,7 @@ import java.lang.reflect.Modifier;
 import java.net.URL;
 import java.security.CodeSource;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Stack;
 
@@ -148,6 +149,15 @@ public class ThrowableProxy extends Thro
      * @return The formatted Throwable that caused this Throwable.
      */
     public String getRootCauseStackTrace() {
+        return getRootCauseStackTrace(null);
+    }
+
+    /**
+     * Format the Throwable that is the cause of this Throwable.
+     * @param packages The List of packages to be suppressed from the trace.
+     * @return The formatted Throwable that caused this Throwable.
+     */
+    public String getRootCauseStackTrace(List<String> packages) {
         StringBuilder sb = new StringBuilder();
         if (cause != null) {
             formatWrapper(sb, cause);
@@ -155,7 +165,7 @@ public class ThrowableProxy extends Thro
         }
         sb.append(throwable.toString());
         sb.append("\n");
-        formatElements(sb, 0, throwable.getStackTrace(), callerPackageData);
+        formatElements(sb, 0, throwable.getStackTrace(), callerPackageData, packages);
         return sb.toString();
     }
 
@@ -165,13 +175,23 @@ public class ThrowableProxy extends Thro
      * @param cause The Throwable to format.
      */
     public void formatWrapper(StringBuilder sb, ThrowableProxy cause) {
+        formatWrapper(sb, cause, null);
+    }
+
+    /**
+     * Formats the specified Throwable.
+     * @param sb StringBuilder to contain the formatted Throwable.
+     * @param cause The Throwable to format.
+     * @param packages The List of packages to be suppressed from the trace.
+     */
+    public void formatWrapper(StringBuilder sb, ThrowableProxy cause, List<String> packages) {
         Throwable caused = cause.getCause();
         if (caused != null) {
             formatWrapper(sb, cause.cause);
             sb.append("Wrapped by: ");
         }
         sb.append(cause).append("\n");
-        formatElements(sb, cause.commonElementCount, cause.getStackTrace(), cause.callerPackageData);
+        formatElements(sb, cause.commonElementCount, cause.getStackTrace(), cause.callerPackageData, packages);
     }
 
     /**
@@ -179,11 +199,20 @@ public class ThrowableProxy extends Thro
      * @return The formatted stack trace including packaging information.
      */
     public String getExtendedStackTrace() {
+        return getExtendedStackTrace(null);
+    }
+
+    /**
+     * Format the stack trace including packaging information.
+     * @param packages List of packages to be suppressed from the trace.
+     * @return The formatted stack trace including packaging information.
+     */
+    public String getExtendedStackTrace(List<String> packages) {
         StringBuilder sb = new StringBuilder(throwable.toString());
         sb.append("\n");
-        formatElements(sb, 0, throwable.getStackTrace(), callerPackageData);
+        formatElements(sb, 0, throwable.getStackTrace(), callerPackageData, packages);
         if (cause != null) {
-            formatCause(sb, cause);
+            formatCause(sb, cause, packages);
         }
         return sb.toString();
     }
@@ -204,28 +233,68 @@ public class ThrowableProxy extends Thro
         return sb.toString();
     }
 
-    private void formatCause(StringBuilder sb, ThrowableProxy cause) {
+    private void formatCause(StringBuilder sb, ThrowableProxy cause, List<String> packages) {
         sb.append("Caused by: ").append(cause).append("\n");
-        formatElements(sb, cause.commonElementCount, cause.getStackTrace(), cause.callerPackageData);
+        formatElements(sb, cause.commonElementCount, cause.getStackTrace(), cause.callerPackageData, packages);
         if (cause.getCause() != null) {
-            formatCause(sb, cause.cause);
+            formatCause(sb, cause.cause, packages);
         }
     }
 
     private void formatElements(StringBuilder sb, int commonCount, StackTraceElement[] causedTrace,
-                                StackTracePackageElement[] packageData) {
-        for (int i = 0; i < packageData.length; ++i) {
-            sb.append("\tat ");
-            sb.append(causedTrace[i]);
-            sb.append(" ");
-            sb.append(packageData[i]);
-            sb.append("\n");
+                                StackTracePackageElement[] packageData, List<String> packages) {
+        if (packages == null || packages.size() == 0) {
+            for (int i = 0; i < packageData.length; ++i) {
+                formatEntry(causedTrace[i], packageData[i], sb);
+            }
+        } else {
+            int count = 0;
+            for (int i = 0; i < packageData.length; ++i) {
+                if (!isSuppressed(causedTrace[i], packages)) {
+                    if (count > 0) {
+                        if (count == 1) {
+                            sb.append("\t....\n");
+                        } else {
+                            sb.append("\t... suppressed ").append(count).append(" lines\n");
+                        }
+                        count = 0;
+                    }
+                    formatEntry(causedTrace[i], packageData[i], sb);
+                } else {
+                    ++count;
+                }
+            }
+            if (count > 0) {
+                if (count == 1) {
+                    sb.append("\t...\n");
+                } else {
+                    sb.append("\t... suppressed ").append(count).append(" lines\n");
+                }
+            }
         }
         if (commonCount != 0) {
             sb.append("\t... ").append(commonCount).append(" more").append("\n");
         }
     }
 
+    private void formatEntry(StackTraceElement element, StackTracePackageElement packageData, StringBuilder sb) {
+        sb.append("\tat ");
+        sb.append(element);
+        sb.append(" ");
+        sb.append(packageData);
+        sb.append("\n");
+    }
+
+    private boolean isSuppressed(StackTraceElement element, List<String> packages) {
+        String className = element.getClassName();
+        for (String pkg : packages) {
+            if (className.startsWith(pkg)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * Initialize the cache by resolving everything in the current stack trace via Reflection.getCallerClass
      * or via the SecurityManager if either are available. These are the only Classes that can be trusted

Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/pattern/AnsiEscape.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/pattern/AnsiEscape.java?rev=1392762&r1=1392761&r2=1392762&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/pattern/AnsiEscape.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/pattern/AnsiEscape.java Tue Oct  2 07:15:57 2012
@@ -25,6 +25,9 @@ public enum AnsiEscape {
     SUFFIX("m"),
     SEPARATOR(";"),
 
+    /**
+     * General Attributes.
+     */
     NORMAL("0"),
     BRIGHT("1"),
     DIM("2"),
@@ -33,6 +36,9 @@ public enum AnsiEscape {
     REVERSE("7"),
     HIDDEN("8"),
 
+    /**
+     * Foreground Colors.
+     */
     BLACK("30"),
     FG_BLACK("30"),
     RED("31"),
@@ -52,6 +58,9 @@ public enum AnsiEscape {
     DEFAULT("39"),
     FG_DEFAULT("39"),
 
+    /**
+     * Background Colors.
+     */
     BG_BLACK("40"),
     BG_RED("41"),
     BG_GREEN("42"),
@@ -61,16 +70,16 @@ public enum AnsiEscape {
     BG_CYAN("46"),
     BG_WHITE("47");
 
-    public static String getDefaultStyle() {
-        return PREFIX.getCode() + SUFFIX.getCode();
-    }
-
     private final String code;
 
     private AnsiEscape(String code) {
         this.code = code;
     }
 
+    public static String getDefaultStyle() {
+        return PREFIX.getCode() + SUFFIX.getCode();
+    }
+
     public String getCode() {
         return code;
     }

Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java?rev=1392762&r1=1392761&r2=1392762&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java Tue Oct  2 07:15:57 2012
@@ -20,6 +20,10 @@ import org.apache.logging.log4j.core.Log
 import org.apache.logging.log4j.core.config.plugins.Plugin;
 import org.apache.logging.log4j.core.impl.ThrowableProxy;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Scanner;
+
 /**
  * Outputs the Throwable portion of the LoggingEvent as a full stacktrace
  * unless this converter's option is 'short', where it just outputs the first line of the trace, or if
@@ -31,6 +35,11 @@ import org.apache.logging.log4j.core.imp
 @Plugin(name = "ExtendedThrowablePatternConverter", type = "Converter")
 @ConverterKeys({"xEx", "xThrowable", "xException" })
 public final class ExtendedThrowablePatternConverter extends ThrowablePatternConverter {
+
+    private static final String FILTERS = "filters(";
+
+    private List<String> packages = null;
+
     /**
      * Private constructor.
      *
@@ -38,6 +47,18 @@ public final class ExtendedThrowablePatt
      */
     private ExtendedThrowablePatternConverter(final String[] options) {
         super("ExtendedThrowable", "throwable", options);
+        if (options != null && options.length > 1) {
+            if (options[1].startsWith(FILTERS) && options[1].endsWith(")")) {
+                String filterStr = options[1].substring(FILTERS.length(), options[1].length() - 1);
+                String[] array = filterStr.split(",");
+                if (array.length > 0) {
+                    packages = new ArrayList<String>(array.length);
+                    for (String token : array) {
+                        packages.add(token.trim());
+                    }
+                }
+            }
+        }
     }
 
     /**
@@ -47,9 +68,24 @@ public final class ExtendedThrowablePatt
      *                only the first line of the throwable will be formatted.
      * @return instance of class.
      */
-    public static ExtendedThrowablePatternConverter newInstance(
-        final String[] options) {
-        return new ExtendedThrowablePatternConverter(options);
+    public static ExtendedThrowablePatternConverter newInstance(final String[] options) {
+        String type = null;
+        String[] array = options;
+        if (options != null && options.length == 1 && options[0].length() > 0) {
+            String[] opts = options[0].split(",", 2);
+            String first = opts[0].trim();
+            String filter;
+            Scanner scanner = new Scanner(first);
+            if (first.equalsIgnoreCase(FULL) || first.equalsIgnoreCase(SHORT) || scanner.hasNextInt()) {
+                type = first;
+                filter = opts[1].trim();
+            } else {
+                filter = options[0].trim();
+            }
+            array = new String[] {type, filter};
+        }
+
+        return new ExtendedThrowablePatternConverter(array);
     }
 
     /**
@@ -64,7 +100,7 @@ public final class ExtendedThrowablePatt
                 return;
             }
             ThrowableProxy t = (ThrowableProxy) throwable;
-            String trace = t.getExtendedStackTrace();
+            String trace = t.getExtendedStackTrace(packages);
             int len = toAppendTo.length();
             if (len > 0 && !Character.isWhitespace(toAppendTo.charAt(len - 1))) {
                 toAppendTo.append(" ");

Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/pattern/HighlightConverter.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/pattern/HighlightConverter.java?rev=1392762&r1=1392761&r2=1392762&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/pattern/HighlightConverter.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/pattern/HighlightConverter.java Tue Oct  2 07:15:57 2012
@@ -33,8 +33,6 @@ import java.util.List;
 @ConverterKeys({"highlight" })
 public final class HighlightConverter extends LogEventPatternConverter {
 
-    private List<PatternFormatter> formatters;
-
     private static final EnumMap<Level, String> LEVEL_STYLES = new EnumMap<Level, String>(Level.class);
 
     private static final String[] FATAL = new String[]{"BLINK", "BRIGHT", "RED"};
@@ -44,6 +42,8 @@ public final class HighlightConverter ex
     private static final String[] DEBUG = null;
     private static final String[] TRACE = null;
 
+    private List<PatternFormatter> formatters;
+
     static {
         LEVEL_STYLES.put(Level.FATAL, AnsiEscape.createSequence(FATAL));
         LEVEL_STYLES.put(Level.ERROR, AnsiEscape.createSequence(ERROR));

Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java?rev=1392762&r1=1392761&r2=1392762&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/pattern/RootThrowablePatternConverter.java Tue Oct  2 07:15:57 2012
@@ -20,6 +20,10 @@ import org.apache.logging.log4j.core.Log
 import org.apache.logging.log4j.core.config.plugins.Plugin;
 import org.apache.logging.log4j.core.impl.ThrowableProxy;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Scanner;
+
 
 /**
  * Outputs the Throwable portion of the LoggingEvent as a full stacktrace
@@ -32,6 +36,11 @@ import org.apache.logging.log4j.core.imp
 @Plugin(name = "RootThrowablePatternConverter", type = "Converter")
 @ConverterKeys({"rEx", "rThrowable", "rException" })
 public final class RootThrowablePatternConverter extends ThrowablePatternConverter {
+
+    private static final String FILTERS = "filters(";
+
+    private List<String> packages = null;
+
     /**
      * Private constructor.
      *
@@ -39,6 +48,18 @@ public final class RootThrowablePatternC
      */
     private RootThrowablePatternConverter(final String[] options) {
         super("RootThrowable", "throwable", options);
+        if (options != null && options.length > 1) {
+            if (options[1].startsWith(FILTERS) && options[1].endsWith(")")) {
+                String filterStr = options[1].substring(FILTERS.length(), options[1].length() - 1);
+                String[] array = filterStr.split(",");
+                if (array.length > 0) {
+                    packages = new ArrayList<String>(array.length);
+                    for (String token : array) {
+                        packages.add(token.trim());
+                    }
+                }
+            }
+        }
     }
 
     /**
@@ -48,9 +69,24 @@ public final class RootThrowablePatternC
      *                only the first line of the throwable will be formatted.
      * @return instance of class.
      */
-    public static RootThrowablePatternConverter newInstance(
-        final String[] options) {
-        return new RootThrowablePatternConverter(options);
+    public static RootThrowablePatternConverter newInstance(final String[] options) {
+        String type = null;
+        String[] array = options;
+        if (options != null && options.length == 1 && options[0].length() > 0) {
+            String[] opts = options[0].split(",", 2);
+            String first = opts[0].trim();
+            String filter;
+            Scanner scanner = new Scanner(first);
+            if (first.equalsIgnoreCase(FULL) || first.equalsIgnoreCase(SHORT) || scanner.hasNextInt()) {
+                type = first;
+                filter = opts[1].trim();
+            } else {
+                filter = options[0].trim();
+            }
+            array = new String[] {type, filter};
+        }
+
+        return new RootThrowablePatternConverter(array);
     }
 
     /**
@@ -65,7 +101,7 @@ public final class RootThrowablePatternC
                 return;
             }
             ThrowableProxy t = (ThrowableProxy) throwable;
-            String trace = t.getRootCauseStackTrace();
+            String trace = t.getRootCauseStackTrace(packages);
             int len = toAppendTo.length();
             if (len > 0 && !Character.isWhitespace(toAppendTo.charAt(len - 1))) {
                 toAppendTo.append(" ");

Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/pattern/StyleConverter.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/pattern/StyleConverter.java?rev=1392762&r1=1392761&r2=1392762&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/pattern/StyleConverter.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/pattern/StyleConverter.java Tue Oct  2 07:15:57 2012
@@ -16,15 +16,12 @@
  */
 package org.apache.logging.log4j.core.pattern;
 
-import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.config.Configuration;
 import org.apache.logging.log4j.core.config.plugins.Plugin;
 import org.apache.logging.log4j.core.layout.PatternLayout;
 
-import java.util.EnumMap;
 import java.util.List;
-import java.util.regex.Pattern;
 
 /**
  * Style pattern converter. Adds ANSI color styling to the result of the enclosed pattern.

Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java?rev=1392762&r1=1392761&r2=1392762&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/pattern/ThrowablePatternConverter.java Tue Oct  2 07:15:57 2012
@@ -63,7 +63,8 @@ public class ThrowablePatternConverter e
         int count = 0;
         if ((options != null) && (options.length > 0)) {
             option = options[0];
-            if (option.equalsIgnoreCase(SHORT)) {
+            if (option == null) {
+            } else if (option.equalsIgnoreCase(SHORT)) {
                 count = 2;
             } else if (!option.equalsIgnoreCase(FULL)) {
                 count = Integer.parseInt(option);
@@ -82,8 +83,7 @@ public class ThrowablePatternConverter e
      *                only the first line of the throwable will be formatted.
      * @return instance of class.
      */
-    public static ThrowablePatternConverter newInstance(
-        final String[] options) {
+    public static ThrowablePatternConverter newInstance(final String[] options) {
         return new ThrowablePatternConverter("Throwable", "throwable", options);
     }
 

Modified: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverterTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverterTest.java?rev=1392762&r1=1392761&r2=1392762&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverterTest.java (original)
+++ logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverterTest.java Tue Oct  2 07:15:57 2012
@@ -28,6 +28,7 @@ import java.io.StringWriter;
 import java.util.List;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 /**
  *
@@ -58,4 +59,19 @@ public class ExtendedThrowablePatternCon
         String expected = sw.toString().replaceAll("\r", "");
         assertEquals(expected, result);
     }
+
+    @Test
+    public void testFiltering() {
+        String packages = "filters(org.junit, org.apache.maven, sun.reflect, java.lang.reflect)";
+        String[] options = {packages};
+        ExtendedThrowablePatternConverter converter = ExtendedThrowablePatternConverter.newInstance(options);
+        Throwable cause = new NullPointerException("null pointer");
+        Throwable parent = new IllegalArgumentException("IllegalArgument", cause);
+        LogEvent event = new Log4jLogEvent("testLogger", null, this.getClass().getName(), Level.DEBUG,
+            new SimpleMessage("test exception"), parent);
+        StringBuilder sb = new StringBuilder();
+        converter.format(event, sb);
+        String result = sb.toString();
+        assertTrue("No suppressed lines", result.contains(" suppressed "));
+    }
 }

Copied: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableTest.java (from r1391705, logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/pattern/RegexReplacementTest.java)
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableTest.java?p2=logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableTest.java&p1=logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/pattern/RegexReplacementTest.java&r1=1391705&r2=1392762&rev=1392762&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/pattern/RegexReplacementTest.java (original)
+++ logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/pattern/ExtendedThrowableTest.java Tue Oct  2 07:15:57 2012
@@ -20,10 +20,10 @@ import org.apache.logging.log4j.LogManag
 import org.apache.logging.log4j.ThreadContext;
 import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.LoggerContext;
-import org.apache.logging.log4j.test.appender.ListAppender;
 import org.apache.logging.log4j.core.config.Configuration;
 import org.apache.logging.log4j.core.config.XMLConfigurationFactory;
 import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.test.appender.ListAppender;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -31,22 +31,16 @@ import org.junit.Test;
 import java.util.List;
 import java.util.Map;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
 
 /**
  *
  */
-public class RegexReplacementTest {
-    private static final String CONFIG = "log4j-replace.xml";
+public class ExtendedThrowableTest {
+    private static final String CONFIG = "log4j-throwablefilter.xml";
     private static Configuration config;
     private static ListAppender app;
-    private static ListAppender app2;
     private static LoggerContext ctx;
-    
-    private static final String LINE_SEP = System.getProperty("line.separator");
-    private static final String EXPECTED = "/RegexReplacementTest" + LINE_SEP;
 
     @BeforeClass
     public static void setupClass() {
@@ -57,9 +51,6 @@ public class RegexReplacementTest {
             if (entry.getKey().equals("List")) {
                 app = (ListAppender) entry.getValue();
             }
-            if (entry.getKey().equals("List2")) {
-                app2 = (ListAppender) entry.getValue();
-            }
         }
     }
 
@@ -68,36 +59,19 @@ public class RegexReplacementTest {
         System.clearProperty(XMLConfigurationFactory.CONFIGURATION_FILE_PROPERTY);
         ctx.reconfigure();
         StatusLogger.getLogger().reset();
-        ThreadContext.clear();
     }
 
     org.apache.logging.log4j.Logger logger = LogManager.getLogger("LoggerTest");
-    org.apache.logging.log4j.Logger logger2 = LogManager.getLogger("ReplacementTest");
 
     @Test
-    public void testReplacement() {
-        logger.error(this.getClass().getName());
+    public void testException() {
+        Throwable cause = new NullPointerException("null pointer");
+        Throwable parent = new IllegalArgumentException("IllegalArgument", cause);
+        logger.error("Exception", parent);
         List<String> msgs = app.getMessages();
         assertNotNull(msgs);
         assertTrue("Incorrect number of messages. Should be 1 is " + msgs.size(), msgs.size() == 1);
-        assertTrue("Replacement failed - expected ending " + EXPECTED + " Actual " + msgs.get(0), msgs.get(0).endsWith(EXPECTED));
-        app.clear();
-        ThreadContext.put("MyKey", "Apache");
-        logger.error("This is a test for ${ctx:MyKey}");
-        msgs = app.getMessages();
-        assertNotNull(msgs);
-        assertTrue("Incorrect number of messages. Should be 1 is " + msgs.size(), msgs.size() == 1);
-        assertEquals("LoggerTest This is a test for Apache" + LINE_SEP , msgs.get(0));
+        assertTrue("No suppressed lines", msgs.get(0).contains("suppressed"));
         app.clear();
-
-    }
-     @Test
-    public void testConverter() {
-        logger2.error(this.getClass().getName());
-        List<String> msgs = app2.getMessages();
-        assertNotNull(msgs);
-        assertTrue("Incorrect number of messages. Should be 1 is " + msgs.size(), msgs.size() == 1);
-         assertTrue("Replacement failed - expected ending " + EXPECTED + " Actual " + msgs.get(0), msgs.get(0).endsWith(EXPECTED));
-        app2.clear();
     }
 }

Added: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowableTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowableTest.java?rev=1392762&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowableTest.java (added)
+++ logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/pattern/RootThrowableTest.java Tue Oct  2 07:15:57 2012
@@ -0,0 +1,77 @@
+/*
+ * 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.logging.log4j.core.pattern;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.XMLConfigurationFactory;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.test.appender.ListAppender;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ *
+ */
+public class RootThrowableTest {
+    private static final String CONFIG = "log4j-rootthrowablefilter.xml";
+    private static Configuration config;
+    private static ListAppender app;
+    private static LoggerContext ctx;
+
+    @BeforeClass
+    public static void setupClass() {
+        System.setProperty(XMLConfigurationFactory.CONFIGURATION_FILE_PROPERTY, CONFIG);
+        ctx = (LoggerContext) LogManager.getContext(false);
+        config = ctx.getConfiguration();
+        for (Map.Entry<String, Appender> entry : config.getAppenders().entrySet()) {
+            if (entry.getKey().equals("List")) {
+                app = (ListAppender) entry.getValue();
+            }
+        }
+    }
+
+    @AfterClass
+    public static void cleanupClass() {
+        System.clearProperty(XMLConfigurationFactory.CONFIGURATION_FILE_PROPERTY);
+        ctx.reconfigure();
+        StatusLogger.getLogger().reset();
+    }
+
+    org.apache.logging.log4j.Logger logger = LogManager.getLogger("LoggerTest");
+
+    @Test
+    public void testException() {
+        Throwable cause = new NullPointerException("null pointer");
+        Throwable parent = new IllegalArgumentException("IllegalArgument", cause);
+        logger.error("Exception", parent);
+        List<String> msgs = app.getMessages();
+        assertNotNull(msgs);
+        assertTrue("Incorrect number of messages. Should be 1 is " + msgs.size(), msgs.size() == 1);
+        assertTrue("No suppressed lines", msgs.get(0).contains("suppressed"));
+        app.clear();
+    }
+}

Added: logging/log4j/log4j2/trunk/core/src/test/resources/log4j-rootthrowablefilter.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/resources/log4j-rootthrowablefilter.xml?rev=1392762&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/resources/log4j-rootthrowablefilter.xml (added)
+++ logging/log4j/log4j2/trunk/core/src/test/resources/log4j-rootthrowablefilter.xml Tue Oct  2 07:15:57 2012
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+
+-->
+<configuration status="warn" name="XMLConfigTest" packages="org.apache.logging.log4j.test">
+  <properties>
+    <property name="filters">org.junit,org.apache.maven,sun.reflect,java.lang.reflect</property>
+  </properties>
+  <ThresholdFilter level="debug"/>
+
+  <appenders>
+    <Console name="STDOUT">
+      <PatternLayout pattern="%m%rEx{FULL,filters(${filters})}%n"/>
+    </Console>
+    <List name="List">
+      <PatternLayout pattern="%m%rEx{filters(${filters})}%n"/>
+    </List>
+  </appenders>
+
+  <loggers>
+    <root level="error">
+      <appender-ref ref="List"/>
+    </root>
+  </loggers>
+
+</configuration>
\ No newline at end of file

Copied: logging/log4j/log4j2/trunk/core/src/test/resources/log4j-throwablefilter.xml (from r1391705, logging/log4j/log4j2/trunk/core/src/test/resources/log4j-test1.xml)
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/resources/log4j-throwablefilter.xml?p2=logging/log4j/log4j2/trunk/core/src/test/resources/log4j-throwablefilter.xml&p1=logging/log4j/log4j2/trunk/core/src/test/resources/log4j-test1.xml&r1=1391705&r2=1392762&rev=1392762&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/resources/log4j-test1.xml (original)
+++ logging/log4j/log4j2/trunk/core/src/test/resources/log4j-throwablefilter.xml Tue Oct  2 07:15:57 2012
@@ -18,40 +18,22 @@
 -->
 <configuration status="warn" name="XMLConfigTest" packages="org.apache.logging.log4j.test">
   <properties>
-    <property name="filename">target/test.log</property>
+    <property name="filters">org.junit,org.apache.maven,sun.reflect,java.lang.reflect</property>
   </properties>
   <ThresholdFilter level="debug"/>
 
   <appenders>
     <Console name="STDOUT">
-      <PatternLayout pattern="%m%n"/>
+      <PatternLayout pattern="%m%xEx{FULL,filters(${filters})}%n"/>
     </Console>
-    <File name="File" fileName="${filename}" bufferedIO="false">
-      <PatternLayout>
-        <pattern>%d %p %C{1.} [%t] %m%n</pattern>
-      </PatternLayout>
-    </File>
     <List name="List">
-      <filters>
-        <ThresholdFilter level="error"/>
-      </filters>
+      <PatternLayout pattern="%m%xEx{filters(${filters})}%n"/>
     </List>
   </appenders>
 
   <loggers>
-    <logger name="org.apache.logging.log4j.test1" level="debug" additivity="false">
-        <ThreadContextMapFilter>
-          <KeyValuePair key="test" value="123"/>
-        </ThreadContextMapFilter>
-      <appender-ref ref="STDOUT"/>
-    </logger>>
-
-    <logger name="org.apache.logging.log4j.test2" level="debug" additivity="false">
-      <appender-ref ref="File"/>
-    </logger>>
-
     <root level="error">
-      <appender-ref ref="STDOUT"/>
+      <appender-ref ref="List"/>
     </root>
   </loggers>
 

Modified: logging/log4j/log4j2/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/src/changes/changes.xml?rev=1392762&r1=1392761&r2=1392762&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/src/changes/changes.xml (original)
+++ logging/log4j/log4j2/trunk/src/changes/changes.xml Tue Oct  2 07:15:57 2012
@@ -23,6 +23,9 @@
 
   <body>
     <release version="2.0-beta2" date="TBD" description="Bug fixes and enhancements">
+      <action issue="LOG4J2-58" dev="rgoers" type="add">
+        Add support for filtering packages from stack traces.
+      </action>
       <action issue="LOG4J2-84" dev="rgoers" type="add">
         If system property "disableThreadContextStack" is set pushes to the ThreadContext will be ignored. If
         system property "disableThreadContext" is set both puts and pushes will be ignored.

Modified: logging/log4j/log4j2/trunk/src/site/xdoc/manual/layouts.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/src/site/xdoc/manual/layouts.xml?rev=1392762&r1=1392761&r2=1392762&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/src/site/xdoc/manual/layouts.xml (original)
+++ logging/log4j/log4j2/trunk/src/site/xdoc/manual/layouts.xml Tue Oct  2 07:15:57 2012
@@ -240,9 +240,9 @@
             </tr>
             <tr>
               <td align="center">
-                <b>ex</b>{depth}<br />
-                <b>exception</b>{depth}<br />
-                <b>throwable</b>{depth}
+                <b>ex</b>{["short"|"full"|depth]}<br />
+                <b>exception</b>{["short"|"full"|depth]}<br />
+                <b>throwable</b>{["short"|"full"|depth]}
               </td>
               <td>
                 <p>Used to output the Throwable trace that has been bound to the LoggingEvent, by
@@ -389,15 +389,23 @@
             </tr>
             <tr>
               <td align="center">
-                <b>rEx</b>{depth}<br />
-                <b>rException</b>{depth}<br />
-                <b>rThrowable</b>{depth}
+                <b>rEx</b>["short"|"full"|depth],[filters(packages)}<br />
+                <b>rException</b>["short"|"full"|depth],[filters(packages)}<br />
+                <b>rThrowable</b>["short"|"full"|depth],[filters(packages)}
               </td>
               <td>
                 <p>
                   The same as the %throwable conversion word but the stack trace is printed starting with the
                   first exception that was thrown followed by each subsequent wrapping exception.
                 </p>
+                <p>
+                  The throwable conversion word can be followed by an option in the form
+                  <b>%rEx{short}</b>
+                  which will only output the first line of the Throwable or <b>%rEx{n}</b> where
+                  the first n lines of the stacktrace will be printed. The conversion word can also be
+                  followed by "filters(packages)" where packages is a list of package names that should
+                  be suppressed from stack traces.
+                </p>
               </td>
             </tr>
             <tr>
@@ -580,9 +588,9 @@
             </tr>
             <tr>
               <td align="center">
-                <b>xEx</b>{depth}<br />
-                <b>xException</b>{depth}<br />
-                <b>xThrowable</b>{depth}
+                <b>xEx</b>{["short"|"full"|depth],[filters(packages)}<br />
+                <b>xException</b>["short"|"full"|depth],[filters(packages)}<br />
+                <b>xThrowable</b>["short"|"full"|depth],[filters(packages)}
               </td>
               <td>
                 <p>
@@ -594,6 +602,14 @@
                   as found in that jar's manifest will be added. If the information is uncertain, then the class
                   packaging data will be preceded by a tilde, i.e. the '~' character.
                 </p>
+                <p>
+                  The throwable conversion word can be followed by an option in the form
+                  <b>%xEx{short}</b>
+                  which will only output the first line of the Throwable or <b>%xEx{n}</b> where
+                  the first n lines of the stacktrace will be printed. The conversion word can also be
+                  followed by "filters(packages)" where packages is a list of package names that should
+                  be suppressed from stack traces.
+                </p>
               </td>
             </tr>
             <tr>
@@ -711,6 +727,32 @@
             application and Log4j will automatically make use of it when writing to the console.
           </p>
           <h4>Example Patterns</h4>
+          <h5>Filtered Throwables</h5>
+          <p>
+            This example shows how to filter out classes from unimportant packages in stack traces.
+          </p>
+          <source><![CDATA[
+  <properties>
+    <property name="filters">org.junit,org.apache.maven,sun.reflect,java.lang.reflect</property>
+  </properties>
+  .
+  .
+      <PatternLayout pattern="%m%xEx{filters(${filters})}%n"/>
+  ]]></source>
+          <p>
+            The result printed to the console will appear similar to:
+          </p>
+          <source>
+  Exception java.lang.IllegalArgumentException: IllegalArgument
+  at org.apache.logging.log4j.core.pattern.ExtendedThrowableTest.testException(ExtendedThrowableTest.java:72) [test-classes/:?]
+  ... suppressed 26 lines
+  at $Proxy0.invoke(Unknown Source) [?:?]
+  ... suppressed 3 lines
+  Caused by: java.lang.NullPointerException: null pointer
+  at org.apache.logging.log4j.core.pattern.ExtendedThrowableTest.testException(ExtendedThrowableTest.java:71) ~[test-classes/:?]
+  ... 30 more
+
+          </source>
           <h5>Ansi Styled</h5>
           <p>The log level will be highlighted according to the event's log level. All the content that follows
             the level will be bright green.</p>