You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by ma...@apache.org on 2017/02/04 09:13:11 UTC

logging-log4j2 git commit: [LOG4J2-1431]: Provide support for simplified global configuration environment

Repository: logging-log4j2
Updated Branches:
  refs/heads/LOG4J2-1431 [created] bd587cf4e


[LOG4J2-1431]: Provide support for simplified global configuration environment

This provides the base support for implementing simplified property names along with environment variable support.


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

Branch: refs/heads/LOG4J2-1431
Commit: bd587cf4e514a62ecd3852e6f1182feeed049fdc
Parents: 8cf9e4f
Author: Matt Sicker <bo...@gmail.com>
Authored: Sat Feb 4 03:12:58 2017 -0600
Committer: Matt Sicker <bo...@gmail.com>
Committed: Sat Feb 4 03:12:58 2017 -0600

----------------------------------------------------------------------
 .../logging/log4j/util/PropertiesUtil.java      | 138 +++++++++++++++++--
 1 file changed, 128 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/bd587cf4/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java
index 16b9ef6..c57d1f9 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java
@@ -25,6 +25,8 @@ import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
  * <em>Consider this class private.</em>
@@ -37,7 +39,7 @@ public final class PropertiesUtil {
 
     private static final PropertiesUtil LOG4J_PROPERTIES = new PropertiesUtil("log4j2.component.properties");
 
-    private final Properties props;
+    private final Environment environment;
 
     /**
      * Constructs a PropertiesUtil using a given Properties object as its source of defined properties.
@@ -45,7 +47,7 @@ public final class PropertiesUtil {
      * @param props the Properties to use by default
      */
     public PropertiesUtil(final Properties props) {
-        this.props = props;
+        this.environment = new Environment(props);
     }
 
     /**
@@ -63,7 +65,7 @@ public final class PropertiesUtil {
                 LowLevelLogUtil.logException("Unable to read " + url.toString(), ioe);
             }
         }
-        this.props = properties;
+        this.environment = new Environment(properties);
     }
 
     /**
@@ -211,13 +213,7 @@ public final class PropertiesUtil {
      * @return the String value of the property or {@code null} if undefined.
      */
     public String getStringProperty(final String name) {
-        String prop = null;
-        try {
-            prop = System.getProperty(name);
-        } catch (final SecurityException ignored) {
-            // Ignore
-        }
-        return prop == null ? props.getProperty(name) : prop;
+        return environment.get(name);
     }
 
     /**
@@ -248,6 +244,128 @@ public final class PropertiesUtil {
     }
 
     /**
+     * Provides support for looking up global configuration properties via environment variables, property files,
+     * and system properties, in three variations:
+     *
+     * Normalized: all log4j-related prefixes removed, remaining property is camelCased with a log4j2 prefix for
+     * property files and system properties, or follows a LOG4J_FOO_BAR format for environment variables.
+     *
+     * Legacy: the original property name as defined in the source pre-2.9.
+     *
+     * Tokenized: loose matching based on word boundaries.
+     */
+    private static class Environment {
+
+        private static final String NORMALIZED_PREFIX = "log4j2.";
+        private static final String PREFIXES = "(?:[Ll]og4j2?|org\\.apache\\.logging\\.log4j\\.)?";
+        private static final Pattern PROPERTY_TOKENIZER = Pattern.compile(PREFIXES + "([A-Z]*[a-z0-9]+)[-._/]?");
+
+        private final Map<String, String> literal = new ConcurrentHashMap<>();
+        private final Map<String, String> normalized = new ConcurrentHashMap<>();
+        private final Map<List<CharSequence>, String> tokenized = new ConcurrentHashMap<>();
+
+        private Environment(final Properties props) {
+            for (final Map.Entry<String, String> entry : System.getenv().entrySet()) {
+                final String envKey = entry.getKey();
+                final String value = entry.getValue();
+                if (envKey.startsWith("LOG4J_")) {
+                    final String key = envKey.substring(6);
+                    literal.put(key, value);
+                    final List<CharSequence> tokens = tokenize(envKey);
+                    if (!tokens.isEmpty()) {
+                        tokenized.put(tokens, value);
+                        normalized.put("LOG4J" + joinAsAllCapsUnderscored(tokens), value);
+                    }
+                }
+            }
+            for (final Map.Entry<Object, Object> entry : props.entrySet()) {
+                final String key = (String) entry.getKey();
+                final String value = (String) entry.getValue();
+                literal.put(key, value);
+                final List<CharSequence> tokens = tokenize(key);
+                if (tokens.isEmpty()) {
+                    normalized.put(NORMALIZED_PREFIX + key, value);
+                } else {
+                    tokenized.put(tokens, value);
+                    normalized.put(NORMALIZED_PREFIX + joinAsCamelCase(tokens), value);
+                }
+
+            }
+            final Properties systemProperties = getSystemProperties();
+            for (Map.Entry<Object, Object> entry : systemProperties.entrySet()) {
+                final String key = (String) entry.getKey();
+                final String value = (String) entry.getValue();
+                literal.put(key, value);
+                // TODO: should this include tokenized lookups? could get screwy
+                final List<CharSequence> tokens = tokenize(key);
+                if (tokens.isEmpty()) {
+                    normalized.put(NORMALIZED_PREFIX + key, value);
+                } else {
+                    tokenized.put(tokens, value);
+                    normalized.put(NORMALIZED_PREFIX + joinAsCamelCase(tokens), value);
+                }
+            }
+        }
+
+        private static CharSequence joinAsAllCapsUnderscored(final List<CharSequence> tokens) {
+            final StringBuilder sb = new StringBuilder();
+            for (final CharSequence token : tokens) {
+                sb.append('_');
+                for (int i = 0; i < token.length(); i++) {
+                    sb.append(Character.toUpperCase(token.charAt(i)));
+                }
+            }
+            return sb.toString();
+        }
+
+        private static CharSequence joinAsCamelCase(final List<CharSequence> tokens) {
+            final StringBuilder sb = new StringBuilder();
+            boolean first = true;
+            for (final CharSequence token : tokens) {
+                if (first) {
+                    sb.append(token);
+                } else {
+                    sb.append(Character.toUpperCase(token.charAt(0)));
+                    if (token.length() > 1) {
+                        sb.append(token.subSequence(1, token.length()));
+                    }
+                }
+                first = false;
+            }
+            return sb.toString();
+        }
+
+        private static List<CharSequence> tokenize(final CharSequence value) {
+            // TODO: cache?
+            List<CharSequence> tokens = new ArrayList<>();
+            final Matcher matcher = PROPERTY_TOKENIZER.matcher(value);
+            while (matcher.find()) {
+                tokens.add(matcher.group(1).toLowerCase());
+            }
+            return tokens;
+        }
+
+        private String get(final String key) {
+            if (normalized.containsKey(key)) {
+                return normalized.get(key);
+            }
+            if (literal.containsKey(key)) {
+                return literal.get(key);
+            }
+            String prop = null;
+            try {
+                prop = System.getProperty(key);
+            } catch (final SecurityException ignored) {
+                // Ignore
+            }
+            if (prop != null) {
+                return prop;
+            }
+            return tokenized.get(tokenize(key));
+        }
+    }
+
+    /**
      * Extracts properties that start with or are equals to the specific prefix and returns them in a new Properties
      * object with the prefix removed.
      *