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/10/14 17:20:17 UTC
[04/15] logging-log4j2 git commit: [LOG4J2-1431]: Provide support for
simplified global configuration environment
[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/6744c8c9
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/6744c8c9
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/6744c8c9
Branch: refs/heads/master
Commit: 6744c8c9172667e0473bb8ac0c755f1d85986903
Parents: 17e7053
Author: Matt Sicker <bo...@gmail.com>
Authored: Sat Feb 4 03:12:58 2017 -0600
Committer: Matt Sicker <ma...@spr.com>
Committed: Sat Aug 26 15:50:56 2017 -0500
----------------------------------------------------------------------
.../logging/log4j/util/PropertiesUtil.java | 138 +++++++++++++++++--
1 file changed, 128 insertions(+), 10 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/6744c8c9/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 66270a5..b760076 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
@@ -26,6 +26,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>
@@ -38,7 +40,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.
@@ -46,7 +48,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);
}
/**
@@ -64,7 +66,7 @@ public final class PropertiesUtil {
LowLevelLogUtil.logException("Unable to read " + url.toString(), ioe);
}
}
- this.props = properties;
+ this.environment = new Environment(properties);
}
/**
@@ -241,13 +243,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);
}
/**
@@ -278,6 +274,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.
*