Commit 49457821 authored by Emmanuel Bourg's avatar Emmanuel Bourg

Update upstream source from tag 'upstream/2.11.1'

Update to upstream version '2.11.1'
with Debian dir eed33319d9c55858ece1b0d9771f9c77b749d797
parents cdc9d970 c87b2af9
This diff is collapsed.
......@@ -20,7 +20,7 @@
<parent>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j</artifactId>
<version>2.11.0</version>
<version>2.11.1</version>
<relativePath>../</relativePath>
</parent>
<artifactId>log4j-1.2-api</artifactId>
......
......@@ -39,14 +39,19 @@ public class LogWithMDCTest {
public void testMDC() throws Exception {
MDC.put("Key1", "John");
MDC.put("Key2", "Smith");
final Logger logger = Logger.getLogger("org.apache.test.logging");
logger.debug("This is a test");
final ListAppender listApp = (ListAppender) CTX.getAppender("List");
assertNotNull(listApp);
final List<String> msgs = listApp.getMessages();
assertNotNull("No messages received", msgs);
assertTrue(msgs.size() == 1);
assertTrue("Key1 is missing", msgs.get(0).contains("Key1=John"));
assertTrue("Key2 is missing", msgs.get(0).contains("Key2=Smith"));
try {
final Logger logger = Logger.getLogger("org.apache.test.logging");
logger.debug("This is a test");
final ListAppender listApp = (ListAppender) CTX.getAppender("List");
assertNotNull(listApp);
final List<String> msgs = listApp.getMessages();
assertNotNull("No messages received", msgs);
assertTrue(msgs.size() == 1);
assertTrue("Key1 is missing", msgs.get(0).contains("Key1=John"));
assertTrue("Key2 is missing", msgs.get(0).contains("Key2=Smith"));
} finally {
MDC.remove("Key1");
MDC.remove("Key2");
}
}
}
......@@ -40,14 +40,19 @@ public class LogWithRouteTest {
public void testMDC() throws Exception {
MDC.put("Type", "Service");
MDC.put("Name", "John Smith");
final Logger logger = Logger.getLogger("org.apache.test.logging");
logger.debug("This is a test");
final ListAppender listApp = (ListAppender) CTX.getAppender("List");
assertNotNull(listApp);
final List<String> msgs = listApp.getMessages();
assertNotNull("No messages received", msgs);
assertTrue(msgs.size() == 1);
assertTrue("Type is missing", msgs.get(0).contains("Type=Service"));
assertTrue("Name is missing", msgs.get(0).contains("Name=John Smith"));
try {
final Logger logger = Logger.getLogger("org.apache.test.logging");
logger.debug("This is a test");
final ListAppender listApp = (ListAppender) CTX.getAppender("List");
assertNotNull(listApp);
final List<String> msgs = listApp.getMessages();
assertNotNull("No messages received", msgs);
assertTrue(msgs.size() == 1);
assertTrue("Type is missing", msgs.get(0).contains("Type=Service"));
assertTrue("Name is missing", msgs.get(0).contains("Name=John Smith"));
} finally {
MDC.remove("Type");
MDC.remove("Name");
}
}
}
......@@ -21,12 +21,17 @@ import static org.junit.Assert.assertEquals;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.impl.ContextDataFactory;
import org.apache.logging.log4j.core.impl.Log4jLogEvent;
import org.apache.logging.log4j.junit.ThreadContextRule;
import org.apache.logging.log4j.message.SimpleMessage;
import org.apache.logging.log4j.util.StringMap;
import org.junit.Rule;
import org.junit.Test;
public class Log4j1XmlLayoutTest {
@Rule
public ThreadContextRule threadContextRule = new ThreadContextRule();
@Test
public void testWithoutThrown() {
final Log4j1XmlLayout layout = Log4j1XmlLayout.createLayout(false, true);
......
......@@ -20,7 +20,7 @@
<parent>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j</artifactId>
<version>2.11.0</version>
<version>2.11.1</version>
<relativePath>../</relativePath>
</parent>
<artifactId>log4j-api-java9</artifactId>
......@@ -60,7 +60,7 @@
<configuration>
<toolchains>
<jdk>
<version>9</version>
<version>[9, )</version>
</jdk>
</toolchains>
</configuration>
......
......@@ -20,7 +20,7 @@
<parent>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j</artifactId>
<version>2.11.0</version>
<version>2.11.1</version>
<relativePath>../</relativePath>
</parent>
<artifactId>log4j-api</artifactId>
......
/*
* 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.logging.log4j.message;
/**
* {@link Clearable} objects may be reset to a reusable state.
*
* This type should be combined into {@link ReusableMessage} as a default method for 3.0.
*
* @since 2.11.1
*/
interface Clearable {
/**
* Resets the object to a clean state.
*/
void clear();
}
......@@ -77,15 +77,15 @@ public final class ReusableMessageFactory implements MessageFactory2, Serializab
}
/**
* Switches the {@code reserved} flag off if the specified message is a ReusableParameterizedMessage,
* otherwise does nothing. This flag is used internally to verify that a reusable message is no longer in use and
* Invokes {@link Clearable#clear()} when possible.
* This flag is used internally to verify that a reusable message is no longer in use and
* can be reused.
* @param message the message to make available again
* @since 2.7
*/
public static void release(final Message message) { // LOG4J2-1583
if (message instanceof ReusableParameterizedMessage) {
((ReusableParameterizedMessage) message).reserved = false;
if (message instanceof Clearable) {
((Clearable) message).clear();
}
}
......
......@@ -24,7 +24,7 @@ import org.apache.logging.log4j.util.StringBuilders;
* @since 2.6
*/
@PerformanceSensitive("allocation")
public class ReusableObjectMessage implements ReusableMessage, ParameterVisitable {
public class ReusableObjectMessage implements ReusableMessage, ParameterVisitable, Clearable {
private static final long serialVersionUID = 6922476812535519960L;
private transient Object obj;
......@@ -121,4 +121,9 @@ public class ReusableObjectMessage implements ReusableMessage, ParameterVisitabl
public Message memento() {
return new ObjectMessage(obj);
}
@Override
public void clear() {
obj = null;
}
}
......@@ -30,7 +30,7 @@ import org.apache.logging.log4j.util.StringBuilders;
* @since 2.6
*/
@PerformanceSensitive("allocation")
public class ReusableParameterizedMessage implements ReusableMessage, ParameterVisitable {
public class ReusableParameterizedMessage implements ReusableMessage, ParameterVisitable, Clearable {
private static final int MIN_BUILDER_SIZE = 512;
private static final int MAX_PARMS = 10;
......@@ -341,4 +341,14 @@ public class ReusableParameterizedMessage implements ReusableMessage, ParameterV
return "ReusableParameterizedMessage[messagePattern=" + getFormat() + ", stringArgs=" +
Arrays.toString(getParameters()) + ", throwable=" + getThrowable() + ']';
}
@Override
public void clear() { // LOG4J2-1583
// This method does not clear parameter values, those are expected to be swapped to a
// reusable message, which is responsible for clearing references.
reserved = false;
varargs = null;
messagePattern = null;
throwable = null;
}
}
......@@ -23,7 +23,7 @@ import org.apache.logging.log4j.util.PerformanceSensitive;
* @since 2.6
*/
@PerformanceSensitive("allocation")
public class ReusableSimpleMessage implements ReusableMessage, CharSequence, ParameterVisitable {
public class ReusableSimpleMessage implements ReusableMessage, CharSequence, ParameterVisitable, Clearable {
private static final long serialVersionUID = -9199974506498249809L;
private static Object[] EMPTY_PARAMS = new Object[0];
private CharSequence charSequence;
......@@ -105,5 +105,10 @@ public class ReusableSimpleMessage implements ReusableMessage, CharSequence, Par
public CharSequence subSequence(final int start, final int end) {
return charSequence.subSequence(start, end);
}
@Override
public void clear() {
charSequence = null;
}
}
......@@ -2181,7 +2181,8 @@ public abstract class AbstractLogger implements ExtendedLogger, Serializable {
throw (LoggingException) exception;
}
final String format = msg.getFormat();
final StringBuilder sb = new StringBuilder(format.length() + 100);
final int formatLength = format == null ? 4 : format.length();
final StringBuilder sb = new StringBuilder(formatLength + 100);
sb.append(fqcn);
sb.append(" caught ");
sb.append(exception.getClass().getName());
......
......@@ -100,7 +100,7 @@ public class Activator implements BundleActivator, SynchronousBundleListener {
}
private void loadProvider(final BundleContext bundleContext, final BundleWiring bundleWiring) {
final String filter = "(APIVersion>=2.60)";
final String filter = "(APIVersion>=2.6.0)";
try {
final Collection<ServiceReference<Provider>> serviceReferences = bundleContext.getServiceReferences(Provider.class, filter);
Provider maxProvider = null;
......
......@@ -109,21 +109,23 @@ public final class LoaderUtil {
List<ClassLoader> classLoaders = new ArrayList<>();
ClassLoader tcl = getThreadContextClassLoader();
classLoaders.add(tcl);
// Some implementations may use null to represent the bootstrap class loader.
ClassLoader current = LoaderUtil.class.getClassLoader();
if (current != tcl) {
if (current != null && current != tcl) {
classLoaders.add(current);
ClassLoader parent = current.getParent();
while (parent != null && !classLoaders.contains(parent)) {
classLoaders.add(parent);
}
}
ClassLoader parent = tcl.getParent();
ClassLoader parent = tcl == null ? null : tcl.getParent();
while (parent != null && !classLoaders.contains(parent)) {
classLoaders.add(parent);
parent = parent.getParent();
}
if (!classLoaders.contains(ClassLoader.getSystemClassLoader())) {
classLoaders.add(ClassLoader.getSystemClassLoader());
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
if (!classLoaders.contains(systemClassLoader)) {
classLoaders.add(systemClassLoader);
}
return classLoaders.toArray(new ClassLoader[classLoaders.size()]);
}
......
......@@ -330,13 +330,15 @@ public final class PropertiesUtil {
source.forEach(new BiConsumer<String, String>() {
@Override
public void accept(final String key, final String value) {
literal.put(key, value);
final List<CharSequence> tokens = PropertySource.Util.tokenize(key);
if (tokens.isEmpty()) {
normalized.put(source.getNormalForm(Collections.singleton(key)), value);
} else {
normalized.put(source.getNormalForm(tokens), value);
tokenized.put(tokens, value);
if (key != null && value != null) {
literal.put(key, value);
final List<CharSequence> tokens = PropertySource.Util.tokenize(key);
if (tokens.isEmpty()) {
normalized.put(source.getNormalForm(Collections.singleton(key)), value);
} else {
normalized.put(source.getNormalForm(tokens), value);
tokenized.put(tokens, value);
}
}
}
});
......
......@@ -100,14 +100,18 @@ public final class ProviderUtil {
}
}
protected static void loadProviders(final ClassLoader cl) {
final ServiceLoader<Provider> serviceLoader = ServiceLoader.load(Provider.class, cl);
for (final Provider provider : serviceLoader) {
if (validVersion(provider.getVersions()) && !PROVIDERS.contains(provider)) {
PROVIDERS.add(provider);
}
}
}
/**
*
* @param classLoader null can be used to mark the bootstrap class loader.
*/
protected static void loadProviders(final ClassLoader classLoader) {
final ServiceLoader<Provider> serviceLoader = ServiceLoader.load(Provider.class, classLoader);
for (final Provider provider : serviceLoader) {
if (validVersion(provider.getVersions()) && !PROVIDERS.contains(provider)) {
PROVIDERS.add(provider);
}
}
}
/**
* @deprecated Use {@link #loadProvider(java.net.URL, ClassLoader)} instead. Will be removed in 3.0.
......
......@@ -169,77 +169,143 @@ public final class StringBuilders {
}
public static void escapeJson(final StringBuilder toAppendTo, final int start) {
for (int i = toAppendTo.length() - 1; i >= start; i--) { // backwards: length may change
int escapeCount = 0;
for (int i = start; i < toAppendTo.length(); i++) {
final char c = toAppendTo.charAt(i);
switch (c) {
case '\b':
toAppendTo.setCharAt(i, '\\');
toAppendTo.insert(i + 1, 'b');
case '\t':
case '\f':
case '\n':
case '\r':
case '"':
case '\\':
escapeCount++;
break;
default:
if (Character.isISOControl(c)) {
escapeCount += 5;
}
}
}
int lastChar = toAppendTo.length() - 1;
toAppendTo.setLength(toAppendTo.length() + escapeCount);
int lastPos = toAppendTo.length() - 1;
for (int i = lastChar; lastPos > i; i--) {
final char c = toAppendTo.charAt(i);
switch (c) {
case '\b':
lastPos = escapeAndDecrement(toAppendTo, lastPos, 'b');
break;
case '\t':
toAppendTo.setCharAt(i, '\\');
toAppendTo.insert(i + 1, 't');
lastPos = escapeAndDecrement(toAppendTo, lastPos, 't');
break;
case '\f':
toAppendTo.setCharAt(i, '\\');
toAppendTo.insert(i + 1, 'f');
lastPos = escapeAndDecrement(toAppendTo, lastPos, 'f');
break;
case '\n':
// Json string newline character must be encoded as literal "\n"
toAppendTo.setCharAt(i, '\\');
toAppendTo.insert(i + 1, 'n');
lastPos = escapeAndDecrement(toAppendTo, lastPos, 'n');
break;
case '\r':
toAppendTo.setCharAt(i, '\\');
toAppendTo.insert(i + 1, 'r');
lastPos = escapeAndDecrement(toAppendTo, lastPos, 'r');
break;
case '"':
case '\\':
// only " and \ need to be escaped; other escapes are optional
toAppendTo.insert(i, '\\');
lastPos = escapeAndDecrement(toAppendTo, lastPos, c);
break;
default:
if (Character.isISOControl(c)) {
// all iso control characters are in U+00xx
toAppendTo.setCharAt(i, '\\');
toAppendTo.insert(i + 1, "u0000");
toAppendTo.setCharAt(i + 4, Chars.getUpperCaseHex((c & 0xF0) >> 4));
toAppendTo.setCharAt(i + 5, Chars.getUpperCaseHex(c & 0xF));
// all iso control characters are in U+00xx, JSON output format is "\\u00XX"
toAppendTo.setCharAt(lastPos--, Chars.getUpperCaseHex(c & 0xF));
toAppendTo.setCharAt(lastPos--, Chars.getUpperCaseHex((c & 0xF0) >> 4));
toAppendTo.setCharAt(lastPos--, '0');
toAppendTo.setCharAt(lastPos--, '0');
toAppendTo.setCharAt(lastPos--, 'u');
toAppendTo.setCharAt(lastPos--, '\\');
} else {
toAppendTo.setCharAt(lastPos, c);
lastPos--;
}
}
}
}
private static int escapeAndDecrement(StringBuilder toAppendTo, int lastPos, char c) {
toAppendTo.setCharAt(lastPos--, c);
toAppendTo.setCharAt(lastPos--, '\\');
return lastPos;
}
public static void escapeXml(final StringBuilder toAppendTo, final int start) {
for (int i = toAppendTo.length() - 1; i >= start; i--) { // backwards: length may change
int escapeCount = 0;
for (int i = start; i < toAppendTo.length(); i++) {
final char c = toAppendTo.charAt(i);
switch (c) {
case '&':
escapeCount += 4;
break;
case '<':
case '>':
escapeCount += 3;
break;
case '"':
case '\'':
escapeCount += 5;
}
}
int lastChar = toAppendTo.length() - 1;
toAppendTo.setLength(toAppendTo.length() + escapeCount);
int lastPos = toAppendTo.length() - 1;
for (int i = lastChar; lastPos > i; i--) {
final char c = toAppendTo.charAt(i);
switch (c) {
case '&':
toAppendTo.setCharAt(i, '&');
toAppendTo.insert(i + 1, "amp;");
toAppendTo.setCharAt(lastPos--, ';');
toAppendTo.setCharAt(lastPos--, 'p');
toAppendTo.setCharAt(lastPos--, 'm');
toAppendTo.setCharAt(lastPos--, 'a');
toAppendTo.setCharAt(lastPos--, '&');
break;
case '<':
toAppendTo.setCharAt(i, '&');
toAppendTo.insert(i + 1, "lt;");
toAppendTo.setCharAt(lastPos--, ';');
toAppendTo.setCharAt(lastPos--, 't');
toAppendTo.setCharAt(lastPos--, 'l');
toAppendTo.setCharAt(lastPos--, '&');
break;
case '>':
toAppendTo.setCharAt(i, '&');
toAppendTo.insert(i + 1, "gt;");
toAppendTo.setCharAt(lastPos--, ';');
toAppendTo.setCharAt(lastPos--, 't');
toAppendTo.setCharAt(lastPos--, 'g');
toAppendTo.setCharAt(lastPos--, '&');
break;
case '"':
toAppendTo.setCharAt(i, '&');
toAppendTo.insert(i + 1, "quot;");
toAppendTo.setCharAt(lastPos--, ';');
toAppendTo.setCharAt(lastPos--, 't');
toAppendTo.setCharAt(lastPos--, 'o');
toAppendTo.setCharAt(lastPos--, 'u');
toAppendTo.setCharAt(lastPos--, 'q');
toAppendTo.setCharAt(lastPos--, '&');
break;
case '\'':
toAppendTo.setCharAt(i, '&');
toAppendTo.insert(i + 1, "apos;");
toAppendTo.setCharAt(lastPos--, ';');
toAppendTo.setCharAt(lastPos--, 's');
toAppendTo.setCharAt(lastPos--, 'o');
toAppendTo.setCharAt(lastPos--, 'p');
toAppendTo.setCharAt(lastPos--, 'a');
toAppendTo.setCharAt(lastPos--, '&');
break;
default:
toAppendTo.setCharAt(lastPos--, c);
}
}
}
......
......@@ -16,12 +16,15 @@
*/
package org.apache.logging.log4j;
import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.apache.logging.log4j.junit.StatusLoggerRule;
import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.message.ObjectMessage;
import org.apache.logging.log4j.message.ParameterizedMessage;
......@@ -29,10 +32,15 @@ import org.apache.logging.log4j.message.ParameterizedMessageFactory;
import org.apache.logging.log4j.message.SimpleMessage;
import org.apache.logging.log4j.spi.AbstractLogger;
import org.apache.logging.log4j.spi.MessageFactory2Adapter;
import org.apache.logging.log4j.status.StatusData;
import org.apache.logging.log4j.status.StatusLogger;
import org.apache.logging.log4j.util.MessageSupplier;
import org.apache.logging.log4j.util.Supplier;
import org.junit.Rule;
import org.junit.Test;
import java.util.List;
/**
*
*/
......@@ -59,6 +67,9 @@ public class AbstractLoggerTest {
private static final Marker MARKER = MarkerManager.getMarker("TEST");
private static final String MARKER_NAME = "TEST";
@Rule
public StatusLoggerRule status = new StatusLoggerRule(Level.WARN);
private static final LogEvent[] EVENTS = new LogEvent[] {
new LogEvent(null, simple, null),
new LogEvent(MARKER_NAME, simple, null),
......@@ -902,6 +913,73 @@ public class AbstractLoggerTest {
logger.log(Level.INFO, MARKER, supplier);
}
@Test
public void testMessageThrows() {
final ThrowableExpectingLogger logger = new ThrowableExpectingLogger(false);
logger.error(new TestMessage(new TestMessage.FormattedMessageSupplier() {
@Override
public String getFormattedMessage() {
throw new IllegalStateException("Oops!");
}
}, "Message Format"));
List<StatusData> statusDatalist = StatusLogger.getLogger().getStatusData();
StatusData mostRecent = statusDatalist.get(statusDatalist.size() - 1);
assertEquals(Level.WARN, mostRecent.getLevel());
assertThat(mostRecent.getFormattedStatus(), containsString(
"org.apache.logging.log4j.spi.AbstractLogger caught " +
"java.lang.IllegalStateException logging TestMessage: Message Format"));
}
@Test
public void testMessageThrowsAndNullFormat() {
final ThrowableExpectingLogger logger = new ThrowableExpectingLogger(false);
logger.error(new TestMessage(new TestMessage.FormattedMessageSupplier() {
@Override
public String getFormattedMessage() {
throw new IllegalStateException("Oops!");
}
}, null /* format */));
List<StatusData> statusDatalist = StatusLogger.getLogger().getStatusData();
StatusData mostRecent = statusDatalist.get(statusDatalist.size() - 1);
assertEquals(Level.WARN, mostRecent.getLevel());
assertThat(mostRecent.getFormattedStatus(), containsString(
"org.apache.logging.log4j.spi.AbstractLogger caught " +
"java.lang.IllegalStateException logging TestMessage: "));
}
private static final class TestMessage implements Message {
private final FormattedMessageSupplier formattedMessageSupplier;
private final String format;
TestMessage(FormattedMessageSupplier formattedMessageSupplier, String format) {
this.formattedMessageSupplier = formattedMessageSupplier;
this.format = format;
}