[LOG4J2-1146] Add %notEmpty to PatternLayout to avoid output of patterns
where all variables are empty.


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

Branch: refs/heads/LOG4J2-1136
Commit: d41f343c47bdb64c96ec9148857b529cf4da687b
Parents: b902020
Author: ggregory <[email protected]>
Authored: Fri Oct 2 11:54:39 2015 -0700
Committer: Ralph Goers <[email protected]>
Committed: Sat Oct 3 23:08:06 2015 -0700

----------------------------------------------------------------------
 .../core/pattern/LiteralPatternConverter.java   |  6 ++
 .../core/pattern/LogEventPatternConverter.java  |  4 +
 .../VariablesNotEmptyReplacementConverter.java  | 91 ++++++++++++++++++++
 ...riablesNotEmptyReplacementConverterTest.java | 78 +++++++++++++++++
 src/changes/changes.xml                         |  3 +
 src/site/xdoc/manual/layouts.xml.vm             | 17 ++++
 6 files changed, 199 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/d41f343c/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/LiteralPatternConverter.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/LiteralPatternConverter.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/LiteralPatternConverter.java
index 2722bff..0751bca 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/LiteralPatternConverter.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/LiteralPatternConverter.java
@@ -79,7 +79,13 @@ public final class LiteralPatternConverter extends 
LogEventPatternConverter impl
     }
 
     @Override
+    public boolean isVariable() {
+        return false;
+    }
+
+    @Override
     public String toString() {
         return "LiteralPatternConverter[literal=" + literal + ", config=" + 
config + ", substitute=" + substitute + "]";
     }
+    
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/d41f343c/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/LogEventPatternConverter.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/LogEventPatternConverter.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/LogEventPatternConverter.java
index d42f300..84cee32 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/LogEventPatternConverter.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/LogEventPatternConverter.java
@@ -64,4 +64,8 @@ public abstract class LogEventPatternConverter extends 
AbstractPatternConverter
     public boolean handlesThrowable() {
         return false;
     }
+
+    public boolean isVariable() {
+        return true;
+    }
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/d41f343c/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/VariablesNotEmptyReplacementConverter.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/VariablesNotEmptyReplacementConverter.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/VariablesNotEmptyReplacementConverter.java
new file mode 100644
index 0000000..ea16266
--- /dev/null
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/VariablesNotEmptyReplacementConverter.java
@@ -0,0 +1,91 @@
+/*
+ * 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 java.util.List;
+
+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;
+
+/**
+ * VariablesNotEmpty pattern converter.
+ */
+@Plugin(name = "notEmpty", category = PatternConverter.CATEGORY)
+@ConverterKeys({ "notEmpty", "varsNotEmpty", "variablesNotEmpty", })
+public final class VariablesNotEmptyReplacementConverter extends 
LogEventPatternConverter {
+
+    /**
+     * Gets an instance of the class.
+     *
+     * @param config
+     *            The current Configuration.
+     * @param options
+     *            pattern options, may be null.
+     * @return instance of class.
+     */
+    public static VariablesNotEmptyReplacementConverter newInstance(final 
Configuration config,
+            final String[] options) {
+        if (options.length != 1) {
+            LOGGER.error("Incorrect number of options on varsNotEmpty. 
Expected 1 received " + options.length);
+            return null;
+        }
+        if (options[0] == null) {
+            LOGGER.error("No pattern supplied on varsNotEmpty");
+            return null;
+        }
+        final PatternParser parser = PatternLayout.createPatternParser(config);
+        final List<PatternFormatter> formatters = parser.parse(options[0]);
+        return new VariablesNotEmptyReplacementConverter(formatters);
+    }
+
+    private final List<PatternFormatter> formatters;
+
+    /**
+     * Construct the converter.
+     * 
+     * @param formatters
+     *            The PatternFormatters to generate the text to manipulate.
+     */
+    private VariablesNotEmptyReplacementConverter(final List<PatternFormatter> 
formatters) {
+        super("notEmpty", "notEmpty");
+        this.formatters = formatters;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void format(final LogEvent event, final StringBuilder toAppendTo) {
+        final StringBuilder buf = new StringBuilder();
+        int emptyVars = 0;
+        int vars = 0;
+        for (final PatternFormatter formatter : formatters) {
+            int start = buf.length();
+            formatter.format(event, buf);
+            final boolean isVariable = formatter.getConverter().isVariable();
+            vars += isVariable ? 1 : 0;
+            if (isVariable && buf.length() - start == 0) {
+                emptyVars++;
+            }
+        }
+        if (vars > 0 && emptyVars != vars) {
+            toAppendTo.append(buf.toString());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/d41f343c/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/VariablesNotEmptyReplacementConverterTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/VariablesNotEmptyReplacementConverterTest.java
 
b/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/VariablesNotEmptyReplacementConverterTest.java
new file mode 100644
index 0000000..15be1ea
--- /dev/null
+++ 
b/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/VariablesNotEmptyReplacementConverterTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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 static org.junit.Assert.assertEquals;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.impl.Log4jLogEvent;
+import org.apache.logging.log4j.message.SimpleMessage;
+import org.apache.logging.log4j.util.Strings;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class VariablesNotEmptyReplacementConverterTest {
+
+    @Test
+    public void testMarkerReplacement() {
+        testReplacement("%marker", Strings.EMPTY);
+    }
+
+    @Test
+    public void testMultipleMarkerReplacementEmpty() {
+        testReplacement("<%marker>Foo</%marker>", Strings.EMPTY);
+    }
+
+    @Test
+    public void testMultipleMarkerReplacementSomeEmpty() {
+        testReplacement("<%marker>%msg</%marker>", "[<>This is a test</>]");
+    }
+
+    @Test
+    public void testMultipleMarkerReplacement() {
+        testReplacement("<%level>%msg</%level>", "[<DEBUG>This is a 
test</DEBUG>]");
+    }
+
+    @Test
+    public void testMarkerSimpleNameReplacement() {
+        testReplacement("%markerSimpleName", Strings.EMPTY);
+    }
+
+    @Test
+    public void testLoggerNameReplacement() {
+        testReplacement("%logger", "[" + 
VariablesNotEmptyReplacementConverterTest.class.getName() + "]");
+    }
+
+    private void testReplacement(String tag, String expectedValue) {
+        final LogEvent event = Log4jLogEvent.newBuilder() //
+                
.setLoggerName(VariablesNotEmptyReplacementConverterTest.class.getName()) //
+                .setLevel(Level.DEBUG) //
+                .setMessage(new SimpleMessage("This is a test")) //
+                .build();
+        final StringBuilder sb = new StringBuilder();
+        final LoggerContext ctx = LoggerContext.getContext();
+        final String[] options = new String[] { "[" + tag + "]" };
+        final VariablesNotEmptyReplacementConverter converter = 
VariablesNotEmptyReplacementConverter
+                .newInstance(ctx.getConfiguration(), options);
+        converter.format(event, sb);
+        assertEquals(expectedValue, sb.toString());
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/d41f343c/src/changes/changes.xml
----------------------------------------------------------------------
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index cd86147..0fa5c6e 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -33,6 +33,9 @@
       <action issue="LOG4J2-1147" dev="ggregory" type="add">
         Add %equalsIgnoreCase to PatternLayout to test and replace patterns 
with strings. 
       </action>
+      <action issue="LOG4J2-1146" dev="ggregory" type="add">
+        Add %notEmpty to PatternLayout to avoid output of patterns where all 
variables are empty.
+      </action>
       <action issue="LOG4J2-1020" dev="mikes" type="fix">
         Possibility to set shutdown timeout on AsyncAppender
       </action>

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/d41f343c/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 e1c0e12..ee1270a 100644
--- a/src/site/xdoc/manual/layouts.xml.vm
+++ b/src/site/xdoc/manual/layouts.xml.vm
@@ -995,6 +995,23 @@ WARN  [main]: Message 2</pre>
             </tr>
             <tr>
               <td align="center">
+              <a name="VariablesNotEmpty" />
+                <b>variablesNotEmpty</b>{pattern}<br />
+                <b>varsNotEmpty</b>{pattern}<br />
+                <b>notEmpty</b>{pattern}
+              </td>
+              <td>
+                <p>
+                  Outputs the result of evaluating the pattern if and only if 
all variables in the pattern are not empty.
+                </p>
+                <p>
+                  For example:
+                  <pre>%notEmpty{[%marker]}</pre>
+                </p>
+              </td>
+            </tr>
+            <tr>
+              <td align="center">
                 <b>p</b>|<b>level</b>{<em>level</em>=<em>label</em>, 
<em>level</em>=<em>label</em>, ...}
                 <b>p</b>|<b>level</b>{length=<em>n</em>}
                 <b>p</b>|<b>level</b>{lowerCase=<em>true</em>|<em>false</em>}

Reply via email to