Repository: logging-log4j2 Updated Branches: refs/heads/master 91b599e7b -> 61e7a5427
Better error reporting. Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/61e7a542 Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/61e7a542 Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/61e7a542 Branch: refs/heads/master Commit: 61e7a542793b0be05264805d75266bd050fd4519 Parents: 91b599e Author: Gary Gregory <[email protected]> Authored: Fri Sep 23 17:50:57 2016 -0700 Committer: Gary Gregory <[email protected]> Committed: Fri Sep 23 17:50:57 2016 -0700 ---------------------------------------------------------------------- .../apache/log4j/config/InputStreamWrapper.java | 92 +++ .../config/Log4j1ConfigurationConverter.java | 4 +- .../log4j/config/Log4j1ConfigurationParser.java | 615 ++++++++++--------- 3 files changed, 403 insertions(+), 308 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/61e7a542/log4j-1.2-api/src/main/java/org/apache/log4j/config/InputStreamWrapper.java ---------------------------------------------------------------------- diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/config/InputStreamWrapper.java b/log4j-1.2-api/src/main/java/org/apache/log4j/config/InputStreamWrapper.java new file mode 100644 index 0000000..29ea51a --- /dev/null +++ b/log4j-1.2-api/src/main/java/org/apache/log4j/config/InputStreamWrapper.java @@ -0,0 +1,92 @@ +/* + * 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.log4j.config; + +import java.io.IOException; +import java.io.InputStream; + +class InputStreamWrapper extends InputStream { + + private final String description; + private final InputStream input; + + public InputStreamWrapper(final InputStream input, final String description) { + this.input = input; + this.description = description; + } + + @Override + public int available() throws IOException { + return input.available(); + } + + @Override + public void close() throws IOException { + input.close(); + } + + @Override + public boolean equals(final Object obj) { + return input.equals(obj); + } + + @Override + public int hashCode() { + return input.hashCode(); + } + + @Override + public void mark(final int readlimit) { + input.mark(readlimit); + } + + @Override + public boolean markSupported() { + return input.markSupported(); + } + + @Override + public int read() throws IOException { + return input.read(); + } + + @Override + public int read(final byte[] b) throws IOException { + return input.read(b); + } + + @Override + public int read(final byte[] b, final int off, final int len) throws IOException { + return input.read(b, off, len); + } + + @Override + public synchronized void reset() throws IOException { + input.reset(); + } + + @Override + public long skip(final long n) throws IOException { + return input.skip(n); + } + + @Override + public String toString() { + return getClass().getSimpleName() + " [description=" + description + ", input=" + input + "]"; + } + +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/61e7a542/log4j-1.2-api/src/main/java/org/apache/log4j/config/Log4j1ConfigurationConverter.java ---------------------------------------------------------------------- diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/config/Log4j1ConfigurationConverter.java b/log4j-1.2-api/src/main/java/org/apache/log4j/config/Log4j1ConfigurationConverter.java index c9c8bc5..e48e54c 100644 --- a/log4j-1.2-api/src/main/java/org/apache/log4j/config/Log4j1ConfigurationConverter.java +++ b/log4j-1.2-api/src/main/java/org/apache/log4j/config/Log4j1ConfigurationConverter.java @@ -142,7 +142,7 @@ public final class Log4j1ConfigurationConverter { } InputStream getInputStream() throws IOException { - return cla.pathIn == null ? System.in : Files.newInputStream(cla.pathIn); + return cla.pathIn == null ? System.in : new InputStreamWrapper(Files.newInputStream(cla.pathIn), cla.pathIn.toString()); } OutputStream getOutputStream() throws IOException { @@ -165,7 +165,7 @@ public final class Log4j1ConfigurationConverter { newFile = lastIndex < 0 ? newFile + FILE_EXT_XML : newFile.substring(0, lastIndex) + FILE_EXT_XML; final Path resolved = file.resolveSibling(newFile); - try (final InputStream input = Files.newInputStream(file); + try (final InputStream input = new InputStreamWrapper(Files.newInputStream(file), file.toString()); final OutputStream output = Files.newOutputStream(resolved)) { try { convert(input, output); http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/61e7a542/log4j-1.2-api/src/main/java/org/apache/log4j/config/Log4j1ConfigurationParser.java ---------------------------------------------------------------------- diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/config/Log4j1ConfigurationParser.java b/log4j-1.2-api/src/main/java/org/apache/log4j/config/Log4j1ConfigurationParser.java index 16ab9c5..da9bc8f 100644 --- a/log4j-1.2-api/src/main/java/org/apache/log4j/config/Log4j1ConfigurationParser.java +++ b/log4j-1.2-api/src/main/java/org/apache/log4j/config/Log4j1ConfigurationParser.java @@ -48,30 +48,26 @@ import org.apache.logging.log4j.status.StatusLogger; * From the Log4j 1.2 Javadocs: * </p> * <p> - * All option values admit variable substitution. The syntax of variable - * substitution is similar to that of Unix shells. The string between an opening - * "${" and closing "}" is interpreted as a key. The value of the substituted - * variable can be defined as a system property or in the configuration file - * itself. The value of the key is first searched in the system properties, and - * if not found there, it is then searched in the configuration file being - * parsed. The corresponding value replaces the ${variableName} sequence. For - * example, if java.home system property is set to /home/xyz, then every - * occurrence of the sequence ${java.home} will be interpreted as /home/xyz. + * All option values admit variable substitution. The syntax of variable substitution is similar to that of Unix shells. The string between + * an opening "${" and closing "}" is interpreted as a key. The value of the substituted variable can be defined as a system property or in + * the configuration file itself. The value of the key is first searched in the system properties, and if not found there, it is then + * searched in the configuration file being parsed. The corresponding value replaces the ${variableName} sequence. For example, if java.home + * system property is set to /home/xyz, then every occurrence of the sequence ${java.home} will be interpreted as /home/xyz. * </p> */ public class Log4j1ConfigurationParser { - private static final String ROOTLOGGER = "rootLogger"; - private static final String ROOTCATEGORY = "rootCategory"; - private static final String TRUE = "true"; - private static final String FALSE = "false"; - - private final Properties properties = new Properties(); - private StrSubstitutor strSubstitutorProperties; - private StrSubstitutor strSubstitutorSystem; - - private final ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory - .newConfigurationBuilder(); + private static final String ROOTLOGGER = "rootLogger"; + private static final String ROOTCATEGORY = "rootCategory"; + private static final String TRUE = "true"; + private static final String FALSE = "false"; + + private final Properties properties = new Properties(); + private StrSubstitutor strSubstitutorProperties; + private StrSubstitutor strSubstitutorSystem; + + private final ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory + .newConfigurationBuilder(); /** * Parses a Log4j 1.2 properties configuration file in ISO 8859-1 encoding into a ConfigurationBuilder. @@ -84,7 +80,7 @@ public class Log4j1ConfigurationParser { * @throws ConfigurationException * if the input does not contain a valid configuration */ - public ConfigurationBuilder<BuiltConfiguration> buildConfigurationBuilder(final InputStream input) + public ConfigurationBuilder<BuiltConfiguration> buildConfigurationBuilder(final InputStream input) throws IOException { try { properties.load(input); @@ -94,8 +90,9 @@ public class Log4j1ConfigurationParser { final String rootLoggerValue = getLog4jValue(ROOTLOGGER); if (rootCategoryValue == null && rootLoggerValue == null) { // This is not a Log4j 1 properties configuration file. - throw new ConfigurationException( - "Input does not contain a valid Log4j 1.x properties configuration: " + input); + warn("Missing " + ROOTCATEGORY + " or " + ROOTLOGGER + " in " + input); + // throw new ConfigurationException( + // "Missing " + ROOTCATEGORY + " or " + ROOTLOGGER + " in " + input); } builder.setConfigurationName("Log4j1"); // DEBUG @@ -124,288 +121,294 @@ public class Log4j1ConfigurationParser { } } - private Map<String, String> buildClassToPropertyPrefixMap(final String[] sortedAppenderNames) { - final String prefix = "log4j.appender."; - final int preLength = prefix.length(); - final Map<String, String> map = new HashMap<>(sortedAppenderNames.length); - for (final Map.Entry<Object, Object> entry : properties.entrySet()) { - final Object keyObj = entry.getKey(); - if (keyObj != null) { - final String key = keyObj.toString(); - if (key.startsWith(prefix)) { - if (key.indexOf('.', preLength) < 0) { - final String name = key.substring(preLength); - if (Arrays.binarySearch(sortedAppenderNames, name) >= 0) { - final Object value = entry.getValue(); - if (value != null) { - map.put(name, value.toString()); - } - } - } - } - } - } - return map; - } - - private void buildAppender(final String appenderName, final String appenderClass) { - switch (appenderClass) { - case "org.apache.log4j.ConsoleAppender": - buildConsoleAppender(appenderName); - break; - case "org.apache.log4j.FileAppender": - buildFileAppender(appenderName); - break; - case "org.apache.log4j.DailyRollingFileAppender": - buildDailyRollingFileAppender(appenderName); - break; - case "org.apache.log4j.RollingFileAppender": - buildRollingFileAppender(appenderName); - break; - case "org.apache.log4j.varia.NullAppender": - buildNullAppender(appenderName); - break; - default: - reportWarning("Unknown appender class: " + appenderClass + "; ignoring appender: " + appenderName); - } - } - - private void buildConsoleAppender(final String appenderName) { - final AppenderComponentBuilder appenderBuilder = builder.newAppender(appenderName, ConsoleAppender.PLUGIN_NAME); - final String targetValue = getLog4jAppenderValue(appenderName, "Target", "System.out"); - if (targetValue != null) { - final ConsoleAppender.Target target; - switch (targetValue) { - case "System.out": - target = ConsoleAppender.Target.SYSTEM_OUT; - break; - case "System.err": - target = ConsoleAppender.Target.SYSTEM_ERR; - break; - default: - reportWarning("Unknown value for console Target: " + targetValue); - target = null; - } - if (target != null) { - appenderBuilder.addAttribute("target", target); - } - } - buildAttribute(appenderName, appenderBuilder, "Follow", "follow"); - if (FALSE.equalsIgnoreCase(getLog4jAppenderValue(appenderName, "ImmediateFlush"))) { - reportWarning("ImmediateFlush=false is not supported on Console appender"); - } - buildAppenderLayout(appenderName, appenderBuilder); - builder.add(appenderBuilder); - } - - private void buildFileAppender(final String appenderName) { - final AppenderComponentBuilder appenderBuilder = builder.newAppender(appenderName, FileAppender.PLUGIN_NAME); - buildFileAppender(appenderName, appenderBuilder); - builder.add(appenderBuilder); - } - - private void buildFileAppender(final String appenderName, final AppenderComponentBuilder appenderBuilder) { - buildMandatoryAttribute(appenderName, appenderBuilder, "File", "fileName"); - buildAttribute(appenderName, appenderBuilder, "Append", "append"); - buildAttribute(appenderName, appenderBuilder, "BufferedIO", "bufferedIo"); - buildAttribute(appenderName, appenderBuilder, "BufferSize", "bufferSize"); - buildAttribute(appenderName, appenderBuilder, "ImmediateFlush", "immediateFlush"); - buildAppenderLayout(appenderName, appenderBuilder); - } - - private void buildDailyRollingFileAppender(final String appenderName) { - final AppenderComponentBuilder appenderBuilder = builder.newAppender(appenderName, RollingFileAppender.PLUGIN_NAME); - buildFileAppender(appenderName, appenderBuilder); - final String fileName = getLog4jAppenderValue(appenderName, "File"); - final String datePattern = getLog4jAppenderValue(appenderName, "DatePattern", fileName + "'.'yyyy-MM-dd"); - appenderBuilder.addAttribute("filePattern", fileName + "%d{" + datePattern + "}"); - final ComponentBuilder<?> triggeringPolicy = builder.newComponent("Policies").addComponent( - builder.newComponent("TimeBasedTriggeringPolicy").addAttribute("modulate", true)); - appenderBuilder.addComponent(triggeringPolicy); - appenderBuilder.addComponent( - builder.newComponent("DefaultRolloverStrategy").addAttribute("max", Integer.MAX_VALUE)); - builder.add(appenderBuilder); - } - - private void buildRollingFileAppender(final String appenderName) { - final AppenderComponentBuilder appenderBuilder = builder.newAppender(appenderName, RollingFileAppender.PLUGIN_NAME); - buildFileAppender(appenderName, appenderBuilder); - final String fileName = getLog4jAppenderValue(appenderName, "File"); - appenderBuilder.addAttribute("filePattern", fileName + ".%i"); - final String maxFileSizeString = getLog4jAppenderValue(appenderName, "MaxFileSize", "10485760"); - final String maxBackupIndexString = getLog4jAppenderValue(appenderName, "MaxBackupIndex", "1"); - final ComponentBuilder<?> triggeringPolicy = builder.newComponent("Policies").addComponent( - builder.newComponent("SizeBasedTriggeringPolicy").addAttribute("size", maxFileSizeString)); - appenderBuilder.addComponent(triggeringPolicy); - appenderBuilder.addComponent( - builder.newComponent("DefaultRolloverStrategy").addAttribute("max", maxBackupIndexString)); - builder.add(appenderBuilder); - } - - private void buildAttribute(final String componentName, final ComponentBuilder componentBuilder, - final String sourceAttributeName, final String targetAttributeName) { - final String attributeValue = getLog4jAppenderValue(componentName, sourceAttributeName); - if (attributeValue != null) { - componentBuilder.addAttribute(targetAttributeName, attributeValue); - } - } - - private void buildAttributeWithDefault(final String componentName, final ComponentBuilder componentBuilder, - final String sourceAttributeName, final String targetAttributeName, final String defaultValue) { - final String attributeValue = getLog4jAppenderValue(componentName, sourceAttributeName, defaultValue); - componentBuilder.addAttribute(targetAttributeName, attributeValue); - } - - private void buildMandatoryAttribute(final String componentName, final ComponentBuilder componentBuilder, - final String sourceAttributeName, final String targetAttributeName) { - final String attributeValue = getLog4jAppenderValue(componentName, sourceAttributeName); - if (attributeValue != null) { - componentBuilder.addAttribute(targetAttributeName, attributeValue); - } else { - reportWarning("Missing " + sourceAttributeName + " for " + componentName); - } - } - - private void buildNullAppender(String appenderName) { - final AppenderComponentBuilder appenderBuilder = builder.newAppender(appenderName, NullAppender.PLUGIN_NAME); - builder.add(appenderBuilder); - } - - private void buildAppenderLayout(final String name, final AppenderComponentBuilder appenderBuilder) { - final String layoutClass = getLog4jAppenderValue(name, "layout", null); - if (layoutClass != null) { - switch (layoutClass) { - case "org.apache.log4j.PatternLayout": - case "org.apache.log4j.EnhancedPatternLayout": { - final String pattern = getLog4jAppenderValue(name, "layout.ConversionPattern", null) - - // Log4j 2's %x (NDC) is not compatible with Log4j 1's - // %x - // Log4j 1: "foo bar baz" - // Log4j 2: "[foo, bar, baz]" - // Use %ndc to get the Log4j 1 format - .replace("%x", "%ndc") - - // Log4j 2's %X (MDC) is not compatible with Log4j 1's - // %X - // Log4j 1: "{{foo,bar}{hoo,boo}}" - // Log4j 2: "{foo=bar,hoo=boo}" - // Use %properties to get the Log4j 1 format - .replace("%X", "%properties"); - - appenderBuilder.add(newPatternLayout(pattern)); - break; - } - case "org.apache.log4j.SimpleLayout": { - appenderBuilder.add(newPatternLayout("%level - %m%n")); - break; - } - case "org.apache.log4j.TTCCLayout": { - String pattern = "%r "; - if (Boolean.parseBoolean(getLog4jAppenderValue(name, "layout.ThreadPrinting", TRUE))) { - pattern += "[%t] "; - } - pattern += "%p "; - if (Boolean.parseBoolean(getLog4jAppenderValue(name, "layout.CategoryPrefixing", TRUE))) { - pattern += "%c "; - } - if (Boolean.parseBoolean(getLog4jAppenderValue(name, "layout.ContextPrinting", TRUE))) { - pattern += "%notEmpty{%ndc }"; - } - pattern += "- %m%n"; - appenderBuilder.add(newPatternLayout(pattern)); - break; - } - case "org.apache.log4j.HTMLLayout": { - final LayoutComponentBuilder htmlLayout = builder.newLayout("HtmlLayout"); - htmlLayout.addAttribute("title", getLog4jAppenderValue(name, "layout.Title", "Log4J Log Messages")); - htmlLayout.addAttribute("locationInfo", - Boolean.parseBoolean(getLog4jAppenderValue(name, "layout.LocationInfo", FALSE))); - appenderBuilder.add(htmlLayout); - break; - } - case "org.apache.log4j.xml.XMLLayout": { - final LayoutComponentBuilder xmlLayout = builder.newLayout("Log4j1XmlLayout"); - xmlLayout.addAttribute("locationInfo", - Boolean.parseBoolean(getLog4jAppenderValue(name, "layout.LocationInfo", FALSE))); - xmlLayout.addAttribute("properties", - Boolean.parseBoolean(getLog4jAppenderValue(name, "layout.Properties", FALSE))); - appenderBuilder.add(xmlLayout); - break; - } - default: - reportWarning("Unknown layout class: " + layoutClass); - } - } - } - - private LayoutComponentBuilder newPatternLayout(final String pattern) { - final LayoutComponentBuilder layoutBuilder = builder.newLayout("PatternLayout"); - if (pattern != null) { - layoutBuilder.addAttribute("pattern", pattern); - } - return layoutBuilder; - } - - private String[] buildRootLogger(final String rootLoggerValue) { - if (rootLoggerValue == null) { - return new String[0]; - } - final String[] rootLoggerParts = rootLoggerValue.split("\\s*,\\s*"); - final Level rootLoggerLevel = rootLoggerParts.length > 0 ? Level.valueOf(rootLoggerParts[0]) : Level.ERROR; - final String[] sortedAppenderNames = Arrays.copyOfRange(rootLoggerParts, 1, rootLoggerParts.length); - Arrays.sort(sortedAppenderNames); - final RootLoggerComponentBuilder loggerBuilder = builder.newRootLogger(rootLoggerLevel); - for (final String appender : sortedAppenderNames) { - loggerBuilder.add(builder.newAppenderRef(appender)); - } - builder.add(loggerBuilder); - return sortedAppenderNames; - } - - private void buildLoggers(final String prefix) { - final int preLength = prefix.length(); - for (final Map.Entry<Object, Object> entry : properties.entrySet()) { - final Object keyObj = entry.getKey(); - if (keyObj != null) { - final String key = keyObj.toString(); - if (key.startsWith(prefix)) { - final String name = key.substring(preLength); - final Object value = entry.getValue(); - if (value != null) { - builder.add(builder.newLogger(name, Level.valueOf(value.toString()))); - } - } - } - } - } - - private String getLog4jAppenderValue(final String appenderName, final String attributeName) { - return getProperty("log4j.appender." + appenderName + "." + attributeName); - } - - private String getProperty(final String key) { - final String value = properties.getProperty(key); - final String sysValue = strSubstitutorSystem.replace(value); - return strSubstitutorProperties.replace(sysValue); - } - - private String getProperty(final String key, String defaultValue) { - final String value = getProperty(key); - return value == null ? defaultValue : value; - } - - private String getLog4jAppenderValue(final String appenderName, final String attributeName, - final String defaultValue) { - return getProperty("log4j.appender." + appenderName + "." + attributeName, defaultValue); - } - - private String getLog4jValue(final String key) { - return getProperty("log4j." + key); - } - - private void reportWarning(final String msg) { - StatusLogger.getLogger().warn("Log4j 1 configuration parser: " + msg); - } + private void warn(String string) { + System.err.println(string); + } + + private Map<String, String> buildClassToPropertyPrefixMap(final String[] sortedAppenderNames) { + final String prefix = "log4j.appender."; + final int preLength = prefix.length(); + final Map<String, String> map = new HashMap<>(sortedAppenderNames.length); + for (final Map.Entry<Object, Object> entry : properties.entrySet()) { + final Object keyObj = entry.getKey(); + if (keyObj != null) { + final String key = keyObj.toString(); + if (key.startsWith(prefix)) { + if (key.indexOf('.', preLength) < 0) { + final String name = key.substring(preLength); + if (Arrays.binarySearch(sortedAppenderNames, name) >= 0) { + final Object value = entry.getValue(); + if (value != null) { + map.put(name, value.toString()); + } + } + } + } + } + } + return map; + } + + private void buildAppender(final String appenderName, final String appenderClass) { + switch (appenderClass) { + case "org.apache.log4j.ConsoleAppender": + buildConsoleAppender(appenderName); + break; + case "org.apache.log4j.FileAppender": + buildFileAppender(appenderName); + break; + case "org.apache.log4j.DailyRollingFileAppender": + buildDailyRollingFileAppender(appenderName); + break; + case "org.apache.log4j.RollingFileAppender": + buildRollingFileAppender(appenderName); + break; + case "org.apache.log4j.varia.NullAppender": + buildNullAppender(appenderName); + break; + default: + reportWarning("Unknown appender class: " + appenderClass + "; ignoring appender: " + appenderName); + } + } + + private void buildConsoleAppender(final String appenderName) { + final AppenderComponentBuilder appenderBuilder = builder.newAppender(appenderName, ConsoleAppender.PLUGIN_NAME); + final String targetValue = getLog4jAppenderValue(appenderName, "Target", "System.out"); + if (targetValue != null) { + final ConsoleAppender.Target target; + switch (targetValue) { + case "System.out": + target = ConsoleAppender.Target.SYSTEM_OUT; + break; + case "System.err": + target = ConsoleAppender.Target.SYSTEM_ERR; + break; + default: + reportWarning("Unknown value for console Target: " + targetValue); + target = null; + } + if (target != null) { + appenderBuilder.addAttribute("target", target); + } + } + buildAttribute(appenderName, appenderBuilder, "Follow", "follow"); + if (FALSE.equalsIgnoreCase(getLog4jAppenderValue(appenderName, "ImmediateFlush"))) { + reportWarning("ImmediateFlush=false is not supported on Console appender"); + } + buildAppenderLayout(appenderName, appenderBuilder); + builder.add(appenderBuilder); + } + + private void buildFileAppender(final String appenderName) { + final AppenderComponentBuilder appenderBuilder = builder.newAppender(appenderName, FileAppender.PLUGIN_NAME); + buildFileAppender(appenderName, appenderBuilder); + builder.add(appenderBuilder); + } + + private void buildFileAppender(final String appenderName, final AppenderComponentBuilder appenderBuilder) { + buildMandatoryAttribute(appenderName, appenderBuilder, "File", "fileName"); + buildAttribute(appenderName, appenderBuilder, "Append", "append"); + buildAttribute(appenderName, appenderBuilder, "BufferedIO", "bufferedIo"); + buildAttribute(appenderName, appenderBuilder, "BufferSize", "bufferSize"); + buildAttribute(appenderName, appenderBuilder, "ImmediateFlush", "immediateFlush"); + buildAppenderLayout(appenderName, appenderBuilder); + } + + private void buildDailyRollingFileAppender(final String appenderName) { + final AppenderComponentBuilder appenderBuilder = builder.newAppender(appenderName, + RollingFileAppender.PLUGIN_NAME); + buildFileAppender(appenderName, appenderBuilder); + final String fileName = getLog4jAppenderValue(appenderName, "File"); + final String datePattern = getLog4jAppenderValue(appenderName, "DatePattern", fileName + "'.'yyyy-MM-dd"); + appenderBuilder.addAttribute("filePattern", fileName + "%d{" + datePattern + "}"); + final ComponentBuilder<?> triggeringPolicy = builder.newComponent("Policies") + .addComponent(builder.newComponent("TimeBasedTriggeringPolicy").addAttribute("modulate", true)); + appenderBuilder.addComponent(triggeringPolicy); + appenderBuilder + .addComponent(builder.newComponent("DefaultRolloverStrategy").addAttribute("max", Integer.MAX_VALUE)); + builder.add(appenderBuilder); + } + + private void buildRollingFileAppender(final String appenderName) { + final AppenderComponentBuilder appenderBuilder = builder.newAppender(appenderName, + RollingFileAppender.PLUGIN_NAME); + buildFileAppender(appenderName, appenderBuilder); + final String fileName = getLog4jAppenderValue(appenderName, "File"); + appenderBuilder.addAttribute("filePattern", fileName + ".%i"); + final String maxFileSizeString = getLog4jAppenderValue(appenderName, "MaxFileSize", "10485760"); + final String maxBackupIndexString = getLog4jAppenderValue(appenderName, "MaxBackupIndex", "1"); + final ComponentBuilder<?> triggeringPolicy = builder.newComponent("Policies").addComponent( + builder.newComponent("SizeBasedTriggeringPolicy").addAttribute("size", maxFileSizeString)); + appenderBuilder.addComponent(triggeringPolicy); + appenderBuilder.addComponent( + builder.newComponent("DefaultRolloverStrategy").addAttribute("max", maxBackupIndexString)); + builder.add(appenderBuilder); + } + + private void buildAttribute(final String componentName, final ComponentBuilder componentBuilder, + final String sourceAttributeName, final String targetAttributeName) { + final String attributeValue = getLog4jAppenderValue(componentName, sourceAttributeName); + if (attributeValue != null) { + componentBuilder.addAttribute(targetAttributeName, attributeValue); + } + } + + private void buildAttributeWithDefault(final String componentName, final ComponentBuilder componentBuilder, + final String sourceAttributeName, final String targetAttributeName, final String defaultValue) { + final String attributeValue = getLog4jAppenderValue(componentName, sourceAttributeName, defaultValue); + componentBuilder.addAttribute(targetAttributeName, attributeValue); + } + + private void buildMandatoryAttribute(final String componentName, final ComponentBuilder componentBuilder, + final String sourceAttributeName, final String targetAttributeName) { + final String attributeValue = getLog4jAppenderValue(componentName, sourceAttributeName); + if (attributeValue != null) { + componentBuilder.addAttribute(targetAttributeName, attributeValue); + } else { + reportWarning("Missing " + sourceAttributeName + " for " + componentName); + } + } + + private void buildNullAppender(String appenderName) { + final AppenderComponentBuilder appenderBuilder = builder.newAppender(appenderName, NullAppender.PLUGIN_NAME); + builder.add(appenderBuilder); + } + + private void buildAppenderLayout(final String name, final AppenderComponentBuilder appenderBuilder) { + final String layoutClass = getLog4jAppenderValue(name, "layout", null); + if (layoutClass != null) { + switch (layoutClass) { + case "org.apache.log4j.PatternLayout": + case "org.apache.log4j.EnhancedPatternLayout": { + final String pattern = getLog4jAppenderValue(name, "layout.ConversionPattern", null) + + // Log4j 2's %x (NDC) is not compatible with Log4j 1's + // %x + // Log4j 1: "foo bar baz" + // Log4j 2: "[foo, bar, baz]" + // Use %ndc to get the Log4j 1 format + .replace("%x", "%ndc") + + // Log4j 2's %X (MDC) is not compatible with Log4j 1's + // %X + // Log4j 1: "{{foo,bar}{hoo,boo}}" + // Log4j 2: "{foo=bar,hoo=boo}" + // Use %properties to get the Log4j 1 format + .replace("%X", "%properties"); + + appenderBuilder.add(newPatternLayout(pattern)); + break; + } + case "org.apache.log4j.SimpleLayout": { + appenderBuilder.add(newPatternLayout("%level - %m%n")); + break; + } + case "org.apache.log4j.TTCCLayout": { + String pattern = "%r "; + if (Boolean.parseBoolean(getLog4jAppenderValue(name, "layout.ThreadPrinting", TRUE))) { + pattern += "[%t] "; + } + pattern += "%p "; + if (Boolean.parseBoolean(getLog4jAppenderValue(name, "layout.CategoryPrefixing", TRUE))) { + pattern += "%c "; + } + if (Boolean.parseBoolean(getLog4jAppenderValue(name, "layout.ContextPrinting", TRUE))) { + pattern += "%notEmpty{%ndc }"; + } + pattern += "- %m%n"; + appenderBuilder.add(newPatternLayout(pattern)); + break; + } + case "org.apache.log4j.HTMLLayout": { + final LayoutComponentBuilder htmlLayout = builder.newLayout("HtmlLayout"); + htmlLayout.addAttribute("title", getLog4jAppenderValue(name, "layout.Title", "Log4J Log Messages")); + htmlLayout.addAttribute("locationInfo", + Boolean.parseBoolean(getLog4jAppenderValue(name, "layout.LocationInfo", FALSE))); + appenderBuilder.add(htmlLayout); + break; + } + case "org.apache.log4j.xml.XMLLayout": { + final LayoutComponentBuilder xmlLayout = builder.newLayout("Log4j1XmlLayout"); + xmlLayout.addAttribute("locationInfo", + Boolean.parseBoolean(getLog4jAppenderValue(name, "layout.LocationInfo", FALSE))); + xmlLayout.addAttribute("properties", + Boolean.parseBoolean(getLog4jAppenderValue(name, "layout.Properties", FALSE))); + appenderBuilder.add(xmlLayout); + break; + } + default: + reportWarning("Unknown layout class: " + layoutClass); + } + } + } + + private LayoutComponentBuilder newPatternLayout(final String pattern) { + final LayoutComponentBuilder layoutBuilder = builder.newLayout("PatternLayout"); + if (pattern != null) { + layoutBuilder.addAttribute("pattern", pattern); + } + return layoutBuilder; + } + + private String[] buildRootLogger(final String rootLoggerValue) { + if (rootLoggerValue == null) { + return new String[0]; + } + final String[] rootLoggerParts = rootLoggerValue.split("\\s*,\\s*"); + final Level rootLoggerLevel = rootLoggerParts.length > 0 ? Level.valueOf(rootLoggerParts[0]) : Level.ERROR; + final String[] sortedAppenderNames = Arrays.copyOfRange(rootLoggerParts, 1, rootLoggerParts.length); + Arrays.sort(sortedAppenderNames); + final RootLoggerComponentBuilder loggerBuilder = builder.newRootLogger(rootLoggerLevel); + for (final String appender : sortedAppenderNames) { + loggerBuilder.add(builder.newAppenderRef(appender)); + } + builder.add(loggerBuilder); + return sortedAppenderNames; + } + + private void buildLoggers(final String prefix) { + final int preLength = prefix.length(); + for (final Map.Entry<Object, Object> entry : properties.entrySet()) { + final Object keyObj = entry.getKey(); + if (keyObj != null) { + final String key = keyObj.toString(); + if (key.startsWith(prefix)) { + final String name = key.substring(preLength); + final Object value = entry.getValue(); + if (value != null) { + builder.add(builder.newLogger(name, Level.valueOf(value.toString()))); + } + } + } + } + } + + private String getLog4jAppenderValue(final String appenderName, final String attributeName) { + return getProperty("log4j.appender." + appenderName + "." + attributeName); + } + + private String getProperty(final String key) { + final String value = properties.getProperty(key); + final String sysValue = strSubstitutorSystem.replace(value); + return strSubstitutorProperties.replace(sysValue); + } + + private String getProperty(final String key, String defaultValue) { + final String value = getProperty(key); + return value == null ? defaultValue : value; + } + + private String getLog4jAppenderValue(final String appenderName, final String attributeName, + final String defaultValue) { + return getProperty("log4j.appender." + appenderName + "." + attributeName, defaultValue); + } + + private String getLog4jValue(final String key) { + return getProperty("log4j." + key); + } + + private void reportWarning(final String msg) { + StatusLogger.getLogger().warn("Log4j 1 configuration parser: " + msg); + } }
