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 <[email protected]> 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
