You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by rp...@apache.org on 2016/09/11 17:05:17 UTC
[4/7] logging-log4j2 git commit: LOG4J2-1575 (GC) Store Configuration
Properties in List instead of Map to prevent creating temporary iterator
objects
LOG4J2-1575 (GC) Store Configuration Properties in List instead of Map to prevent creating temporary iterator objects
Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/9cfdd642
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/9cfdd642
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/9cfdd642
Branch: refs/heads/master
Commit: 9cfdd64210aeb0352fdb35975c881df8e00594b8
Parents: 418955b
Author: rpopma <rp...@apache.org>
Authored: Mon Sep 12 01:38:05 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Mon Sep 12 01:38:05 2016 +0900
----------------------------------------------------------------------
.../logging/log4j/core/config/LoggerConfig.java | 98 +++++++++++++-----
.../logging/log4j/core/config/Property.java | 12 ++-
.../log4j/core/GcFreeLoggingTestUtil.java | 2 +-
...ggerAllThreadContextImplementationsTest.java | 4 +-
...nfigAllThreadContextImplementationsTest.java | 4 +-
.../log4j/core/config/LoggerConfigTest.java | 102 +++++++++++++++++++
.../logging/log4j/core/config/PropertyTest.java | 12 ++-
.../AsyncLoggerConfigThreadContextTest.xml | 7 +-
.../resources/AsyncLoggerThreadContextTest.xml | 5 +-
log4j-core/src/test/resources/gcFreeLogging.xml | 2 +
.../resources/gcFreeMixedSyncAsyncLogging.xml | 4 +
src/changes/changes.xml | 3 +
12 files changed, 218 insertions(+), 37 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/9cfdd642/log4j-core/src/main/java/org/apache/logging/log4j/core/config/LoggerConfig.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/LoggerConfig.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/LoggerConfig.java
index c7170c7..0fc7b3f 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/LoggerConfig.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/LoggerConfig.java
@@ -67,7 +67,9 @@ public class LoggerConfig extends AbstractFilterable {
private boolean additive = true;
private boolean includeLocation = true;
private LoggerConfig parent;
- private final Map<Property, Boolean> properties;
+ private Map<Property, Boolean> propertiesMap;
+ private final List<Property> properties;
+ private final boolean propertiesRequireLookup;
private final Configuration config;
private final ReliabilityStrategy reliabilityStrategy;
@@ -98,6 +100,7 @@ public class LoggerConfig extends AbstractFilterable {
this.level = Level.ERROR;
this.name = Strings.EMPTY;
this.properties = null;
+ this.propertiesRequireLookup = false;
this.config = null;
this.reliabilityStrategy = new DefaultReliabilityStrategy(this);
}
@@ -115,6 +118,7 @@ public class LoggerConfig extends AbstractFilterable {
this.level = level;
this.additive = additive;
this.properties = null;
+ this.propertiesRequireLookup = false;
this.config = null;
this.reliabilityStrategy = new DefaultReliabilityStrategy(this);
}
@@ -131,18 +135,27 @@ public class LoggerConfig extends AbstractFilterable {
this.includeLocation = includeLocation;
this.config = config;
if (properties != null && properties.length > 0) {
- final Map<Property, Boolean> map = new HashMap<>(properties.length);
- for (final Property prop : properties) {
- final boolean interpolate = prop.getValue().contains("${");
- map.put(prop, interpolate);
- }
- this.properties = Collections.unmodifiableMap(map);
+ this.properties = Collections.unmodifiableList(Arrays.asList(Arrays.copyOf(
+ properties, properties.length)));
} else {
this.properties = null;
}
+ this.propertiesRequireLookup = containsPropertyRequiringLookup(properties);
this.reliabilityStrategy = config.getReliabilityStrategy(this);
}
+ private static boolean containsPropertyRequiringLookup(final Property[] properties) {
+ if (properties == null) {
+ return false;
+ }
+ for (int i = 0; i < properties.length; i++) {
+ if (properties[i].isValueNeedsLookup()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
@Override
public Filter getFilter() {
return super.getFilter();
@@ -310,12 +323,43 @@ public class LoggerConfig extends AbstractFilterable {
* @return an unmodifiable map with the configuration properties, or {@code null}
* @see Configuration#getStrSubstitutor()
* @see StrSubstitutor
+ * @deprecated use {@link #getPropertyList()} instead
*/
// LOG4J2-157
public Map<Property, Boolean> getProperties() {
+ if (properties == null) {
+ return null;
+ }
+ if (propertiesMap == null) { // lazily initialize: only used by user custom code, not by Log4j any more
+ final Map<Property, Boolean> result = new HashMap<>(properties.size() * 2);
+ for (int i = 0; i < properties.size(); i++) {
+ result.put(properties.get(i), Boolean.valueOf(properties.get(i).isValueNeedsLookup()));
+ }
+ propertiesMap = Collections.unmodifiableMap(result);
+ }
+ return propertiesMap;
+ }
+
+ /**
+ * Returns an unmodifiable list with the configuration properties, or {@code null} if this {@code LoggerConfig} does
+ * not have any configuration properties.
+ * <p>
+ * Each {@code Property} in the list has an attribute {@link Property#isValueNeedsLookup() valueNeedsLookup} that
+ * is {@code true} if the property value has a variable that needs to be substituted.
+ *
+ * @return an unmodifiable list with the configuration properties, or {@code null}
+ * @see Configuration#getStrSubstitutor()
+ * @see StrSubstitutor
+ * @since 2.7
+ */
+ public List<Property> getPropertyList() {
return properties;
}
+ public boolean isPropertiesRequireLookup() {
+ return propertiesRequireLookup;
+ }
+
/**
* Logs an event.
*
@@ -326,24 +370,30 @@ public class LoggerConfig extends AbstractFilterable {
* @param data The Message.
* @param t A Throwable or null.
*/
+ @PerformanceSensitive("allocation")
public void log(final String loggerName, final String fqcn, final Marker marker, final Level level,
final Message data, final Throwable t) {
List<Property> props = null;
- if (properties != null) {
- props = new ArrayList<>(properties.size());
- final LogEvent event = Log4jLogEvent.newBuilder()
- .setMessage(data)
- .setMarker(marker)
- .setLevel(level)
- .setLoggerName(loggerName)
- .setLoggerFqcn(fqcn)
- .setThrown(t)
- .build();
- for (final Map.Entry<Property, Boolean> entry : properties.entrySet()) {
- final Property prop = entry.getKey();
- final String value = entry.getValue() ? config.getStrSubstitutor().replace(event, prop.getValue())
- : prop.getValue();
- props.add(Property.createProperty(prop.getName(), value));
+ if (!propertiesRequireLookup) {
+ props = properties;
+ } else {
+ if (properties != null) {
+ props = new ArrayList<>(properties.size());
+ final LogEvent event = Log4jLogEvent.newBuilder()
+ .setMessage(data)
+ .setMarker(marker)
+ .setLevel(level)
+ .setLoggerName(loggerName)
+ .setLoggerFqcn(fqcn)
+ .setThrown(t)
+ .build();
+ for (int i = 0; i < properties.size(); i++) {
+ final Property prop = properties.get(i);
+ final String value = prop.isValueNeedsLookup() // since LOG4J2-1575
+ ? config.getStrSubstitutor().replace(event, prop.getValue()) //
+ : prop.getValue();
+ props.add(Property.createProperty(prop.getName(), value));
+ }
}
}
log(logEventFactory.createEvent(loggerName, marker, fqcn, level, data, props, t));
@@ -413,11 +463,11 @@ public class LoggerConfig extends AbstractFilterable {
@Deprecated
public static LoggerConfig createLogger(final String additivity,
// @formatter:off
- final Level level,
+ final Level level,
@PluginAttribute("name") final String loggerName,
final String includeLocation,
final AppenderRef[] refs,
- final Property[] properties,
+ final Property[] properties,
@PluginConfiguration final Configuration config,
final Filter filter) {
// @formatter:on
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/9cfdd642/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Property.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Property.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Property.java
index c33efb4..4dca05a 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Property.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Property.java
@@ -33,10 +33,12 @@ public final class Property {
private final String name;
private final String value;
+ private final boolean valueNeedsLookup;
private Property(final String name, final String value) {
this.name = name;
this.value = value;
+ this.valueNeedsLookup = value != null && value.contains("${");
}
/**
@@ -56,8 +58,16 @@ public final class Property {
}
/**
+ * Returns {@code true} if the value contains a substitutable property that requires a lookup to be resolved.
+ * @return {@code true} if the value contains {@code "${"}, {@code false} otherwise
+ */
+ public boolean isValueNeedsLookup() {
+ return valueNeedsLookup;
+ }
+
+ /**
* Creates a Property.
- *
+ *
* @param name The key.
* @param value The value.
* @return A Property.
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/9cfdd642/log4j-core/src/test/java/org/apache/logging/log4j/core/GcFreeLoggingTestUtil.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/GcFreeLoggingTestUtil.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/GcFreeLoggingTestUtil.java
index 9cf4164..1d57c2d 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/GcFreeLoggingTestUtil.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/GcFreeLoggingTestUtil.java
@@ -132,7 +132,7 @@ public class GcFreeLoggingTestUtil {
final String text = new String(Files.readAllBytes(tempFile.toPath()));
final List<String> lines = Files.readAllLines(tempFile.toPath(), Charset.defaultCharset());
final String className = cls.getSimpleName();
- assertEquals(text, "FATAL o.a.l.l.c." + className + " [main] value1 {aKey=value1, key2=value2} This message is logged to the console",
+ assertEquals(text, "FATAL o.a.l.l.c." + className + " [main] value1 {aKey=value1, key2=value2, prop1=value1, prop2=value2} This message is logged to the console",
lines.get(0));
final String LINESEP = System.getProperty("line.separator");
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/9cfdd642/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerAllThreadContextImplementationsTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerAllThreadContextImplementationsTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerAllThreadContextImplementationsTest.java
index 4283cbb..38d959f 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerAllThreadContextImplementationsTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerAllThreadContextImplementationsTest.java
@@ -180,10 +180,10 @@ public class AsyncLoggerAllThreadContextImplementationsTest {
for (int i = 0; i < LINE_COUNT; i++) {
String line = reader.readLine();
if ((i & 1) == 1) {
- expect = "INFO c.f.Bar mapvalue [stackvalue] {KEY=mapvalue, count=" + i + "} "
+ expect = "INFO c.f.Bar mapvalue [stackvalue] {KEY=mapvalue, configProp=configValue, configProp2=configValue2, count=" + i + "} "
+ contextDesc + " i=" + i;
} else {
- expect = "INFO c.f.Bar mapvalue [stackvalue] {KEY=mapvalue} " + contextDesc + " i=" + i;
+ expect = "INFO c.f.Bar mapvalue [stackvalue] {KEY=mapvalue, configProp=configValue, configProp2=configValue2} " + contextDesc + " i=" + i;
}
assertEquals(file.getName() + ": line " + i, expect, line);
}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/9cfdd642/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigAllThreadContextImplementationsTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigAllThreadContextImplementationsTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigAllThreadContextImplementationsTest.java
index 3c3d69c..4d09ffb 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigAllThreadContextImplementationsTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigAllThreadContextImplementationsTest.java
@@ -151,10 +151,10 @@ public class AsyncLoggerConfigAllThreadContextImplementationsTest {
for (int i = 0; i < LINE_COUNT; i++) {
String line = reader.readLine();
if ((i & 1) == 1) {
- expect = "INFO c.f.Bar mapvalue [stackvalue] {KEY=mapvalue, count=" + i + "} "
+ expect = "INFO c.f.Bar mapvalue [stackvalue] {KEY=mapvalue, configProp=configValue, configProp2=configValue2, count=" + i + "} "
+ contextDesc + " i=" + i;
} else {
- expect = "INFO c.f.Bar mapvalue [stackvalue] {KEY=mapvalue} " + contextDesc + " i=" + i;
+ expect = "INFO c.f.Bar mapvalue [stackvalue] {KEY=mapvalue, configProp=configValue, configProp2=configValue2} " + contextDesc + " i=" + i;
}
assertEquals(file.getName() + ": line " + i, expect, line);
}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/9cfdd642/log4j-core/src/test/java/org/apache/logging/log4j/core/config/LoggerConfigTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/LoggerConfigTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/LoggerConfigTest.java
new file mode 100644
index 0000000..6eb04a3
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/LoggerConfigTest.java
@@ -0,0 +1,102 @@
+package org.apache.logging.log4j.core.config;/*
+ * 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.
+ */
+
+import java.util.HashSet;
+import java.util.List;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.impl.Log4jLogEvent;
+import org.apache.logging.log4j.core.impl.LogEventFactory;
+import org.apache.logging.log4j.message.Message;
+import org.apache.logging.log4j.message.SimpleMessage;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Tests for LoggerConfig.
+ */
+public class LoggerConfigTest {
+
+ private static LoggerConfig createForProperties(final Property[] properties) {
+ return LoggerConfig.createLogger(true, Level.INFO, "name", "false", new AppenderRef[0], properties,
+ new NullConfiguration(), null);
+ }
+
+ @SuppressWarnings({"deprecation", "unchecked"})
+ @Test
+ public void testPropertiesWithoutSubstitution() {
+ assertNull("null propertiesList", createForProperties(null).getPropertyList());
+ assertNull("null property Map", createForProperties(null).getProperties());
+
+ final Property[] all = new Property[] {
+ Property.createProperty("key1", "value1"),
+ Property.createProperty("key2", "value2"),
+ };
+ final LoggerConfig loggerConfig = createForProperties(all);
+ final List<Property> list = loggerConfig.getPropertyList();
+ assertEquals("map and list contents equal", new HashSet(list), loggerConfig.getProperties().keySet());
+
+ final Object[] actualList = new Object[1];
+ loggerConfig.setLogEventFactory(new LogEventFactory() {
+ @Override
+ public LogEvent createEvent(final String loggerName, final Marker marker, final String fqcn,
+ final Level level, final Message data,
+ final List<Property> properties, final Throwable t) {
+ actualList[0] = properties;
+ return new Log4jLogEvent(System.currentTimeMillis());
+ }
+ });
+ loggerConfig.log("name", "fqcn", null, Level.INFO, new SimpleMessage("msg"), null);
+ assertSame("propertiesList passed in as is if no substitutions required", list, actualList[0]);
+ }
+
+ @SuppressWarnings({"deprecation", "unchecked"})
+ @Test
+ public void testPropertiesWithSubstitution() {
+ final Property[] all = new Property[] {
+ Property.createProperty("key1", "value1-${sys:user.name}"),
+ Property.createProperty("key2", "value2-${sys:user.name}"),
+ };
+ final LoggerConfig loggerConfig = createForProperties(all);
+ final List<Property> list = loggerConfig.getPropertyList();
+ assertEquals("map and list contents equal", new HashSet(list), loggerConfig.getProperties().keySet());
+
+ final Object[] actualListHolder = new Object[1];
+ loggerConfig.setLogEventFactory(new LogEventFactory() {
+ @Override
+ public LogEvent createEvent(final String loggerName, final Marker marker, final String fqcn,
+ final Level level, final Message data,
+ final List<Property> properties, final Throwable t) {
+ actualListHolder[0] = properties;
+ return new Log4jLogEvent(System.currentTimeMillis());
+ }
+ });
+ loggerConfig.log("name", "fqcn", null, Level.INFO, new SimpleMessage("msg"), null);
+ assertNotSame("propertiesList with substitutions", list, actualListHolder[0]);
+
+ final List<Property> actualList = (List<Property>) actualListHolder[0];
+
+ for (int i = 0; i < list.size(); i++) {
+ assertEquals("name[" + i + "]", list.get(i).getName(), actualList.get(i).getName());
+ final String value = list.get(i).getValue().replace("${sys:user.name}", System.getProperty("user.name"));
+ assertEquals("value[" + i + "]", value, actualList.get(i).getValue());
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/9cfdd642/log4j-core/src/test/java/org/apache/logging/log4j/core/config/PropertyTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/PropertyTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/PropertyTest.java
index a38382d..8e4a081 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/PropertyTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/PropertyTest.java
@@ -60,4 +60,14 @@ public class PropertyTest {
assertEquals(expect, messages.get(0));
app.clear();
}
-}
\ No newline at end of file
+
+ @Test
+ public void testIsValueNeedsLookup() {
+ assertTrue("with ${ as value", Property.createProperty("", "${").isValueNeedsLookup());
+ assertTrue("with ${ in value", Property.createProperty("", "blah${blah").isValueNeedsLookup());
+ assertFalse("empty value", Property.createProperty("", "").isValueNeedsLookup());
+ assertFalse("without ${ in value", Property.createProperty("", "blahblah").isValueNeedsLookup());
+ assertFalse("without $ in value", Property.createProperty("", "blahb{sys:lah").isValueNeedsLookup());
+ assertFalse("without { in value", Property.createProperty("", "blahb$sys:lah").isValueNeedsLookup());
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/9cfdd642/log4j-core/src/test/resources/AsyncLoggerConfigThreadContextTest.xml
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/resources/AsyncLoggerConfigThreadContextTest.xml b/log4j-core/src/test/resources/AsyncLoggerConfigThreadContextTest.xml
index 1ce6faa..5d40e1a 100644
--- a/log4j-core/src/test/resources/AsyncLoggerConfigThreadContextTest.xml
+++ b/log4j-core/src/test/resources/AsyncLoggerConfigThreadContextTest.xml
@@ -1,8 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="ERROR">
- <Properties>
- <Property name="configProp">configValue</Property>
- </Properties>
<Appenders>
<RandomAccessFile name="AsyncLoggerAndAsyncAppenderFile" fileName="target/AsyncLoggerAndAsyncAppenderTest.log"
immediateFlush="false" append="false">
@@ -38,10 +35,14 @@
<Loggers>
<AsyncLogger name="com.foo" level="info" includeLocation="false" additivity="true">
+ <Property name="configProp">configValue</Property>
+ <Property name="configProp2">configValue2</Property>
<AppenderRef ref="RandomAccessFile"/>
<AppenderRef ref="AsyncLoggerAndAsyncAppender"/>
</AsyncLogger>
<Root level="info" includeLocation="false">
+ <Property name="configProp">configValue</Property>
+ <Property name="configProp2">configValue2</Property>
<AppenderRef ref="SynchronousRandomAccessFile"/>
<AppenderRef ref="AsyncAppender"/>
</Root>
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/9cfdd642/log4j-core/src/test/resources/AsyncLoggerThreadContextTest.xml
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/resources/AsyncLoggerThreadContextTest.xml b/log4j-core/src/test/resources/AsyncLoggerThreadContextTest.xml
index 6e507d2..683f41c 100644
--- a/log4j-core/src/test/resources/AsyncLoggerThreadContextTest.xml
+++ b/log4j-core/src/test/resources/AsyncLoggerThreadContextTest.xml
@@ -1,8 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="ERROR">
- <Properties>
- <Property name="configProp">configValue</Property>
- </Properties>
<Appenders>
<RandomAccessFile name="RandomAccessFile" fileName="target/AsyncLoggerTest.log"
immediateFlush="false" append="false">
@@ -14,6 +11,8 @@
<Loggers>
<Root level="info" includeLocation="false">
+ <Property name="configProp">configValue</Property>
+ <Property name="configProp2">configValue2</Property>
<AppenderRef ref="RandomAccessFile"/>
</Root>
</Loggers>
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/9cfdd642/log4j-core/src/test/resources/gcFreeLogging.xml
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/resources/gcFreeLogging.xml b/log4j-core/src/test/resources/gcFreeLogging.xml
index 3a3c07e..fd3d1a2 100644
--- a/log4j-core/src/test/resources/gcFreeLogging.xml
+++ b/log4j-core/src/test/resources/gcFreeLogging.xml
@@ -48,6 +48,8 @@
</Appenders>
<Loggers>
<Root level="trace" includeLocation="false">
+ <Property name="prop1">value1</Property>
+ <Property name="prop2">value2</Property>
<appender-ref ref="Console" level="FATAL" />
<appender-ref ref="File"/>
<appender-ref ref="RandomAccessFile"/>
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/9cfdd642/log4j-core/src/test/resources/gcFreeMixedSyncAsyncLogging.xml
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/resources/gcFreeMixedSyncAsyncLogging.xml b/log4j-core/src/test/resources/gcFreeMixedSyncAsyncLogging.xml
index 03d55b5..7c29931 100644
--- a/log4j-core/src/test/resources/gcFreeMixedSyncAsyncLogging.xml
+++ b/log4j-core/src/test/resources/gcFreeMixedSyncAsyncLogging.xml
@@ -48,6 +48,8 @@
<Loggers>
<AsyncLogger name="org.apache.logging.log4j.core.GcFreeMixedSyncAyncLoggingTest"
level="trace" includeLocation="false">
+ <Property name="prop1">value1</Property>
+ <Property name="prop2">value2</Property>
<appender-ref ref="Console" level="FATAL" />
<appender-ref ref="File"/>
<appender-ref ref="RandomAccessFile"/>
@@ -58,6 +60,8 @@
<appender-ref ref="RandomAccessFileGelf"/>
</AsyncLogger>
<Root level="trace" includeLocation="false">
+ <Property name="prop1">value1</Property>
+ <Property name="prop2">value2</Property>
<appender-ref ref="Console" level="FATAL" />
<appender-ref ref="File"/>
<appender-ref ref="RandomAccessFile"/>
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/9cfdd642/src/changes/changes.xml
----------------------------------------------------------------------
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 2b34b8f..e0fa64d 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -24,6 +24,9 @@
</properties>
<body>
<release version="2.7" date="2016-MM-DD" description="GA Release 2.7">
+ <action issue="LOG4J2-1575" dev="rpopma" type="fix">
+ (GC) LoggerConfig now stores configuration properties in a List, not a Map to prevent creating temporary Iterator objects. Added method LoggerConfig#getPropertyList(), deprecated method #getProperties().
+ </action>
<action issue="LOG4J2-1457" dev="mattsicker" type="fix" due-to="Leon Finker">
Fixed class loader deadlock when using async logging and extended stack trace pattern.
</action>