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 2019/11/21 04:27:32 UTC
[logging-log4j2] branch release-2.x updated: LOG4J2-63 Add
AsyncAppender
This is an automated email from the ASF dual-hosted git repository.
rgoers pushed a commit to branch release-2.x
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
View the commit online:
https://github.com/apache/logging-log4j2/commit/8193ab7004696bbb64038bf1b3400a614bbc7991
The following commit(s) were added to refs/heads/release-2.x by this push:
new 8193ab7 LOG4J2-63 Add AsyncAppender
8193ab7 is described below
commit 8193ab7004696bbb64038bf1b3400a614bbc7991
Author: Ralph Goers <rg...@apache.org>
AuthorDate: Wed Nov 20 21:27:09 2019 -0700
LOG4J2-63 Add AsyncAppender
---
.../org/apache/log4j/builders/AbstractBuilder.java | 64 +++++++-
.../builders/appender/AsyncAppenderBuilder.java | 170 +++++++++++++++++++++
.../builders/appender/ConsoleAppenderBuilder.java | 80 ++++++----
.../appender/DailyRollingFileAppenderBuilder.java | 30 ++--
.../builders/appender/FileAppenderBuilder.java | 32 ++--
.../appender/RollingFileAppenderBuilder.java | 27 ++--
.../apache/log4j/config/Log4j1Configuration.java | 2 +
.../org/apache/log4j/xml/XmlConfiguration.java | 11 +-
.../org/apache/log4j/config/AsyncAppenderTest.java | 103 +++++++++++++
.../src/test/resources/log4j1-async.properties | 21 +++
log4j-1.2-api/src/test/resources/log4j1-async.xml | 35 +++++
11 files changed, 503 insertions(+), 72 deletions(-)
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/AbstractBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/AbstractBuilder.java
index d4e1b37..0448ed2 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/AbstractBuilder.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/AbstractBuilder.java
@@ -16,13 +16,26 @@
*/
package org.apache.log4j.builders;
+import org.apache.log4j.bridge.FilterAdapter;
+import org.apache.log4j.bridge.FilterWrapper;
+import org.apache.log4j.helpers.OptionConverter;
+import org.apache.log4j.spi.Filter;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.filter.CompositeFilter;
+import org.apache.logging.log4j.core.filter.ThresholdFilter;
+import org.apache.logging.log4j.status.StatusLogger;
+
+import java.util.ArrayList;
+import java.util.List;
import java.util.Properties;
/**
- * Class Description goes here.
+ * Base class for Log4j 1 component builders.
*/
public abstract class AbstractBuilder {
+ private static Logger LOGGER = StatusLogger.getLogger();
protected static final String FILE_PARAM = "File";
protected static final String APPEND_PARAM = "Append";
protected static final String BUFFERED_IO_PARAM = "BufferedIO";
@@ -55,4 +68,53 @@ public abstract class AbstractBuilder {
public boolean getBooleanProperty(String key) {
return Boolean.parseBoolean(props.getProperty(prefix + key, Boolean.FALSE.toString()));
}
+
+ public int getIntegerProperty(String key, int defaultValue) {
+ String value = props.getProperty(key);
+ try {
+ if (value != null) {
+ return Integer.parseInt(value);
+ }
+ } catch (Exception ex) {
+ LOGGER.warn("Error converting value {} of {} to an integer: {}", value, key, ex.getMessage());
+ }
+ return defaultValue;
+ }
+
+ public Properties getProperties() {
+ return props;
+ }
+
+
+ protected org.apache.logging.log4j.core.Filter buildFilters(String level, Filter filter) {
+ if (level != null && filter != null) {
+ List<org.apache.logging.log4j.core.Filter> filterList = new ArrayList<>();
+ org.apache.logging.log4j.core.Filter thresholdFilter =
+ ThresholdFilter.createFilter(OptionConverter.convertLevel(level, Level.TRACE),
+ org.apache.logging.log4j.core.Filter.Result.NEUTRAL,
+ org.apache.logging.log4j.core.Filter.Result.DENY);
+ filterList.add(thresholdFilter);
+ Filter f = filter;
+ while (f != null) {
+ if (filter instanceof FilterWrapper) {
+ filterList.add(((FilterWrapper) f).getFilter());
+ } else {
+ filterList.add(new FilterAdapter(f));
+ }
+ f = f.next;
+ }
+ return CompositeFilter.createFilters(filterList.toArray(new org.apache.logging.log4j.core.Filter[0]));
+ } else if (level != null) {
+ return ThresholdFilter.createFilter(OptionConverter.convertLevel(level, Level.TRACE),
+ org.apache.logging.log4j.core.Filter.Result.NEUTRAL,
+ org.apache.logging.log4j.core.Filter.Result.DENY);
+ } else if (filter != null) {
+ if (filter instanceof FilterWrapper) {
+ return ((FilterWrapper) filter).getFilter();
+ } else {
+ return new FilterAdapter(filter);
+ }
+ }
+ return null;
+ }
}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/AsyncAppenderBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/AsyncAppenderBuilder.java
new file mode 100644
index 0000000..e14537c
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/AsyncAppenderBuilder.java
@@ -0,0 +1,170 @@
+/*
+ * 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.builders.appender;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.bridge.AppenderAdapter;
+import org.apache.log4j.bridge.AppenderWrapper;
+import org.apache.log4j.builders.AbstractBuilder;
+import org.apache.log4j.builders.BooleanHolder;
+import org.apache.log4j.builders.Holder;
+import org.apache.log4j.config.Log4j1Configuration;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.helpers.OptionConverter;
+import org.apache.log4j.xml.XmlConfiguration;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.appender.AsyncAppender;
+import org.apache.logging.log4j.core.config.AppenderRef;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.w3c.dom.Element;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.xml.XmlConfiguration.NAME_ATTR;
+import static org.apache.log4j.xml.XmlConfiguration.PARAM_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.REF_ATTR;
+import static org.apache.log4j.xml.XmlConfiguration.VALUE_ATTR;
+import static org.apache.log4j.xml.XmlConfiguration.forEachElement;
+import static org.apache.log4j.config.Log4j1Configuration.APPENDER_REF_TAG;
+import static org.apache.log4j.config.Log4j1Configuration.THRESHOLD_PARAM;
+
+
+/**
+ * Build an Asynch Appender
+ */
+@Plugin(name = "org.apache.log4j.AsyncAppender", category = CATEGORY)
+public class AsyncAppenderBuilder extends AbstractBuilder implements AppenderBuilder {
+
+ private static final Logger LOGGER = StatusLogger.getLogger();
+ private static final String BLOCKING_PARAM = "Blocking";
+ private static final String INCLUDE_LOCATION_PARAM = "IncludeLocation";
+
+ public AsyncAppenderBuilder() {
+ }
+
+ public AsyncAppenderBuilder(String prefix, Properties props) {
+ super(prefix, props);
+ }
+
+ @Override
+ public Appender parseAppender(final Element appenderElement, final XmlConfiguration config) {
+ String name = appenderElement.getAttribute(NAME_ATTR);
+ Holder<List<String>> appenderRefs = new Holder<>(new ArrayList<>());
+ Holder<Boolean> blocking = new BooleanHolder();
+ Holder<Boolean> includeLocation = new BooleanHolder();
+ Holder<String> level = new Holder<>("trace");
+ Holder<Integer> bufferSize = new Holder<>(1024);
+ forEachElement(appenderElement.getChildNodes(), (currentElement) -> {
+ switch (currentElement.getTagName()) {
+ case APPENDER_REF_TAG:
+ Appender appender = config.findAppenderByReference(currentElement);
+ if (appender != null) {
+ appenderRefs.get().add(appender.getName());
+ }
+ break;
+ case PARAM_TAG: {
+ switch (currentElement.getAttribute(NAME_ATTR)) {
+ case BUFFER_SIZE_PARAM: {
+ String value = currentElement.getAttribute(VALUE_ATTR);
+ if (value == null) {
+ LOGGER.warn("No value supplied for BufferSize parameter. Defaulting to 1024.");
+ } else {
+ bufferSize.set(Integer.parseInt(value));
+ }
+ break;
+ }
+ case BLOCKING_PARAM: {
+ String value = currentElement.getAttribute(VALUE_ATTR);
+ if (value == null) {
+ LOGGER.warn("No value supplied for Blocking parameter. Defaulting to false.");
+ } else {
+ blocking.set(Boolean.parseBoolean(value));
+ }
+ break;
+ }
+ case INCLUDE_LOCATION_PARAM: {
+ String value = currentElement.getAttribute(VALUE_ATTR);
+ if (value == null) {
+ LOGGER.warn("No value supplied for IncludeLocation parameter. Defaulting to false.");
+ } else {
+ includeLocation.set(Boolean.parseBoolean(value));
+ }
+ break;
+ }
+ case THRESHOLD_PARAM: {
+ String value = currentElement.getAttribute(VALUE_ATTR);
+ if (value == null) {
+ LOGGER.warn("No value supplied for Threshold parameter, ignoring.");
+ } else {
+ level.set(value);
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ });
+ return createAppender(name, level.get(), appenderRefs.get().toArray(new String[0]), blocking.get(),
+ bufferSize.get(), includeLocation.get(), config);
+ }
+
+ @Override
+ public Appender parseAppender(final String name, final String layoutPrefix,
+ final String filterPrefix, final Properties props, final PropertiesConfiguration configuration) {
+ String appenderRef = getProperty(APPENDER_REF_TAG);
+ boolean blocking = getBooleanProperty(BLOCKING_PARAM);
+ boolean includeLocation = getBooleanProperty(INCLUDE_LOCATION_PARAM);
+ String level = getProperty(THRESHOLD_PARAM);
+ int bufferSize = getIntegerProperty(BUFFER_SIZE_PARAM, 1024);
+ if (appenderRef == null) {
+ LOGGER.warn("No appender references configured for AsyncAppender {}", name);
+ return null;
+ }
+ Appender appender = configuration.parseAppender(props, appenderRef);
+ if (appender == null) {
+ LOGGER.warn("Cannot locate Appender {}", appenderRef);
+ return null;
+ }
+ return createAppender(name, level, new String[] {appenderRef}, blocking, bufferSize, includeLocation,
+ configuration);
+ }
+
+ private <T extends Log4j1Configuration> Appender createAppender(String name, String level,
+ String[] appenderRefs, boolean blocking, int bufferSize, boolean includeLocation,
+ T configuration) {
+ org.apache.logging.log4j.Level logLevel = OptionConverter.convertLevel(level,
+ org.apache.logging.log4j.Level.TRACE);
+ AppenderRef[] refs = new AppenderRef[appenderRefs.length];
+ int index = 0;
+ for (String appenderRef : appenderRefs) {
+ refs[index++] = AppenderRef.createAppenderRef(appenderRef, logLevel, null);
+ }
+ return new AppenderWrapper(AsyncAppender.newBuilder()
+ .setName(name)
+ .setAppenderRefs(refs)
+ .setBlocking(blocking)
+ .setBufferSize(bufferSize)
+ .setIncludeLocation(includeLocation)
+ .setConfiguration(configuration)
+ .build());
+ }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/ConsoleAppenderBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/ConsoleAppenderBuilder.java
index 8c754bd..398ca6d 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/ConsoleAppenderBuilder.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/ConsoleAppenderBuilder.java
@@ -19,8 +19,6 @@ package org.apache.log4j.builders.appender;
import org.apache.log4j.Appender;
import org.apache.log4j.Layout;
import org.apache.log4j.bridge.AppenderWrapper;
-import org.apache.log4j.bridge.FilterAdapter;
-import org.apache.log4j.bridge.FilterWrapper;
import org.apache.log4j.bridge.LayoutAdapter;
import org.apache.log4j.bridge.LayoutWrapper;
import org.apache.log4j.builders.AbstractBuilder;
@@ -35,9 +33,12 @@ import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.status.StatusLogger;
import org.w3c.dom.Element;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Properties;
import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.config.Log4j1Configuration.THRESHOLD_PARAM;
import static org.apache.log4j.xml.XmlConfiguration.FILTER_TAG;
import static org.apache.log4j.xml.XmlConfiguration.LAYOUT_TAG;
import static org.apache.log4j.xml.XmlConfiguration.NAME_ATTR;
@@ -45,7 +46,6 @@ import static org.apache.log4j.xml.XmlConfiguration.PARAM_TAG;
import static org.apache.log4j.xml.XmlConfiguration.VALUE_ATTR;
import static org.apache.log4j.xml.XmlConfiguration.forEachElement;
-
/**
* Build a Console Appender
*/
@@ -69,39 +69,63 @@ public class ConsoleAppenderBuilder extends AbstractBuilder implements AppenderB
String name = appenderElement.getAttribute(NAME_ATTR);
Holder<String> target = new Holder<>(SYSTEM_OUT);
Holder<Layout> layout = new Holder<>();
- Holder<Filter> filter = new Holder<>();
+ Holder<List<Filter>> filters = new Holder<>(new ArrayList<>());
+ Holder<String> level = new Holder<>();
forEachElement(appenderElement.getChildNodes(), (currentElement) -> {
switch (currentElement.getTagName()) {
case LAYOUT_TAG:
layout.set(config.parseLayout(currentElement));
break;
case FILTER_TAG:
- filter.set(config.parseFilters(currentElement));
+ filters.get().add(config.parseFilters(currentElement));
break;
case PARAM_TAG: {
- if (currentElement.getAttribute(NAME_ATTR).equalsIgnoreCase(TARGET)) {
- String value = currentElement.getAttribute(VALUE_ATTR);
- if (value == null) {
- LOGGER.warn("No value supplied for target parameter. Defaulting to System.out.");
- } else {
- switch (value) {
- case SYSTEM_OUT:
- target.set(SYSTEM_OUT);
- break;
- case SYSTEM_ERR:
- target.set(SYSTEM_ERR);
- break;
- default:
- LOGGER.warn("Invalid value \"{}\" for target parameter. Using default of System.out",
- value);
+ switch (currentElement.getAttribute(NAME_ATTR)) {
+ case TARGET: {
+ String value = currentElement.getAttribute(VALUE_ATTR);
+ if (value == null) {
+ LOGGER.warn("No value supplied for target parameter. Defaulting to System.out.");
+ } else {
+ switch (value) {
+ case SYSTEM_OUT:
+ target.set(SYSTEM_OUT);
+ break;
+ case SYSTEM_ERR:
+ target.set(SYSTEM_ERR);
+ break;
+ default:
+ LOGGER.warn("Invalid value \"{}\" for target parameter. Using default of System.out",
+ value);
+ }
+ }
+ break;
+ }
+ case THRESHOLD_PARAM: {
+ String value = currentElement.getAttribute(VALUE_ATTR);
+ if (value == null) {
+ LOGGER.warn("No value supplied for Threshold parameter, ignoring.");
+ } else {
+ level.set(value);
}
+ break;
}
}
break;
}
}
});
- return createAppender(name, layout.get(), filter.get(), target.get(), config);
+ Filter head = null;
+ Filter current = null;
+ for (Filter f : filters.get()) {
+ if (head == null) {
+ head = f;
+ current = f;
+ } else {
+ current.next = f;
+ current = f;
+ }
+ }
+ return createAppender(name, layout.get(), head, level.get(), target.get(), config);
}
@Override
@@ -109,27 +133,21 @@ public class ConsoleAppenderBuilder extends AbstractBuilder implements AppenderB
final String filterPrefix, final Properties props, final PropertiesConfiguration configuration) {
Layout layout = configuration.parseLayout(layoutPrefix, name, props);
Filter filter = configuration.parseAppenderFilters(props, filterPrefix, name);
+ String level = getProperty(THRESHOLD_PARAM);
String target = getProperty(TARGET);
- return createAppender(name, layout, filter, target, configuration);
+ return createAppender(name, layout, filter, level, target, configuration);
}
private <T extends Log4j1Configuration> Appender createAppender(String name, Layout layout, Filter filter,
- String target, T configuration) {
+ String level, String target, T configuration) {
org.apache.logging.log4j.core.Layout<?> consoleLayout = null;
- org.apache.logging.log4j.core.Filter consoleFilter = null;
if (layout instanceof LayoutWrapper) {
consoleLayout = ((LayoutWrapper) layout).getLayout();
} else if (layout != null) {
consoleLayout = new LayoutAdapter(layout);
}
- if (filter != null) {
- if (filter instanceof FilterWrapper) {
- consoleFilter = ((FilterWrapper) filter).getFilter();
- } else {
- consoleFilter = new FilterAdapter(filter);
- }
- }
+ org.apache.logging.log4j.core.Filter consoleFilter = buildFilters(level, filter);
ConsoleAppender.Target consoleTarget = SYSTEM_ERR.equals(target)
? ConsoleAppender.Target.SYSTEM_ERR : ConsoleAppender.Target.SYSTEM_OUT;
return new AppenderWrapper(ConsoleAppender.newBuilder()
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/DailyRollingFileAppenderBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/DailyRollingFileAppenderBuilder.java
index ae50e45..a612d42 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/DailyRollingFileAppenderBuilder.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/DailyRollingFileAppenderBuilder.java
@@ -43,6 +43,7 @@ import org.w3c.dom.Element;
import java.util.Properties;
import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.config.Log4j1Configuration.THRESHOLD_PARAM;
import static org.apache.log4j.xml.XmlConfiguration.FILTER_TAG;
import static org.apache.log4j.xml.XmlConfiguration.LAYOUT_TAG;
import static org.apache.log4j.xml.XmlConfiguration.NAME_ATTR;
@@ -73,6 +74,7 @@ public class DailyRollingFileAppenderBuilder extends AbstractBuilder implements
Holder<Layout> layout = new Holder<>();
Holder<Filter> filter = new Holder<>();
Holder<String> fileName = new Holder<>();
+ Holder<String> level = new Holder<>();
Holder<Boolean> immediateFlush = new BooleanHolder();
Holder<Boolean> append = new BooleanHolder();
Holder<Boolean> bufferedIo = new BooleanHolder();
@@ -108,7 +110,7 @@ public class DailyRollingFileAppenderBuilder extends AbstractBuilder implements
}
break;
}
- case BUFFER_SIZE_PARAM:
+ case BUFFER_SIZE_PARAM: {
String size = currentElement.getAttribute(VALUE_ATTR);
if (size != null) {
bufferSize.set(Integer.parseInt(size));
@@ -116,13 +118,23 @@ public class DailyRollingFileAppenderBuilder extends AbstractBuilder implements
LOGGER.warn("No value provide for bufferSize parameter");
}
break;
+ }
+ case THRESHOLD_PARAM: {
+ String value = currentElement.getAttribute(VALUE_ATTR);
+ if (value == null) {
+ LOGGER.warn("No value supplied for Threshold parameter, ignoring.");
+ } else {
+ level.set(value);
+ }
+ break;
+ }
}
break;
}
}
});
return createAppender(name, layout.get(), filter.get(), fileName.get(), append.get(), immediateFlush.get(),
- bufferedIo.get(), bufferSize.get(), config);
+ level.get(), bufferedIo.get(), bufferSize.get(), config);
}
@Override
@@ -131,20 +143,20 @@ public class DailyRollingFileAppenderBuilder extends AbstractBuilder implements
Layout layout = configuration.parseLayout(layoutPrefix, name, props);
Filter filter = configuration.parseAppenderFilters(props, filterPrefix, name);
String fileName = getProperty(FILE_PARAM);
+ String level = getProperty(THRESHOLD_PARAM);
boolean append = getBooleanProperty(APPEND_PARAM);
boolean immediateFlush = false;
boolean bufferedIo = getBooleanProperty(BUFFERED_IO_PARAM);
int bufferSize = Integer.parseInt(getProperty(BUFFER_SIZE_PARAM, "8192"));
return createAppender(name, layout, filter, fileName, append, immediateFlush,
- bufferedIo, bufferSize, configuration);
+ level, bufferedIo, bufferSize, configuration);
}
private <T extends Log4j1Configuration> Appender createAppender(final String name, final Layout layout,
final Filter filter, final String fileName, final boolean append, boolean immediateFlush,
- final boolean bufferedIo, final int bufferSize, final T configuration) {
+ final String level, final boolean bufferedIo, final int bufferSize, final T configuration) {
org.apache.logging.log4j.core.Layout<?> fileLayout = null;
- org.apache.logging.log4j.core.Filter fileFilter = null;
if (bufferedIo) {
immediateFlush = true;
}
@@ -153,13 +165,7 @@ public class DailyRollingFileAppenderBuilder extends AbstractBuilder implements
} else if (layout != null) {
fileLayout = new LayoutAdapter(layout);
}
- if (filter != null) {
- if (filter instanceof FilterWrapper) {
- fileFilter = ((FilterWrapper) filter).getFilter();
- } else {
- fileFilter = new FilterAdapter(filter);
- }
- }
+ org.apache.logging.log4j.core.Filter fileFilter = buildFilters(level, filter);
if (fileName == null) {
LOGGER.warn("Unable to create File Appender, no file name provided");
return null;
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/FileAppenderBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/FileAppenderBuilder.java
index 76f2788..3b4fefd 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/FileAppenderBuilder.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/FileAppenderBuilder.java
@@ -39,6 +39,7 @@ import org.w3c.dom.Element;
import java.util.Properties;
import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.config.Log4j1Configuration.THRESHOLD_PARAM;
import static org.apache.log4j.xml.XmlConfiguration.FILTER_TAG;
import static org.apache.log4j.xml.XmlConfiguration.LAYOUT_TAG;
import static org.apache.log4j.xml.XmlConfiguration.PARAM_TAG;
@@ -67,6 +68,7 @@ public class FileAppenderBuilder extends AbstractBuilder implements AppenderBuil
Holder<Layout> layout = new Holder<>();
Holder<Filter> filter = new Holder<>();
Holder<String> fileName = new Holder<>();
+ Holder<String> level = new Holder<>();
Holder<Boolean> immediateFlush = new BooleanHolder();
Holder<Boolean> append = new BooleanHolder();
Holder<Boolean> bufferedIo = new BooleanHolder();
@@ -102,7 +104,7 @@ public class FileAppenderBuilder extends AbstractBuilder implements AppenderBuil
}
break;
}
- case BUFFER_SIZE_PARAM:
+ case BUFFER_SIZE_PARAM: {
String size = currentElement.getAttribute(VALUE_ATTR);
if (size != null) {
bufferSize.set(Integer.parseInt(size));
@@ -110,14 +112,24 @@ public class FileAppenderBuilder extends AbstractBuilder implements AppenderBuil
LOGGER.warn("No value provide for bufferSize parameter");
}
break;
+ }
+ case THRESHOLD_PARAM: {
+ String value = currentElement.getAttribute(VALUE_ATTR);
+ if (value == null) {
+ LOGGER.warn("No value supplied for Threshold parameter, ignoring.");
+ } else {
+ level.set(value);
+ }
+ break;
+ }
}
break;
}
}
});
- return createAppender(name, config, layout.get(), filter.get(), fileName.get(), immediateFlush.get(),
- append.get(), bufferedIo.get(), bufferSize.get());
+ return createAppender(name, config, layout.get(), filter.get(), fileName.get(), level.get(),
+ immediateFlush.get(), append.get(), bufferedIo.get(), bufferSize.get());
}
@@ -126,20 +138,20 @@ public class FileAppenderBuilder extends AbstractBuilder implements AppenderBuil
final Properties props, final PropertiesConfiguration configuration) {
Layout layout = configuration.parseLayout(layoutPrefix, name, props);
Filter filter = configuration.parseAppenderFilters(props, filterPrefix, name);
+ String level = getProperty(THRESHOLD_PARAM);
String fileName = getProperty(FILE_PARAM);
boolean append = getBooleanProperty(APPEND_PARAM);
boolean immediateFlush = false;
boolean bufferedIo = getBooleanProperty(BUFFERED_IO_PARAM);
int bufferSize = Integer.parseInt(getProperty(BUFFER_SIZE_PARAM, "8192"));
- return createAppender(name, configuration, layout, filter, fileName, immediateFlush,
+ return createAppender(name, configuration, layout, filter, fileName, level, immediateFlush,
append, bufferedIo, bufferSize);
}
private Appender createAppender(final String name, final Log4j1Configuration configuration, final Layout layout,
- final Filter filter, final String fileName, boolean immediateFlush, final boolean append,
+ final Filter filter, final String fileName, String level, boolean immediateFlush, final boolean append,
final boolean bufferedIo, final int bufferSize) {
org.apache.logging.log4j.core.Layout<?> fileLayout = null;
- org.apache.logging.log4j.core.Filter fileFilter = null;
if (bufferedIo) {
immediateFlush = true;
}
@@ -148,13 +160,7 @@ public class FileAppenderBuilder extends AbstractBuilder implements AppenderBuil
} else if (layout != null) {
fileLayout = new LayoutAdapter(layout);
}
- if (filter != null) {
- if (filter instanceof FilterWrapper) {
- fileFilter = ((FilterWrapper) filter).getFilter();
- } else {
- fileFilter = new FilterAdapter(filter);
- }
- }
+ org.apache.logging.log4j.core.Filter fileFilter = buildFilters(level, filter);
if (fileName == null) {
LOGGER.warn("Unable to create File Appender, no file name provided");
return null;
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/RollingFileAppenderBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/RollingFileAppenderBuilder.java
index d6e33c5..0746be6 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/RollingFileAppenderBuilder.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/RollingFileAppenderBuilder.java
@@ -45,6 +45,7 @@ import org.w3c.dom.Element;
import java.util.Properties;
import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.config.Log4j1Configuration.THRESHOLD_PARAM;
import static org.apache.log4j.xml.XmlConfiguration.FILTER_TAG;
import static org.apache.log4j.xml.XmlConfiguration.LAYOUT_TAG;
import static org.apache.log4j.xml.XmlConfiguration.NAME_ATTR;
@@ -80,6 +81,7 @@ public class RollingFileAppenderBuilder extends AbstractBuilder implements Appen
Holder<Integer> bufferSize = new Holder<>(8192);
Holder<String> maxSize = new Holder<>();
Holder<String> maxBackups = new Holder<>();
+ Holder<String> level = new Holder<>();
forEachElement(appenderElement.getChildNodes(), (currentElement) -> {
switch (currentElement.getTagName()) {
case LAYOUT_TAG:
@@ -138,13 +140,22 @@ public class RollingFileAppenderBuilder extends AbstractBuilder implements Appen
}
break;
}
+ case THRESHOLD_PARAM: {
+ String value = currentElement.getAttribute(VALUE_ATTR);
+ if (value == null) {
+ LOGGER.warn("No value supplied for Threshold parameter, ignoring.");
+ } else {
+ level.set(value);
+ }
+ break;
+ }
}
break;
}
}
});
return createAppender(name, config, layout.get(), filter.get(), bufferedIo.get(), immediateFlush.get(),
- fileName.get(), maxSize.get(), maxBackups.get());
+ fileName.get(), level.get(), maxSize.get(), maxBackups.get());
}
@@ -154,19 +165,19 @@ public class RollingFileAppenderBuilder extends AbstractBuilder implements Appen
Layout layout = configuration.parseLayout(layoutPrefix, name, props);
Filter filter = configuration.parseAppenderFilters(props, filterPrefix, name);
String fileName = getProperty(FILE_PARAM);
+ String level = getProperty(THRESHOLD_PARAM);
boolean immediateFlush = false;
boolean bufferedIo = getBooleanProperty(BUFFERED_IO_PARAM);
String maxSize = getProperty(MAX_SIZE_PARAM);
String maxBackups = getProperty(MAX_BACKUP_INDEX);
- return createAppender(name, configuration, layout, filter, bufferedIo, immediateFlush, fileName, maxSize,
+ return createAppender(name, configuration, layout, filter, bufferedIo, immediateFlush, fileName, level, maxSize,
maxBackups);
}
private Appender createAppender(final String name, final Log4j1Configuration config, final Layout layout,
final Filter filter, final boolean bufferedIo, boolean immediateFlush, final String fileName,
- final String maxSize, final String maxBackups) {
+ final String level, final String maxSize, final String maxBackups) {
org.apache.logging.log4j.core.Layout<?> fileLayout = null;
- org.apache.logging.log4j.core.Filter fileFilter = null;
if (bufferedIo) {
immediateFlush = true;
}
@@ -175,13 +186,7 @@ public class RollingFileAppenderBuilder extends AbstractBuilder implements Appen
} else if (layout != null) {
fileLayout = new LayoutAdapter(layout);
}
- if (filter != null) {
- if (filter instanceof FilterWrapper) {
- fileFilter = ((FilterWrapper) filter).getFilter();
- } else {
- fileFilter = new FilterAdapter(filter);
- }
- }
+ org.apache.logging.log4j.core.Filter fileFilter = buildFilters(level, filter);
if (fileName == null) {
LOGGER.warn("Unable to create File Appender, no file name provided");
return null;
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/config/Log4j1Configuration.java b/log4j-1.2-api/src/main/java/org/apache/log4j/config/Log4j1Configuration.java
index ffa45d8..ceafd07 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/config/Log4j1Configuration.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/config/Log4j1Configuration.java
@@ -29,6 +29,8 @@ import org.apache.logging.log4j.core.config.Reconfigurable;
public class Log4j1Configuration extends AbstractConfiguration implements Reconfigurable {
public static final String MONITOR_INTERVAL = "log4j1.monitorInterval";
+ public static final String APPENDER_REF_TAG = "appender-ref";
+ public static final String THRESHOLD_PARAM = "Threshold";
public static final String INHERITED = "inherited";
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfiguration.java b/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfiguration.java
index a82b773..6ce22c8 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfiguration.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfiguration.java
@@ -65,7 +65,6 @@ public class XmlConfiguration extends Log4j1Configuration {
private static final String OLD_CONFIGURATION_TAG = "configuration";
private static final String RENDERER_TAG = "renderer";
private static final String APPENDER_TAG = "appender";
- private static final String APPENDER_REF_TAG = "appender-ref";
public static final String PARAM_TAG = "param";
public static final String LAYOUT_TAG = "layout";
private static final String CATEGORY = "category";
@@ -80,7 +79,7 @@ public class XmlConfiguration extends Log4j1Configuration {
private static final String PRIORITY_TAG = "priority";
public static final String FILTER_TAG = "filter";
private static final String ERROR_HANDLER_TAG = "errorHandler";
- private static final String REF_ATTR = "ref";
+ public static final String REF_ATTR = "ref";
private static final String ADDITIVITY_ATTR = "additivity";
private static final String CONFIG_DEBUG_ATTR = "configDebug";
private static final String INTERNAL_DEBUG_ATTR = "debug";
@@ -114,6 +113,10 @@ public class XmlConfiguration extends Log4j1Configuration {
manager = new BuilderManager();
}
+ public void addAppenderIfAbsent(Appender appender) {
+ appenderMap.putIfAbsent(appender.getName(), appender);
+ }
+
/**
* Configure log4j by reading in a log4j.dtd compliant XML
* configuration file.
@@ -328,7 +331,7 @@ public class XmlConfiguration extends Log4j1Configuration {
/**
* Used internally to parse appenders by IDREF element.
*/
- private Appender findAppenderByReference(Element appenderRef) {
+ public Appender findAppenderByReference(Element appenderRef) {
String appenderName = subst(appenderRef.getAttribute(REF_ATTR));
Document doc = appenderRef.getOwnerDocument();
return findAppenderByName(doc, appenderName);
@@ -337,7 +340,7 @@ public class XmlConfiguration extends Log4j1Configuration {
/**
* Used internally to parse an appender element.
*/
- private Appender parseAppender(Element appenderElement) {
+ public Appender parseAppender(Element appenderElement) {
String className = subst(appenderElement.getAttribute(CLASS_ATTR));
LOGGER.debug("Class name: [" + className + ']');
Appender appender = manager.parseAppender(className, appenderElement, this);
diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/config/AsyncAppenderTest.java b/log4j-1.2-api/src/test/java/org/apache/log4j/config/AsyncAppenderTest.java
new file mode 100644
index 0000000..bac1338
--- /dev/null
+++ b/log4j-1.2-api/src/test/java/org/apache/log4j/config/AsyncAppenderTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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 org.apache.log4j.ListAppender;
+import org.apache.log4j.LogManager;
+import org.apache.log4j.Logger;
+import org.apache.log4j.bridge.AppenderAdapter;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.ConfigurationSource;
+import org.apache.logging.log4j.core.config.Configurator;
+import org.apache.logging.log4j.spi.LoggerContextFactory;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test configuration from XML.
+ */
+public class AsyncAppenderTest {
+
+ @Test
+ public void testAsyncXml() throws Exception {
+ LoggerContext loggerContext = configure("target/test-classes/log4j1-async.xml");
+ Logger logger = LogManager.getLogger("test");
+ logger.debug("This is a test of the root logger");
+ Thread.sleep(50);
+ Configuration configuration = loggerContext.getConfiguration();
+ Map<String, Appender> appenders = configuration.getAppenders();
+ ListAppender messageAppender = null;
+ for (Map.Entry<String, Appender> entry : appenders.entrySet()) {
+ if (entry.getKey().equals("list")) {
+ messageAppender = (ListAppender) ((AppenderAdapter.Adapter) entry.getValue()).getAppender();
+ }
+ }
+ assertNotNull("No Message Appender", messageAppender);
+ List<String> messages = messageAppender.getMessages();
+ assertTrue("No messages", messages != null && messages.size() > 0);
+ }
+
+ @Test
+ public void testAsyncProperties() throws Exception {
+ LoggerContext loggerContext = configure("target/test-classes/log4j1-async.properties");
+ Logger logger = LogManager.getLogger("test");
+ logger.debug("This is a test of the root logger");
+ Thread.sleep(50);
+ Configuration configuration = loggerContext.getConfiguration();
+ Map<String, Appender> appenders = configuration.getAppenders();
+ ListAppender messageAppender = null;
+ for (Map.Entry<String, Appender> entry : appenders.entrySet()) {
+ if (entry.getKey().equals("list")) {
+ messageAppender = (ListAppender) ((AppenderAdapter.Adapter) entry.getValue()).getAppender();
+ }
+ }
+ assertNotNull("No Message Appender", messageAppender);
+ List<String> messages = messageAppender.getMessages();
+ assertTrue("No messages", messages != null && messages.size() > 0);
+ }
+
+
+ private LoggerContext configure(String configLocation) throws Exception {
+ File file = new File(configLocation);
+ InputStream is = new FileInputStream(file);
+ ConfigurationSource source = new ConfigurationSource(is, file);
+ LoggerContextFactory factory = org.apache.logging.log4j.LogManager.getFactory();
+ LoggerContext context = (LoggerContext) org.apache.logging.log4j.LogManager.getContext(false);
+ Configuration configuration;
+ if (configLocation.endsWith(".xml")) {
+ configuration = new XmlConfigurationFactory().getConfiguration(context, source);
+ } else {
+ configuration = new PropertiesConfigurationFactory().getConfiguration(context, source);
+ }
+ assertNotNull("No configuration created", configuration);
+ Configurator.reconfigure(configuration);
+ return context;
+ }
+
+}
diff --git a/log4j-1.2-api/src/test/resources/log4j1-async.properties b/log4j-1.2-api/src/test/resources/log4j1-async.properties
new file mode 100644
index 0000000..8e80b46
--- /dev/null
+++ b/log4j-1.2-api/src/test/resources/log4j1-async.properties
@@ -0,0 +1,21 @@
+# 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.
+
+log4j.appender.list=org.apache.log4j.ListAppender
+log4j.appender.list.layout=org.apache.log4j.PatternLayout
+log4j.appender.list.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
+log4j.appender.async=org.apache.log4j.AsyncAppender
+log4j.appender.async.appender-ref=list
+log4j.rootLogger=trace, async
\ No newline at end of file
diff --git a/log4j-1.2-api/src/test/resources/log4j1-async.xml b/log4j-1.2-api/src/test/resources/log4j1-async.xml
new file mode 100644
index 0000000..a0cb7f6
--- /dev/null
+++ b/log4j-1.2-api/src/test/resources/log4j1-async.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ 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.
+-->
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
+ <appender name="list" class="org.apache.log4j.ListAppender">
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n" />
+ </layout>
+ </appender>
+ <appender name="async" class="org.apache.log4j.AsyncAppender">
+ <appender-ref ref="list"/>
+ </appender>
+
+ <root>
+ <priority value ="trace" />
+ <appender-ref ref="async" />
+ </root>
+
+</log4j:configuration>
\ No newline at end of file