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 2020/02/16 07:38:36 UTC
[logging-log4j2] branch master updated: LOG4J2-2211 - Allow Lookup
keys with leading dashes by using a slash as an escape character.
This is an automated email from the ASF dual-hosted git repository.
rgoers pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
The following commit(s) were added to refs/heads/master by this push:
new 19aa7fd LOG4J2-2211 - Allow Lookup keys with leading dashes by using a slash as an escape character.
19aa7fd is described below
commit 19aa7fd40606d728471953890f86c9ae4d88ea5b
Author: Ralph Goers <rg...@apache.org>
AuthorDate: Sun Feb 16 00:38:18 2020 -0700
LOG4J2-2211 - Allow Lookup keys with leading dashes by using a slash as an escape character.
---
.../logging/log4j/core/lookup/Interpolator.java | 6 +-
.../logging/log4j/core/lookup/MainMapLookup.java | 8 ++-
.../logging/log4j/core/lookup/StrSubstitutor.java | 75 +++++++++++++++++++---
...pTest.java => MainInputArgumentsLookupApp.java} | 4 +-
.../logging/log4j/core/lookup/MainLookupTest.java | 56 ++++++++++++++++
src/changes/changes.xml | 3 +
src/site/asciidoc/manual/configuration.adoc | 6 ++
src/site/asciidoc/manual/lookups.adoc | 13 +++-
8 files changed, 154 insertions(+), 17 deletions(-)
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/Interpolator.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/Interpolator.java
index 7003e3f..446d57b 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/Interpolator.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/Interpolator.java
@@ -36,6 +36,9 @@ import org.apache.logging.log4j.util.Constants;
*/
public class Interpolator extends AbstractConfigurationAwareLookup {
+ /** Constant for the prefix separator. */
+ public static final char PREFIX_SEPARATOR = ':';
+
private static final String LOOKUP_KEY_WEB = "web";
private static final String LOOKUP_KEY_DOCKER = "docker";
@@ -50,9 +53,6 @@ public class Interpolator extends AbstractConfigurationAwareLookup {
private static final Logger LOGGER = StatusLogger.getLogger();
- /** Constant for the prefix separator. */
- private static final char PREFIX_SEPARATOR = ':';
-
private final Map<String, StrLookup> strLookupMap = new HashMap<>();
private final StrLookup defaultLookup;
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/MainMapLookup.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/MainMapLookup.java
index adddd53..df8d8a4 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/MainMapLookup.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/MainMapLookup.java
@@ -64,9 +64,13 @@ public class MainMapLookup extends MapLookup {
* Second using the argument at position n as the key to access the value at n+1.
* </p>
* <ul>
- * <li>{@code "main:--file"} = {@code "path/file.txt"}</li>
- * <li>{@code "main:-x"} = {@code "2"}</li>
+ * <li>{@code "main:\--file"} = {@code "path/file.txt"}</li>
+ * <li>{@code "main:\-x"} = {@code "2"}</li>
* </ul>
+ *<p>Note: Many applications use leading dashes to identify command arguments. Specifying {@code "main:--file}
+ * would result in the lookup failing because it would look for a variable named "main" with a default
+ * value of "-file". To avoid this the ":" separating the Lookup name from the key must be followed by
+ * a backslash as an escape character.</p>
*
* @param args
* An application's {@code public static main(String[])} arguments.
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/StrSubstitutor.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/StrSubstitutor.java
index 405ca28..33fc535 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/StrSubstitutor.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/StrSubstitutor.java
@@ -158,7 +158,11 @@ public class StrSubstitutor implements ConfigurationAware {
/**
* Constant for the default value delimiter of a variable.
*/
- public static final StrMatcher DEFAULT_VALUE_DELIMITER = StrMatcher.stringMatcher(":-");
+ public static final String DEFAULT_VALUE_DELIMITER_STRING = ":-";
+ public static final StrMatcher DEFAULT_VALUE_DELIMITER = StrMatcher.stringMatcher(DEFAULT_VALUE_DELIMITER_STRING);
+
+ public static final String ESCAPE_DELIMITER_STRING = ":\\-";
+ public static final StrMatcher DEFAULT_VALUE_ESCAPE_DELIMITER = StrMatcher.stringMatcher(ESCAPE_DELIMITER_STRING);
private static final int BUF_SIZE = 256;
@@ -180,9 +184,15 @@ public class StrSubstitutor implements ConfigurationAware {
/**
* Stores the default variable value delimiter
*/
+ private String valueDelimiterString;
private StrMatcher valueDelimiterMatcher;
/**
+ * Escape string to avoid matching the value delimiter matcher;
+ */
+ private StrMatcher valueEscapeDelimiterMatcher;
+
+ /**
* Variable resolution is delegated to an implementer of VariableResolver.
*/
private StrLookup variableResolver;
@@ -323,7 +333,28 @@ public class StrSubstitutor implements ConfigurationAware {
public StrSubstitutor(final StrLookup variableResolver, final StrMatcher prefixMatcher,
final StrMatcher suffixMatcher,
final char escape) {
- this(variableResolver, prefixMatcher, suffixMatcher, escape, DEFAULT_VALUE_DELIMITER);
+ this(variableResolver, prefixMatcher, suffixMatcher, escape, DEFAULT_VALUE_DELIMITER,
+ DEFAULT_VALUE_ESCAPE_DELIMITER);
+ this.valueDelimiterString = DEFAULT_VALUE_DELIMITER_STRING;
+ }
+
+ /**
+ * Creates a new instance and initializes it.
+ *
+ * @param variableResolver the variable resolver, may be null
+ * @param prefixMatcher the prefix for variables, not null
+ * @param suffixMatcher the suffix for variables, not null
+ * @param escape the escape character
+ * @param valueDelimiterMatcher the variable default value delimiter matcher, may be null
+ * @throws IllegalArgumentException if the prefix or suffix is null
+ */
+ public StrSubstitutor(final StrLookup variableResolver, final StrMatcher prefixMatcher,
+ final StrMatcher suffixMatcher, final char escape, final StrMatcher valueDelimiterMatcher) {
+ this.setVariableResolver(variableResolver);
+ this.setVariablePrefixMatcher(prefixMatcher);
+ this.setVariableSuffixMatcher(suffixMatcher);
+ this.setEscapeChar(escape);
+ this.setValueDelimiterMatcher(valueDelimiterMatcher);
}
/**
@@ -334,15 +365,18 @@ public class StrSubstitutor implements ConfigurationAware {
* @param suffixMatcher the suffix for variables, not null
* @param escape the escape character
* @param valueDelimiterMatcher the variable default value delimiter matcher, may be null
+ * @param valueEscapeMatcher the matcher to escape defaulting, may be null.
* @throws IllegalArgumentException if the prefix or suffix is null
*/
- public StrSubstitutor(
- final StrLookup variableResolver, final StrMatcher prefixMatcher, final StrMatcher suffixMatcher, final char escape, final StrMatcher valueDelimiterMatcher) {
+ public StrSubstitutor(final StrLookup variableResolver, final StrMatcher prefixMatcher,
+ final StrMatcher suffixMatcher, final char escape, final StrMatcher valueDelimiterMatcher,
+ final StrMatcher valueEscapeMatcher) {
this.setVariableResolver(variableResolver);
this.setVariablePrefixMatcher(prefixMatcher);
this.setVariableSuffixMatcher(suffixMatcher);
this.setEscapeChar(escape);
this.setValueDelimiterMatcher(valueDelimiterMatcher);
+ valueEscapeDelimiterMatcher = valueEscapeMatcher;
}
//-----------------------------------------------------------------------
@@ -960,10 +994,32 @@ public class StrSubstitutor implements ConfigurationAware {
&& prefixMatcher.isMatch(varNameExprChars, i, i, varNameExprChars.length) != 0) {
break;
}
- if ((valueDelimiterMatchLen = valueDelimiterMatcher.isMatch(varNameExprChars, i)) != 0) {
- varName = varNameExpr.substring(0, i);
- varDefaultValue = varNameExpr.substring(i + valueDelimiterMatchLen);
- break;
+ if (valueEscapeDelimiterMatcher != null) {
+ int matchLen = valueEscapeDelimiterMatcher.isMatch(varNameExprChars, i);
+ if (matchLen != 0) {
+ String varNamePrefix = varNameExpr.substring(0, i) + Interpolator.PREFIX_SEPARATOR;
+ varName = varNamePrefix + varNameExpr.substring(i + matchLen - 1);
+ for (int j = i + matchLen; j < varNameExprChars.length; ++j){
+ if ((valueDelimiterMatchLen = valueDelimiterMatcher.isMatch(varNameExprChars, j)) != 0) {
+ varName = varNamePrefix + varNameExpr.substring(i + matchLen, j);
+ varDefaultValue = varNameExpr.substring(j + valueDelimiterMatchLen);
+ break;
+ }
+ }
+ break;
+ } else {
+ if ((valueDelimiterMatchLen = valueDelimiterMatcher.isMatch(varNameExprChars, i)) != 0) {
+ varName = varNameExpr.substring(0, i);
+ varDefaultValue = varNameExpr.substring(i + valueDelimiterMatchLen);
+ break;
+ }
+ }
+ } else {
+ if ((valueDelimiterMatchLen = valueDelimiterMatcher.isMatch(varNameExprChars, i)) != 0) {
+ varName = varNameExpr.substring(0, i);
+ varDefaultValue = varNameExpr.substring(i + valueDelimiterMatchLen);
+ break;
+ }
}
}
}
@@ -1294,6 +1350,9 @@ public class StrSubstitutor implements ConfigurationAware {
setValueDelimiterMatcher(null);
return this;
}
+ String escapeValue = valueDelimiter.substring(0, valueDelimiter.length() - 1) + "\\"
+ + valueDelimiter.substring(valueDelimiter.length() - 1);
+ valueEscapeDelimiterMatcher = StrMatcher.stringMatcher(escapeValue);
return setValueDelimiterMatcher(StrMatcher.stringMatcher(valueDelimiter));
}
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/MainInputArgumentsLookupTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/MainInputArgumentsLookupApp.java
similarity index 94%
rename from log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/MainInputArgumentsLookupTest.java
rename to log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/MainInputArgumentsLookupApp.java
index 6150afd..ddb8b8f 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/MainInputArgumentsLookupTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/MainInputArgumentsLookupApp.java
@@ -28,11 +28,11 @@ import org.apache.logging.log4j.core.config.Configurator;
*
* @since 2.4
*/
-public class MainInputArgumentsLookupTest {
+public class MainInputArgumentsLookupApp {
public static void main(final String[] args) {
MainMapLookup.setMainArguments(args);
- try (final LoggerContext ctx = Configurator.initialize(MainInputArgumentsLookupTest.class.getName(),
+ try (final LoggerContext ctx = Configurator.initialize(MainInputArgumentsLookupApp.class.getName(),
"target/test-classes/log4j-lookup-main.xml")) {
LogManager.getLogger().error("this is an error message");
}
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/MainLookupTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/MainLookupTest.java
new file mode 100644
index 0000000..b019c2a
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/lookup/MainLookupTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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.lookup;
+
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests MainLookup.
+ */
+public class MainLookupTest {
+
+ @Test
+ public void testMainArgs(){
+ MainMapLookup.setMainArguments("--file", "foo.txt", "--verbose", "-x", "bar");
+ String str ="${key} ${main:-1} ${main:0} ${main:1} ${main:2} ${main:3} ${main:4} ${main:\\--file} ${main:foo.txt} ${main:\\--verbose} ${main:\\-x} ${main:bar} ${main:\\--quiet:-true}";
+ Map<String, String> properties = new HashMap<String, String>();
+ properties.put("key", "value");
+ properties.put("bar", "default_bar_value");
+ Interpolator lookup = new Interpolator(properties);
+ StrSubstitutor substitutor = new StrSubstitutor(lookup);
+ String replacedValue = substitutor.replace(null, str);
+ String[] values = replacedValue.split(" ");
+ assertEquals("Item 0 is incorrect ", "value", values[0]);
+ assertEquals("Item 1 is incorrect ", "1", values[1]);
+ assertEquals("Item 2 is incorrect", "--file", values[2]);
+ assertEquals("Item 3 is incorrect", "foo.txt", values[3]);
+ assertEquals("Item 4 is incorrect", "--verbose", values[4]);
+ assertEquals("Item 5 is incorrect", "-x", values[5]);
+ assertEquals("Iten 6 is incorrect", "bar", values[6]);
+ assertEquals("Item 7 is incorrect", "foo.txt", values[7]);
+ assertEquals("Item 8 is incorrect", "--verbose", values[8]);
+ assertEquals("Item 9 is incorrect", "-x", values[9]);
+ assertEquals("Item 10 is incorrect", "bar", values[10]);
+ assertEquals("Item 11 is incorrect", "default_bar_value", values[11]);
+ assertEquals("Item 12 is incorrect", "true", values[12]);
+ }
+}
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 2b02b02..24d73f0 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -166,6 +166,9 @@
</action>
</release>
<release version="2.13.1" date="2019-MM-DD" description="GA Release 2.13.1">
+ <action issue="LOG4J2-2211" dev="rgoers" type="fix">
+ Allow Lookup keys with leading dashes by using a slash as an escape character.
+ </action>
<action issue="LOG4J2-2782" dev="rgoers" type="update">
Use LinkedBlockingQueue instead of synchronized collction in StatusConfiguration.
</action>
diff --git a/src/site/asciidoc/manual/configuration.adoc b/src/site/asciidoc/manual/configuration.adoc
index 0a466c1..82c4a3e 100644
--- a/src/site/asciidoc/manual/configuration.adoc
+++ b/src/site/asciidoc/manual/configuration.adoc
@@ -1127,6 +1127,12 @@ for "hostName" that is the current system's host name or IP address and
the "contextName" with is the value of the current logging context. See many places
a Properties element is used in this section for examples.
+Default properties may also be specified in the Lookup by using the syntax `${lookupName:key:-defaultValue}`.
+In some cases the key might contain a leading '-'. When this is the case an escape character must be
+included, such as ``${main:\--file:-app.properties}`. This would use the
+`MainMapLookup` for a key named `--file`. If the key is not found then
+<code>app.properties</code> would be used as the default value.
+
[#RuntimeLookup]
== Lookup Variables with Multiple Leading '$' Characters
diff --git a/src/site/asciidoc/manual/lookups.adoc b/src/site/asciidoc/manual/lookups.adoc
index 5585b1a..1efc99a 100644
--- a/src/site/asciidoc/manual/lookups.adoc
+++ b/src/site/asciidoc/manual/lookups.adoc
@@ -331,6 +331,11 @@ configuration. The key that follows the `main:` prefix can either be a
`${main:myString}` is substituted with the value that follows `myString`
in the main argument list.
+Note: Many applications use leading dashes to identify command arguments. Specifying
+`${main:--file}` would result in the lookup failing because it would look for a variable
+named "main" with a default value of "-file". To avoid this the ":" separating the Lookup name from the
+key must be followed by a backslash as an escape character as in `${main:\--file}`.
+
For example, suppose the static void main String[] arguments are:
....
@@ -358,16 +363,20 @@ Then the following substitutions are possible:
|${main:4}
|bar
-|${main:--file}
+|${main:\--file}
|foo.txt
-|${main:-x}
+|${main:\-x}
|bar
|${main:bar}
|null
|===
+|${main:\--quiet:-true}
+|true
+|===
+
Example usage:
[source,xml]