You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by mi...@apache.org on 2016/05/06 14:43:28 UTC

[18/50] logging-log4j2 git commit: [LOG4J2-621] Pattern to drop first N package parts. Closes #28 https://github.com/apache/logging-log4j2/pull/28

[LOG4J2-621] Pattern to drop first N package parts. Closes #28
https://github.com/apache/logging-log4j2/pull/28

Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/23b2b367
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/23b2b367
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/23b2b367

Branch: refs/heads/LOG4J-1181
Commit: 23b2b3670d70e4494b2dc6c1929e6eb36ac0db2d
Parents: ad5073c
Author: ggregory <gg...@apache.org>
Authored: Mon May 2 14:31:35 2016 -0700
Committer: ggregory <gg...@apache.org>
Committed: Mon May 2 14:31:35 2016 -0700

----------------------------------------------------------------------
 .../log4j/core/pattern/NameAbbreviator.java     |  77 ++++++-
 .../log4j/core/layout/PatternLayoutTest.java    | 202 +++++++++++++++++++
 src/changes/changes.xml                         |   3 +
 src/site/xdoc/manual/layouts.xml.vm             |  34 +++-
 4 files changed, 304 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/23b2b367/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/NameAbbreviator.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/NameAbbreviator.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/NameAbbreviator.java
index 1271ad5..a59cc5f 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/NameAbbreviator.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/NameAbbreviator.java
@@ -52,18 +52,31 @@ public abstract class NameAbbreviator {
                 return DEFAULT;
             }
 
+            boolean isNegativeNumber;
+            final String number;
+
+            // check if number is a negative number
+            if (trimmed.length() > 1 && trimmed.charAt(0) == '-') {
+                isNegativeNumber = true;
+                number = trimmed.substring(1);
+            } else {
+                isNegativeNumber = false;
+                number = trimmed;
+            }
+
             int i = 0;
 
-            while (i < trimmed.length() && trimmed.charAt(i) >= '0'
-                    && trimmed.charAt(i) <= '9') {
+            while (i < number.length() && number.charAt(i) >= '0'
+                    && number.charAt(i) <= '9') {
                 i++;
             }
 
             //
             //  if all blanks and digits
             //
-            if (i == trimmed.length()) {
-                return new MaxElementAbbreviator(Integer.parseInt(trimmed));
+            if (i == number.length()) {
+                return new MaxElementAbbreviator(Integer.parseInt(number),
+                        isNegativeNumber? MaxElementAbbreviator.Strategy.DROP : MaxElementAbbreviator.Strategy.RETAIN);
             }
 
             final ArrayList<PatternAbbreviatorFragment> fragments = new ArrayList<>(5);
@@ -156,18 +169,45 @@ public abstract class NameAbbreviator {
      * Abbreviator that drops starting path elements.
      */
     private static class MaxElementAbbreviator extends NameAbbreviator {
+
+        /**
+         * <p>When the name is reduced in length by cutting parts, there can be two ways to do it.</p>
+         * 1. Remove a given number of parts starting from front - called DROP <br/>
+         * 2. Retain a given number of parts starting from the end - called RETAIN
+         */
+        private enum Strategy {
+            DROP,
+            RETAIN
+        };
+
         /**
          * Maximum number of path elements to output.
          */
         private final int count;
 
         /**
+         * Strategy used for cutting down the size of the name
+         */
+        private final Strategy strategy;
+
+        /**
          * Create new instance.
          *
-         * @param count maximum number of path elements to output.
+         * @param count maximum number of path elements to drop or output.
+         * @param strategy drop or retain
          */
-        public MaxElementAbbreviator(final int count) {
-            this.count = count < 1 ? 1 : count;
+        public MaxElementAbbreviator(final int count, final Strategy strategy) {
+            final int minCount = getMinCount(strategy);
+            this.count = count < minCount ? minCount : count;
+            this.strategy = strategy;
+        }
+
+        private int getMinCount(final Strategy strategy) {
+            if (Strategy.DROP == strategy) {
+                return 0;
+            } else { // Strategy.RETAIN
+                return 1;
+            }
         }
 
         /**
@@ -179,7 +219,30 @@ public abstract class NameAbbreviator {
          */
         @Override
         public void abbreviate(final String original, final StringBuilder destination) {
+            if (Strategy.DROP == strategy) {
+                abbreviateForDrop(original, destination);
+            } else { // Strategy.RETAIN
+                abbreviateForRetain(original, destination);
+            }
+        }
+
+        private void abbreviateForDrop(String original, StringBuilder destination) {
+            // If a path does not contain enough path elements to drop, none will be dropped.
+            int start = 0;
+            int nextStart = 0;
+            for (int i = 0; i < count; i++) {
+                nextStart = original.indexOf('.', start);
+                if (nextStart == -1) {
+                    destination.append(original);
+                    return;
+                } else {
+                    start = nextStart + 1;
+                }
+            }
+            destination.append(original, start, original.length());
+        }
 
+        private void abbreviateForRetain(String original, StringBuilder destination) {
             // We subtract 1 from 'len' when assigning to 'end' to avoid out of
             // bounds exception in return r.substring(end+1, len). This can happen if
             // precision is 1 and the category name ends with a dot.

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/23b2b367/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java
index 988b42b..6f58ebc 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java
@@ -398,4 +398,206 @@ public class PatternLayoutTest {
                 .withConfiguration(ctx.getConfiguration()).withCharset(StandardCharsets.UTF_8).build();
         assertEquals(StandardCharsets.UTF_8, layout.getCharset());
     }
+
+    @Test
+    public void testLoggerNameTruncationByRetainingPartsFromEnd() throws Exception {
+        {
+            final PatternLayout layout = PatternLayout.newBuilder().withPattern("%c{1} %m")
+                    .withConfiguration(ctx.getConfiguration()).build();
+            final LogEvent event1 = Log4jLogEvent.newBuilder()
+                    .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger")
+                    .setLevel(Level.INFO)
+                    .setMessage(new SimpleMessage("Hello, world 1!")).build();
+            final String result1 = layout.toSerializable(event1);
+            assertEquals(this.getClass().getName().substring(this.getClass().getName().lastIndexOf(".") + 1) + " Hello, world 1!", new String(result1));
+        }
+        {
+            final PatternLayout layout = PatternLayout.newBuilder().withPattern("%c{2} %m")
+                    .withConfiguration(ctx.getConfiguration()).build();
+            final LogEvent event1 = Log4jLogEvent.newBuilder()
+                    .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger")
+                    .setLevel(Level.INFO)
+                    .setMessage(new SimpleMessage("Hello, world 1!")).build();
+            final String result1 = layout.toSerializable(event1);
+            String name = this.getClass().getName().substring(0, this.getClass().getName().lastIndexOf("."));
+            name = name.substring(0, name.lastIndexOf("."));
+            assertEquals(this.getClass().getName().substring(name.length() + 1) + " Hello, world 1!", new String(result1));
+        }
+        {
+            final PatternLayout layout = PatternLayout.newBuilder().withPattern("%c{20} %m")
+                    .withConfiguration(ctx.getConfiguration()).build();
+            final LogEvent event1 = Log4jLogEvent.newBuilder()
+                    .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger")
+                    .setLevel(Level.INFO)
+                    .setMessage(new SimpleMessage("Hello, world 1!")).build();
+            final String result1 = layout.toSerializable(event1);
+            assertEquals(this.getClass().getName() + " Hello, world 1!", new String(result1));
+        }
+    }
+
+    @Test
+    public void testCallersFqcnTruncationByRetainingPartsFromEnd() throws Exception {
+        {
+            final PatternLayout layout = PatternLayout.newBuilder().withPattern("%C{1} %m")
+                    .withConfiguration(ctx.getConfiguration()).build();
+            final LogEvent event1 = Log4jLogEvent.newBuilder()
+                    .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger")
+                    .setLevel(Level.INFO)
+                    .setMessage(new SimpleMessage("Hello, world 1!"))
+                    .setSource(new StackTraceElement(this.getClass().getName(), "testCallersFqcnTruncationByRetainingPartsFromEnd", this.getClass().getCanonicalName() + ".java", 440))
+                    .build();
+            final String result1 = layout.toSerializable(event1);
+            assertEquals(this.getClass().getName().substring(this.getClass().getName().lastIndexOf(".") + 1) + " Hello, world 1!", new String(result1));
+        }
+        {
+            final PatternLayout layout = PatternLayout.newBuilder().withPattern("%C{2} %m")
+                    .withConfiguration(ctx.getConfiguration()).build();
+            final LogEvent event1 = Log4jLogEvent.newBuilder()
+                    .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger")
+                    .setLevel(Level.INFO)
+                    .setMessage(new SimpleMessage("Hello, world 1!"))
+                    .setSource(new StackTraceElement(this.getClass().getName(), "testCallersFqcnTruncationByRetainingPartsFromEnd", this.getClass().getCanonicalName() + ".java", 440))
+                    .build();
+            final String result1 = layout.toSerializable(event1);
+            String name = this.getClass().getName().substring(0, this.getClass().getName().lastIndexOf("."));
+            name = name.substring(0, name.lastIndexOf("."));
+            assertEquals(this.getClass().getName().substring(name.length() + 1) + " Hello, world 1!", new String(result1));
+        }
+        {
+            final PatternLayout layout = PatternLayout.newBuilder().withPattern("%C{20} %m")
+                    .withConfiguration(ctx.getConfiguration()).build();
+            final LogEvent event1 = Log4jLogEvent.newBuilder()
+                    .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger")
+                    .setLevel(Level.INFO)
+                    .setMessage(new SimpleMessage("Hello, world 1!"))
+                    .setSource(new StackTraceElement(this.getClass().getName(), "testCallersFqcnTruncationByRetainingPartsFromEnd", this.getClass().getCanonicalName() + ".java", 440))
+                    .build();
+            final String result1 = layout.toSerializable(event1);
+            assertEquals(this.getClass().getName() + " Hello, world 1!", new String(result1));
+        }
+        {
+            final PatternLayout layout = PatternLayout.newBuilder().withPattern("%class{1} %m")
+                    .withConfiguration(ctx.getConfiguration()).build();
+            final LogEvent event1 = Log4jLogEvent.newBuilder()
+                    .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger")
+                    .setLevel(Level.INFO)
+                    .setMessage(new SimpleMessage("Hello, world 1!"))
+                    .setSource(new StackTraceElement(this.getClass().getName(), "testCallersFqcnTruncationByRetainingPartsFromEnd", this.getClass().getCanonicalName() + ".java", 440))
+                    .build();
+            final String result1 = layout.toSerializable(event1);
+            assertEquals(this.getClass().getName().substring(this.getClass().getName().lastIndexOf(".") + 1) + " Hello, world 1!", new String(result1));
+        }
+    }
+
+    @Test
+    public void testLoggerNameTruncationByDroppingPartsFromFront() throws Exception {
+        {
+            final PatternLayout layout = PatternLayout.newBuilder().withPattern("%c{-1} %m")
+                    .withConfiguration(ctx.getConfiguration()).build();
+            final LogEvent event1 = Log4jLogEvent.newBuilder()
+                    .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger")
+                    .setLevel(Level.INFO)
+                    .setMessage(new SimpleMessage("Hello, world 1!")).build();
+            final String result1 = layout.toSerializable(event1);
+            String name = this.getClass().getName().substring(this.getClass().getName().indexOf(".") + 1);
+            assertEquals(name + " Hello, world 1!", new String(result1));
+        }
+        {
+            final PatternLayout layout = PatternLayout.newBuilder().withPattern("%c{-3} %m")
+                    .withConfiguration(ctx.getConfiguration()).build();
+            final LogEvent event1 = Log4jLogEvent.newBuilder()
+                    .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger")
+                    .setLevel(Level.INFO)
+                    .setMessage(new SimpleMessage("Hello, world 1!")).build();
+            final String result1 = layout.toSerializable(event1);
+            String name = this.getClass().getName().substring(this.getClass().getName().indexOf(".") + 1);
+            name = name.substring(name.indexOf(".") + 1);
+            name = name.substring(name.indexOf(".") + 1);
+            assertEquals(name + " Hello, world 1!", new String(result1));
+        }
+        {
+            final PatternLayout layout = PatternLayout.newBuilder().withPattern("%logger{-3} %m")
+                    .withConfiguration(ctx.getConfiguration()).build();
+            final LogEvent event1 = Log4jLogEvent.newBuilder()
+                    .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger")
+                    .setLevel(Level.INFO)
+                    .setMessage(new SimpleMessage("Hello, world 1!")).build();
+            final String result1 = layout.toSerializable(event1);
+            String name = this.getClass().getName().substring(this.getClass().getName().indexOf(".") + 1);
+            name = name.substring(name.indexOf(".") + 1);
+            name = name.substring(name.indexOf(".") + 1);
+            assertEquals(name + " Hello, world 1!", new String(result1));
+        }
+        {
+            final PatternLayout layout = PatternLayout.newBuilder().withPattern("%c{-20} %m")
+                    .withConfiguration(ctx.getConfiguration()).build();
+            final LogEvent event1 = Log4jLogEvent.newBuilder()
+                    .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger")
+                    .setLevel(Level.INFO)
+                    .setMessage(new SimpleMessage("Hello, world 1!")).build();
+            final String result1 = layout.toSerializable(event1);
+            assertEquals(this.getClass().getName() + " Hello, world 1!", new String(result1));
+        }
+
+    }
+
+    @Test
+    public void testCallersFqcnTruncationByDroppingPartsFromFront() throws Exception {
+        {
+            final PatternLayout layout = PatternLayout.newBuilder().withPattern("%C{-1} %m")
+                    .withConfiguration(ctx.getConfiguration()).build();
+            final LogEvent event1 = Log4jLogEvent.newBuilder()
+                    .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger")
+                    .setLevel(Level.INFO)
+                    .setMessage(new SimpleMessage("Hello, world 1!"))
+                    .setSource(new StackTraceElement(this.getClass().getName(), "testCallersFqcnTruncationByDroppingPartsFromFront", this.getClass().getCanonicalName() + ".java", 546))
+                    .build();
+            final String result1 = layout.toSerializable(event1);
+            String name = this.getClass().getName().substring(this.getClass().getName().indexOf(".") + 1);
+            assertEquals(name + " Hello, world 1!", new String(result1));
+        }
+        {
+            final PatternLayout layout = PatternLayout.newBuilder().withPattern("%C{-3} %m")
+                    .withConfiguration(ctx.getConfiguration()).build();
+            final LogEvent event1 = Log4jLogEvent.newBuilder()
+                    .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger")
+                    .setLevel(Level.INFO)
+                    .setMessage(new SimpleMessage("Hello, world 1!"))
+                    .setSource(new StackTraceElement(this.getClass().getName(), "testCallersFqcnTruncationByDroppingPartsFromFront", this.getClass().getCanonicalName() + ".java", 546))
+                    .build();
+            final String result1 = layout.toSerializable(event1);
+            String name = this.getClass().getName().substring(this.getClass().getName().indexOf(".") + 1);
+            name = name.substring(name.indexOf(".") + 1);
+            name = name.substring(name.indexOf(".") + 1);
+            assertEquals(name + " Hello, world 1!", new String(result1));
+        }
+        {
+            final PatternLayout layout = PatternLayout.newBuilder().withPattern("%class{-3} %m")
+                    .withConfiguration(ctx.getConfiguration()).build();
+            final LogEvent event1 = Log4jLogEvent.newBuilder()
+                    .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger")
+                    .setLevel(Level.INFO)
+                    .setMessage(new SimpleMessage("Hello, world 1!"))
+                    .setSource(new StackTraceElement(this.getClass().getName(), "testCallersFqcnTruncationByDroppingPartsFromFront", this.getClass().getCanonicalName() + ".java", 546))
+                    .build();
+            final String result1 = layout.toSerializable(event1);
+            String name = this.getClass().getName().substring(this.getClass().getName().indexOf(".") + 1);
+            name = name.substring(name.indexOf(".") + 1);
+            name = name.substring(name.indexOf(".") + 1);
+            assertEquals(name + " Hello, world 1!", new String(result1));
+        }
+        {
+            final PatternLayout layout = PatternLayout.newBuilder().withPattern("%C{-20} %m")
+                    .withConfiguration(ctx.getConfiguration()).build();
+            final LogEvent event1 = Log4jLogEvent.newBuilder()
+                    .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger")
+                    .setLevel(Level.INFO)
+                    .setMessage(new SimpleMessage("Hello, world 1!"))
+                    .setSource(new StackTraceElement(this.getClass().getName(), "testCallersFqcnTruncationByDroppingPartsFromFront", this.getClass().getCanonicalName() + ".java", 546))
+                    .build();
+            final String result1 = layout.toSerializable(event1);
+            assertEquals(this.getClass().getName() + " Hello, world 1!", new String(result1));
+        }
+
+    }
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/23b2b367/src/changes/changes.xml
----------------------------------------------------------------------
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 7d77dc9..77e687d 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -24,6 +24,9 @@
   </properties>
   <body>
     <release version="2.6" date="2016-MM-DD" description="GA Release 2.6">
+      <action issue="LOG4J2-621" dev="ggregory" type="add" due-to="Lee Theobald, Kamal Mettananda, Gary Gregory">
+        Pattern to drop first N package parts.
+      </action>
       <action issue="LOG4J2-494" dev="rgoers" type="add" due-to="Philipp Knobel">
         Support merging configurations to for a composite configuration.
       </action>

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/23b2b367/src/site/xdoc/manual/layouts.xml.vm
----------------------------------------------------------------------
diff --git a/src/site/xdoc/manual/layouts.xml.vm b/src/site/xdoc/manual/layouts.xml.vm
index e94e5e7..1a33b76 100644
--- a/src/site/xdoc/manual/layouts.xml.vm
+++ b/src/site/xdoc/manual/layouts.xml.vm
@@ -520,11 +520,15 @@ WARN  [main]: Message 2</pre>
                   specifier can be optionally followed by <em>precision specifier</em>, which consists of a
                   decimal integer, or a pattern starting with a decimal integer.
                 </p>
-                <p>If a precision specifier is given and it is an integer value, then only the corresponding number
-                  of right most components of the logger name will be printed. If the precision contains
-                  other non-integer characters then the name will be abbreviated based on the pattern. If the
-                  precision integer is less than one the right-most token will still be printed in full.
-                  By default the logger name is printed in full.
+                <p>When the precision specifier is an integer value, it reduces the size of the logger name. 
+                  If the number is positive, the layout prints the corresponding number of rightmost logger 
+                  name components. If negative, the layout removes the corresponding number of leftmost logger 
+                  name components.
+                </p>
+                <p>
+                   If the precision contains any non-integer characters, then the layout abbreviates the name 
+                   based on the pattern. If the precision integer is less than one, the layout still prints 
+                   the right-most token in full. By default, the layout prints the logger name in full.
                 </p>
                 <table>
                   <tr>
@@ -543,6 +547,26 @@ WARN  [main]: Message 2</pre>
                     <td>commons.Foo</td>
                   </tr>
                   <tr>
+                    <td>%c{10}</td>
+                    <td>org.apache.${break}commons.Foo</td>
+                    <td>org.apache.${break}commons.Foo</td>
+                  </tr>
+                  <tr>
+                    <td>%c{-1}</td>
+                    <td>org.apache.${break}commons.Foo</td>
+                    <td>apache.${break}commons.Foo</td>
+                  </tr>
+                  <tr>
+                    <td>%c{-2}</td>
+                    <td>org.apache.${break}commons.Foo</td>
+                    <td>${break}commons.Foo</td>
+                  </tr>
+                  <tr>
+                    <td>%c{-10}</td>
+                    <td>org.apache.${break}commons.Foo</td>
+                    <td>org.apache.${break}commons.Foo</td>
+                  </tr>
+                  <tr>
                     <td>%c{1.}</td>
                     <td>org.apache.${break}commons.Foo</td>
                     <td>o.a.c.Foo</td>