You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by mi...@apache.org on 2016/03/11 15:23:40 UTC
[11/21] logging-log4j2 git commit: [LOG4J2-63] Support configuration
from version 1.x log4j.properties. A start, with the ConsoleAppender.
[LOG4J2-63] Support configuration from version 1.x log4j.properties. A
start, with the ConsoleAppender.
Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/9371266e
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/9371266e
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/9371266e
Branch: refs/heads/gelf-layout-gc-free
Commit: 9371266e5f2afb2df8eee6721f372b0894f7c9c8
Parents: 2ccf95d
Author: ggregory <gg...@apache.org>
Authored: Wed Mar 9 00:20:15 2016 -0800
Committer: ggregory <gg...@apache.org>
Committed: Wed Mar 9 00:20:15 2016 -0800
----------------------------------------------------------------------
.../config/Log4j1ConfigurationFactory.java | 296 +++++++++++++++++++
.../config/Log4j1ConfigurationFactoryTest.java | 60 ++++
.../log4j-console-PatternLayout.properties | 19 ++
.../log4j-console-SimpleLayout.properties | 18 ++
4 files changed, 393 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/9371266e/log4j-1.2-api/src/main/java/org/apache/log4j/config/Log4j1ConfigurationFactory.java
----------------------------------------------------------------------
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/config/Log4j1ConfigurationFactory.java b/log4j-1.2-api/src/main/java/org/apache/log4j/config/Log4j1ConfigurationFactory.java
new file mode 100644
index 0000000..470a3fe
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/config/Log4j1ConfigurationFactory.java
@@ -0,0 +1,296 @@
+/*
+ * 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;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.core.appender.ConsoleAppender;
+import org.apache.logging.log4j.core.appender.ConsoleAppender.Target;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.config.ConfigurationSource;
+import org.apache.logging.log4j.core.config.builder.api.AppenderComponentBuilder;
+import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
+import org.apache.logging.log4j.core.config.builder.api.LayoutComponentBuilder;
+import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
+import org.apache.logging.log4j.status.StatusLogger;
+
+/**
+ * Experimental ConfigurationFactory for Log4j 1.2 properties files.
+ * <p>
+ * Currently supports:
+ * </p>
+ * <ul>
+ * <li>log4j.debug</li>
+ * <li>log4j.rootLogger</li>
+ * <li>log4j.logger</li>
+ * <li>log4j.appender</li>
+ * <li>org.apache.log4j.ConsoleAppender</li>
+ * <li>org.apache.log4j.PatternLayout</li>
+ * <ul>
+ * <li>Follow</li>
+ * <li>Target</li>
+ * <li>layout = org.apache.log4j.PatternLayout</li>
+ * <li>layout = org.apache.log4j.SimpleLayout</li>
+ * <li>layout.ConversionPattern</li>
+ * </ul>
+ * </ul>
+ */
+// TODO
+// @Plugin(name = "Log4j1ConfigurationFactory", category = ConfigurationFactory.CATEGORY)
+//
+// Best Value?
+// @Order(50)
+public class Log4j1ConfigurationFactory extends ConfigurationFactory {
+
+ private Map<String, String> buildClassToPropertyPrefixMap(final Properties properties,
+ final String[] sortedAppenderNames) {
+ final String prefix = "log4j.appender.";
+ final int preLength = prefix.length();
+ final Map<String, String> map = new HashMap<>(sortedAppenderNames.length);
+ for (final 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 buildConsoleAppender(final Properties properties, final String name,
+ final ConfigurationBuilder<BuiltConfiguration> builder) {
+ final AppenderComponentBuilder appenderBuilder = builder.newAppender(name, "CONSOLE");
+ buildConsoleAppenderTarget(properties, name, builder, appenderBuilder);
+ buildConsoleAppenderLayout(properties, name, builder, appenderBuilder);
+ buildConsoleAppenderFollow(properties, name, builder, appenderBuilder);
+ builder.add(appenderBuilder);
+ }
+
+ private void buildConsoleAppenderLayout(final Properties properties, final String name,
+ final ConfigurationBuilder<BuiltConfiguration> builder, final AppenderComponentBuilder appenderBuilder) {
+ final String layoutValue = getLog4jAppenderValue(properties, name, "layout", null);
+ if (layoutValue != null) {
+ final String cpValue = getLog4jAppenderValue(properties, name, "layout.ConversionPattern", null);
+ switch (layoutValue) {
+ case "org.apache.log4j.PatternLayout": {
+ final LayoutComponentBuilder layoutBuilder = newPatternLayout(builder, cpValue);
+ appenderBuilder.add(layoutBuilder);
+ break;
+ }
+ case "org.apache.log4j.SimpleLayout": {
+ final LayoutComponentBuilder layoutBuilder = newPatternLayout(builder, "%level - %m%n");
+ appenderBuilder.add(layoutBuilder);
+ break;
+ }
+ default:
+ reportWarning("Unsupported value for console appender layout: " + layoutValue);
+ }
+ }
+ }
+
+ private LayoutComponentBuilder newPatternLayout(final ConfigurationBuilder<BuiltConfiguration> builder,
+ final String pattern) {
+ final LayoutComponentBuilder layoutBuilder = builder.newLayout("PatternLayout");
+ if (pattern != null) {
+ layoutBuilder.addAttribute("pattern", pattern);
+ }
+ return layoutBuilder;
+ }
+
+ private void buildConsoleAppenderTarget(final Properties properties, final String name,
+ final ConfigurationBuilder<BuiltConfiguration> builder, final AppenderComponentBuilder appenderBuilder) {
+ final String value = getLog4jAppenderValue(properties, name, "Target", "System.out");
+ if (value != null) {
+ final Target target;
+ switch (value) {
+ case "System.out":
+ target = ConsoleAppender.Target.SYSTEM_OUT;
+ break;
+ case "System.err":
+ target = ConsoleAppender.Target.SYSTEM_ERR;
+ break;
+ default:
+ reportWarning("Unknow value for console Target: " + value);
+ target = null;
+ }
+ if (target != null) {
+ appenderBuilder.addAttribute("target", target);
+ }
+ }
+ }
+
+ private void buildConsoleAppenderFollow(final Properties properties, final String name,
+ final ConfigurationBuilder<BuiltConfiguration> builder, final AppenderComponentBuilder appenderBuilder) {
+ final String value = getLog4jAppenderValue(properties, name, "Follow", "false");
+ if (value != null) {
+ appenderBuilder.addAttribute("follow", Boolean.valueOf(value).booleanValue());
+ }
+ }
+
+ Configuration createConfiguration(final String configName, final URI configLocation,
+ final ConfigurationBuilder<BuiltConfiguration> builder) throws IOException {
+ builder.setConfigurationName(configName);
+ final Properties properties = load(configLocation);
+ if (properties == null) {
+ return null;
+ }
+ // DEBUG
+ final String debugValue = getLog4jValue(properties, "debug");
+ if (Boolean.valueOf(debugValue)) {
+ builder.setStatusLevel(Level.DEBUG);
+ }
+ // Root
+ final String[] sortedAppenderNamesC = buildRootLogger(builder, getRootCategoryValue(properties));
+ final String[] sortedAppenderNamesL = buildRootLogger(builder, getRootLoggerValue(properties));
+ final String[] sortedAppenderNames = sortedAppenderNamesL.length > 0 ? sortedAppenderNamesL
+ : sortedAppenderNamesC;
+ // Appenders
+ final Map<String, String> classNameToProperty = buildClassToPropertyPrefixMap(properties, sortedAppenderNames);
+ for (final Entry<String, String> entry : classNameToProperty.entrySet()) {
+ final String appenderName = entry.getKey();
+ switch (entry.getValue()) {
+ case "org.apache.log4j.ConsoleAppender":
+ buildConsoleAppender(properties, appenderName, builder);
+ break;
+ default:
+ reportWarning("Ignoring appender " + appenderName
+ + "; consider porting your configuration file to the current Log4j format.");
+ }
+ }
+ // Loggers
+ buildLoggers(properties, "log4j.category.", builder);
+ buildLoggers(properties, "log4j.logger.", builder);
+ return builder.build();
+ }
+
+ private String[] buildRootLogger(final ConfigurationBuilder<BuiltConfiguration> builder,
+ 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;
+ builder.add(builder.newRootLogger(rootLoggerLevel));
+ final String[] sortedAppenderNames = Arrays.copyOfRange(rootLoggerParts, 1, rootLoggerParts.length);
+ Arrays.sort(sortedAppenderNames);
+ return sortedAppenderNames;
+ }
+
+ private void buildLoggers(final Properties properties, final String prefix,
+ final ConfigurationBuilder<BuiltConfiguration> builder) {
+ final int preLength = prefix.length();
+ for (final 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())));
+ }
+ }
+ }
+ }
+
+ }
+
+ @Override
+ public Configuration getConfiguration(final ConfigurationSource source) {
+ return getConfiguration(source.toString(), null);
+ }
+
+ @Override
+ public Configuration getConfiguration(final String name, final URI configLocation) {
+ try {
+ return createConfiguration(name, configLocation, newConfigurationBuilder());
+ } catch (final IOException e) {
+ StatusLogger.getLogger().error(e);
+ return null;
+ }
+ }
+
+ private String getLog4jAppenderValue(final Properties properties, final String appenderName,
+ final String attributeName, final String defaultValue) {
+ return properties.getProperty("log4j.appender." + appenderName + "." + attributeName, defaultValue);
+ }
+
+ private String getLog4jValue(final Properties properties, final String key) {
+ return properties.getProperty("log4j." + key);
+ }
+
+ private String getRootCategoryValue(final Properties properties) {
+ return getLog4jValue(properties, "rootCategory");
+ }
+
+ private String getRootLoggerValue(final Properties properties) {
+ return getLog4jValue(properties, "rootLogger");
+ }
+
+ @Override
+ protected String[] getSupportedTypes() {
+ return new String[] { "*.properties", ".xml" };
+ }
+
+ private Properties load(final URI uri) throws IOException {
+ final Properties properties = toProperties(uri);
+ final String rootCategoryValue = getRootCategoryValue(properties);
+ final String rootLoggerValue = getRootLoggerValue(properties);
+ if (rootCategoryValue == null && rootLoggerValue == null) {
+ // This is not a Log4j 1 properties file.
+ return null;
+ }
+ return properties;
+ }
+
+ private void reportWarning(final String msg) {
+ StatusLogger.getLogger().warn("Log4j version 1 to 2 configuration bridge: " + msg);
+
+ }
+
+ private Properties toProperties(final URI uri) throws IOException {
+ final Properties properties;
+ try (InputStream in = uri.toURL().openStream()) {
+ properties = new Properties();
+ if (uri.toString().endsWith(".xml")) {
+ properties.loadFromXML(in);
+ } else {
+ properties.load(in);
+ }
+ }
+ return properties;
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/9371266e/log4j-1.2-api/src/test/java/org/apache/log4j/config/Log4j1ConfigurationFactoryTest.java
----------------------------------------------------------------------
diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/config/Log4j1ConfigurationFactoryTest.java b/log4j-1.2-api/src/test/java/org/apache/log4j/config/Log4j1ConfigurationFactoryTest.java
new file mode 100644
index 0000000..13bcdc2
--- /dev/null
+++ b/log4j-1.2-api/src/test/java/org/apache/log4j/config/Log4j1ConfigurationFactoryTest.java
@@ -0,0 +1,60 @@
+/*
+ * 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.net.URL;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.core.appender.ConsoleAppender;
+import org.apache.logging.log4j.core.appender.ConsoleAppender.Target;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.LoggerConfig;
+import org.apache.logging.log4j.core.layout.PatternLayout;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class Log4j1ConfigurationFactoryTest {
+
+ private void testConsole(final String configResource, final String expectedPattern) throws Exception {
+ final URL configLocation = ClassLoader.getSystemResource(configResource);
+ Assert.assertNotNull(configLocation);
+ final Configuration configuration = new Log4j1ConfigurationFactory().getConfiguration("test",
+ configLocation.toURI());
+ Assert.assertNotNull(configuration);
+ final ConsoleAppender appender = configuration.getAppender("Console");
+ Assert.assertNotNull(appender);
+ // Can't set ImmediateFlush for a Console Appender in Log4j 2 like you can in 1.2
+ Assert.assertTrue(appender.getImmediateFlush());
+ Assert.assertEquals(Target.SYSTEM_ERR, appender.getTarget());
+ final PatternLayout layout = (PatternLayout) appender.getLayout();
+ Assert.assertEquals(expectedPattern, layout.getConversionPattern());
+ //
+ final LoggerConfig loggerConfig = configuration.getLoggerConfig("com.example.foo");
+ Assert.assertNotNull(loggerConfig);
+ Assert.assertEquals(Level.DEBUG, loggerConfig.getLevel());
+ }
+
+ @Test
+ public void testConsolePatternLayout() throws Exception {
+ testConsole("config-1.2/log4j-console-PatternLayout.properties", "%d{ISO8601} [%t][%c] %-5p: %m%n");
+ }
+
+ @Test
+ public void testConsoleSimpleLayout() throws Exception {
+ testConsole("config-1.2/log4j-console-SimpleLayout.properties", "%level - %m%n");
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/9371266e/log4j-1.2-api/src/test/resources/config-1.2/log4j-console-PatternLayout.properties
----------------------------------------------------------------------
diff --git a/log4j-1.2-api/src/test/resources/config-1.2/log4j-console-PatternLayout.properties b/log4j-1.2-api/src/test/resources/config-1.2/log4j-console-PatternLayout.properties
new file mode 100644
index 0000000..fab7070
--- /dev/null
+++ b/log4j-1.2-api/src/test/resources/config-1.2/log4j-console-PatternLayout.properties
@@ -0,0 +1,19 @@
+###############################################################################
+#
+# Log4J 1.2 Configuration.
+#
+
+log4j.rootLogger=TRACE, Console
+
+##############################################################################
+#
+# The Console log
+#
+
+log4j.appender.Console=org.apache.log4j.ConsoleAppender
+log4j.appender.Console.ImmediateFlush=false
+log4j.appender.Console.Target=System.err
+log4j.appender.Console.layout=org.apache.log4j.PatternLayout
+log4j.appender.Console.layout.ConversionPattern=%d{ISO8601} [%t][%c] %-5p: %m%n
+
+log4j.logger.com.example.foo = DEBUG
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/9371266e/log4j-1.2-api/src/test/resources/config-1.2/log4j-console-SimpleLayout.properties
----------------------------------------------------------------------
diff --git a/log4j-1.2-api/src/test/resources/config-1.2/log4j-console-SimpleLayout.properties b/log4j-1.2-api/src/test/resources/config-1.2/log4j-console-SimpleLayout.properties
new file mode 100644
index 0000000..5e915f8
--- /dev/null
+++ b/log4j-1.2-api/src/test/resources/config-1.2/log4j-console-SimpleLayout.properties
@@ -0,0 +1,18 @@
+###############################################################################
+#
+# Log4J 1.2 Configuration.
+#
+
+log4j.rootLogger=TRACE, Console
+
+##############################################################################
+#
+# The Console log
+#
+
+log4j.appender.Console=org.apache.log4j.ConsoleAppender
+log4j.appender.Console.ImmediateFlush=false
+log4j.appender.Console.Target=System.err
+log4j.appender.Console.layout=org.apache.log4j.SimpleLayout
+
+log4j.logger.com.example.foo = DEBUG