Repository: logging-log4j2
Updated Branches:
  refs/heads/master 2fe34f762 -> 6a4c88d4a


[LOG4J2-905] Ability to disable (date) lookup completely, compatibility
issues with other libraries like Camel.

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

Branch: refs/heads/master
Commit: 6a4c88d4ae85f6a70843df23e0781becc790c821
Parents: 2fe34f7
Author: Gary Gregory <ggreg...@apache.org>
Authored: Fri Aug 19 00:31:44 2016 -0700
Committer: Gary Gregory <ggreg...@apache.org>
Committed: Fri Aug 19 00:31:44 2016 -0700

----------------------------------------------------------------------
 .../core/pattern/MessagePatternConverter.java   |  45 +++++--
 .../logging/log4j/core/util/ArrayUtils.java     | 124 +++++++++++++++++++
 .../layout/PatternLayoutNoLookupDateTest.java   |  26 ++++
 .../src/test/resources/log4j-list-nolookups.xml |  29 +++++
 src/changes/changes.xml                         |   3 +
 src/site/xdoc/manual/layouts.xml.vm             |  12 +-
 6 files changed, 223 insertions(+), 16 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/6a4c88d4/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/MessagePatternConverter.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/MessagePatternConverter.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/MessagePatternConverter.java
index 75af44c..1fd2d2b 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/MessagePatternConverter.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/MessagePatternConverter.java
@@ -21,6 +21,7 @@ import java.util.Locale;
 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.util.ArrayUtils;
 import org.apache.logging.log4j.core.util.Loader;
 import org.apache.logging.log4j.message.Message;
 import org.apache.logging.log4j.message.MultiformatMessage;
@@ -34,9 +35,12 @@ import 
org.apache.logging.log4j.util.StringBuilderFormattable;
 @ConverterKeys({ "m", "msg", "message" })
 public final class MessagePatternConverter extends LogEventPatternConverter {
 
+    private static final String NOLOOKUPS = "nolookups";
+
     private final String[] formats;
     private final Configuration config;
     private final TextRenderer textRenderer;
+    private final boolean noLookups;
 
     /**
      * Private constructor.
@@ -48,22 +52,37 @@ public final class MessagePatternConverter extends 
LogEventPatternConverter {
         super("Message", "message");
         this.formats = options;
         this.config = config;
-        this.textRenderer = loadMessageRenderer(options);
+        final int noLookupsIdx = loadNoLookups(options);
+        this.noLookups = noLookupsIdx >= 0;
+        this.textRenderer = loadMessageRenderer(noLookupsIdx >= 0 ? 
ArrayUtils.remove(options, noLookupsIdx) : options);
+    }
+
+    private int loadNoLookups(String[] options) {
+        if (options != null) {
+            for (int i = 0; i < options.length; i++) {
+                final String option = options[i];
+                if (NOLOOKUPS.equalsIgnoreCase(option)) {
+                    return i;
+                }
+            }
+        }
+        return -1;
     }
 
     private TextRenderer loadMessageRenderer(String[] options) {
-        if (formats != null && formats.length > 0) {
-            final String format = formats[0].toUpperCase(Locale.ROOT);
-            switch (format) {
-            case "ANSI":
-                if (Loader.isJansiAvailable()) {
-                    return new JAnsiTextRenderer(formats, 
JAnsiTextRenderer.DefaultMessageStyleMap);
+        if (options != null) {
+            for (String option : options) {
+                switch (option.toUpperCase(Locale.ROOT)) {
+                case "ANSI":
+                    if (Loader.isJansiAvailable()) {
+                        return new JAnsiTextRenderer(options, 
JAnsiTextRenderer.DefaultMessageStyleMap);
+                    }
+                    StatusLogger.getLogger()
+                            .warn("You requested ANSI message rendering but 
JANSI is not on the classpath.");
+                    return null;
+                case "HTML":
+                    return new HtmlTextRenderer(options);
                 }
-                StatusLogger.getLogger()
-                        .warn("You requested ANSI message rendering but JANSI 
is not on the classpath.");
-                return null;
-            case "HTML":
-                return new HtmlTextRenderer(formats);
             }
         }
         return null;
@@ -98,7 +117,7 @@ public final class MessagePatternConverter extends 
LogEventPatternConverter {
             stringBuilderFormattable.formatTo(workingBuilder);
 
             // TODO can we optimize this?
-            if (config != null) {
+            if (config != null && !noLookups) {
                 for (int i = offset; i < workingBuilder.length() - 1; i++) {
                     if (workingBuilder.charAt(i) == '$' && 
workingBuilder.charAt(i + 1) == '{') {
                         final String value = workingBuilder.substring(offset, 
workingBuilder.length());

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/6a4c88d4/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ArrayUtils.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ArrayUtils.java 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ArrayUtils.java
new file mode 100644
index 0000000..bcf8d54
--- /dev/null
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ArrayUtils.java
@@ -0,0 +1,124 @@
+/*
+ * 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.util;
+
+import java.lang.reflect.Array;
+
+/**
+ * Copied from Apache Commons Lang (including the {@code @since} tags.)
+ */
+public class ArrayUtils {
+
+    /**
+     * <p>Returns the length of the specified array.
+     * This method can deal with {@code Object} arrays and with primitive 
arrays.</p>
+     *
+     * <p>If the input array is {@code null}, {@code 0} is returned.</p>
+     *
+     * <pre>
+     * ArrayUtils.getLength(null)            = 0
+     * ArrayUtils.getLength([])              = 0
+     * ArrayUtils.getLength([null])          = 1
+     * ArrayUtils.getLength([true, false])   = 2
+     * ArrayUtils.getLength([1, 2, 3])       = 3
+     * ArrayUtils.getLength(["a", "b", "c"]) = 3
+     * </pre>
+     *
+     * @param array  the array to retrieve the length from, may be null
+     * @return The length of the array, or {@code 0} if the array is {@code 
null}
+     * @throws IllegalArgumentException if the object argument is not an array.
+     * @since 2.1
+     */
+    public static int getLength(final Object array) {
+        if (array == null) {
+            return 0;
+        }
+        return Array.getLength(array);
+    }
+
+    /**
+     * <p>Removes the element at the specified position from the specified 
array.
+     * All subsequent elements are shifted to the left (subtracts one from
+     * their indices).</p>
+     *
+     * <p>This method returns a new array with the same elements of the input
+     * array except the element on the specified position. The component
+     * type of the returned array is always the same as that of the input
+     * array.</p>
+     *
+     * <p>If the input array is {@code null}, an IndexOutOfBoundsException
+     * will be thrown, because in that case no valid index can be 
specified.</p>
+     *
+     * @param array  the array to remove the element from, may not be {@code 
null}
+     * @param index  the position of the element to be removed
+     * @return A new array containing the existing elements except the element
+     *         at the specified position.
+     * @throws IndexOutOfBoundsException if the index is out of range
+     * (index &lt; 0 || index &gt;= array.length), or if the array is {@code 
null}.
+     * @since 2.1
+     */
+    private static Object remove(final Object array, final int index) {
+        final int length = getLength(array);
+        if (index < 0 || index >= length) {
+            throw new IndexOutOfBoundsException("Index: " + index + ", Length: 
" + length);
+        }
+
+        final Object result = 
Array.newInstance(array.getClass().getComponentType(), length - 1);
+        System.arraycopy(array, 0, result, 0, index);
+        if (index < length - 1) {
+            System.arraycopy(array, index + 1, result, index, length - index - 
1);
+        }
+
+        return result;
+    }
+
+    /**
+     * <p>Removes the element at the specified position from the specified 
array.
+     * All subsequent elements are shifted to the left (subtracts one from
+     * their indices).</p>
+     *
+     * <p>This method returns a new array with the same elements of the input
+     * array except the element on the specified position. The component
+     * type of the returned array is always the same as that of the input
+     * array.</p>
+     *
+     * <p>If the input array is {@code null}, an IndexOutOfBoundsException
+     * will be thrown, because in that case no valid index can be 
specified.</p>
+     *
+     * <pre>
+     * ArrayUtils.remove(["a"], 0)           = []
+     * ArrayUtils.remove(["a", "b"], 0)      = ["b"]
+     * ArrayUtils.remove(["a", "b"], 1)      = ["a"]
+     * ArrayUtils.remove(["a", "b", "c"], 1) = ["a", "c"]
+     * </pre>
+     *
+     * @param <T> the component type of the array
+     * @param array  the array to remove the element from, may not be {@code 
null}
+     * @param index  the position of the element to be removed
+     * @return A new array containing the existing elements except the element
+     *         at the specified position.
+     * @throws IndexOutOfBoundsException if the index is out of range
+     * (index &lt; 0 || index &gt;= array.length), or if the array is {@code 
null}.
+     * @since 2.1
+     */
+    @SuppressWarnings("unchecked") // remove() always creates an array of the 
same type as its input
+    public static <T> T[] remove(final T[] array, final int index) {
+        return (T[]) remove((Object) array, index);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/6a4c88d4/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutNoLookupDateTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutNoLookupDateTest.java
 
b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutNoLookupDateTest.java
new file mode 100644
index 0000000..5b2f7be
--- /dev/null
+++ 
b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutNoLookupDateTest.java
@@ -0,0 +1,26 @@
+package org.apache.logging.log4j.core.layout;
+
+import org.apache.logging.log4j.junit.LoggerContextRule;
+import org.apache.logging.log4j.test.appender.ListAppender;
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+
+/**
+ * See (LOG4J2-905) Ability to disable (date) lookup completely, compatibility 
issues with other libraries like camel.
+ */
+public class PatternLayoutNoLookupDateTest {
+
+    @Rule
+    public final LoggerContextRule context = new 
LoggerContextRule("log4j-list-nolookups.xml");
+
+    @Test
+    public void testDateLookupInMessage() {
+        final String template = "${date:YYYY-MM-dd}";
+        
context.getLogger(PatternLayoutNoLookupDateTest.class.getName()).info(template);
+        final ListAppender listAppender = context.getListAppender("List");
+        final String string = listAppender.getMessages().get(0);
+        Assert.assertTrue(string, string.contains(template));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/6a4c88d4/log4j-core/src/test/resources/log4j-list-nolookups.xml
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/resources/log4j-list-nolookups.xml 
b/log4j-core/src/test/resources/log4j-list-nolookups.xml
new file mode 100644
index 0000000..2477db7
--- /dev/null
+++ b/log4j-core/src/test/resources/log4j-list-nolookups.xml
@@ -0,0 +1,29 @@
+<?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">
+  <Appenders>
+    <List name="List">
+      <PatternLayout pattern="[%-5level] %c{1.} %msg{ansi}{nolookups}%n" />
+    </List>
+  </Appenders>
+  <Loggers>
+    <Root level="debug">
+      <AppenderRef ref="List" />
+    </Root>
+  </Loggers>
+</Configuration>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/6a4c88d4/src/changes/changes.xml
----------------------------------------------------------------------
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 0af30cc..675a24a 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -24,6 +24,9 @@
   </properties>
   <body>
     <release version="2.7" date="2016-MM-DD" description="GA Release 2.7">
+      <action issue="LOG4J2-905" dev="ggregory" type="fix" due-to="Gary 
Gregory, Moritz Löser">
+        Ability to disable (date) lookup completely, compatibility issues with 
other libraries like Camel.
+      </action>
       <action issue="LOG4J2-1526" dev="mikes" type="fix">
         Possibility to set StatusLogger destination in ConfigurationBuilder.
       </action>

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/6a4c88d4/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 8607604..69622f9 100644
--- a/src/site/xdoc/manual/layouts.xml.vm
+++ b/src/site/xdoc/manual/layouts.xml.vm
@@ -1013,9 +1013,9 @@ WARN  [main]: Message 2</pre>
             <tr>
               <td align="center">
                 <a name="PatternMessage"/>
-                <b>m</b>{ansi}<br />
-                <b>msg</b>{ansi}<br />
-                <b>message</b>{ansi}
+                <b>m</b>{nolookups}{ansi}<br />
+                <b>msg</b>{nolookups}{ansi}<br />
+                <b>message</b>{nolookups}{ansi}
               </td>
               <td>
                 <p>
@@ -1049,6 +1049,12 @@ WARN  [main]: Message 2</pre>
                   The call site can look like this:
                 </p>
                 <pre class="prettyprint linenums">logger.info("@|KeyStyle {}|@ 
= @|ValueStyle {}|@", entry.getKey(), entry.getValue());</pre>
+                <p>
+                  Use <code>{nolookups}</code> to log messages like 
<code>"${esc.d}{date:YYYY-MM-dd}"</code> 
+                  without using any lookups. Normally calling 
<code>logger.info("Try ${esc.d}{date:YYYY-MM-dd}")</code> 
+                  would replace the date template 
<code>${esc.d}{date:YYYY-MM-dd}</code> with an actual date.
+                  Using <code>nolookups</code> disables this feature and logs 
the message string untouched.
+                </p>
               </td>
             </tr>
             <tr>

Reply via email to