Skip to content

Commit 001aaad

Browse files
carterkozakrgoers
authored andcommitted
LOG4J2-3198: Log4j2 no longer formats lookups in messages by default
Lookups in messages are confusing, and muddy the line between logging APIs and implementation. Given a particular API, there's an expectation that a particular shape of call will result in specific results. However, lookups in messages can be passed into JUL and will result in resolved output in log4j formatted output, but not any other implementations despite no direct dependency on those implementations. There's also a cost to searching formatted message strings for particular escape sequences which define lookups. This feature is not used as far as we've been able to tell searching github and stackoverflow, so it's unnecessary for every log event in every application to burn several cpu cycles searching for the value.
1 parent c77b3cb commit 001aaad

File tree

11 files changed

+84
-54
lines changed

11 files changed

+84
-54
lines changed

���log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/MessagePatternConverter.java‎

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@
1616
*/
1717
package org.apache.logging.log4j.core.pattern;
1818

19+
import java.util.ArrayList;
20+
import java.util.List;
1921
import java.util.Locale;
2022

2123
import org.apache.logging.log4j.core.LogEvent;
2224
import org.apache.logging.log4j.core.config.Configuration;
2325
import org.apache.logging.log4j.core.config.plugins.Plugin;
24-
import org.apache.logging.log4j.core.util.ArrayUtils;
25-
import org.apache.logging.log4j.core.util.Constants;
2626
import org.apache.logging.log4j.core.util.Loader;
2727
import org.apache.logging.log4j.message.Message;
2828
import org.apache.logging.log4j.message.MultiformatMessage;
@@ -39,17 +39,18 @@
3939
@PerformanceSensitive("allocation")
4040
public class MessagePatternConverter extends LogEventPatternConverter {
4141

42+
private static final String LOOKUPS = "lookups";
4243
private static final String NOLOOKUPS = "nolookups";
4344

4445
private MessagePatternConverter() {
4546
super("Message", "message");
4647
}
4748

48-
private static int loadNoLookups(final String[] options) {
49+
private static int loadLookups(final String[] options) {
4950
if (options != null) {
5051
for (int i = 0; i < options.length; i++) {
5152
final String option = options[i];
52-
if (NOLOOKUPS.equalsIgnoreCase(option)) {
53+
if (LOOKUPS.equalsIgnoreCase(option)) {
5354
return i;
5455
}
5556
}
@@ -86,14 +87,13 @@ private static TextRenderer loadMessageRenderer(final String[] options) {
8687
* @return instance of pattern converter.
8788
*/
8889
public static MessagePatternConverter newInstance(final Configuration config, final String[] options) {
89-
int noLookupsIdx = loadNoLookups(options);
90-
boolean noLookups = Constants.FORMAT_MESSAGES_PATTERN_DISABLE_LOOKUPS || noLookupsIdx >= 0;
91-
String[] formats = noLookupsIdx >= 0 ? ArrayUtils.remove(options, noLookupsIdx) : options;
92-
TextRenderer textRenderer = loadMessageRenderer(noLookupsIdx >= 0 ? ArrayUtils.remove(options, noLookupsIdx) : options);
90+
boolean lookups = loadLookups(options) >= 0;
91+
String[] formats = withoutLookupOptions(options);
92+
TextRenderer textRenderer = loadMessageRenderer(formats);
9393
MessagePatternConverter result = formats == null || formats.length == 0
9494
? SimpleMessagePatternConverter.INSTANCE
9595
: new FormattedMessagePatternConverter(formats);
96-
if (!noLookups && config != null) {
96+
if (lookups && config != null) {
9797
result = new LookupMessagePatternConverter(result, config);
9898
}
9999
if (textRenderer != null) {
@@ -102,6 +102,19 @@ public static MessagePatternConverter newInstance(final Configuration config, fi
102102
return result;
103103
}
104104

105+
private static String[] withoutLookupOptions(final String[] options) {
106+
if (options == null || options.length == 0) {
107+
return options;
108+
}
109+
List<String> results = new ArrayList<>(options.length);
110+
for (String option : options) {
111+
if (!LOOKUPS.equalsIgnoreCase(option) && !NOLOOKUPS.equalsIgnoreCase(option)) {
112+
results.add(option);
113+
}
114+
}
115+
return results.toArray(new String[0]);
116+
}
117+
105118
@Override
106119
public void format(final LogEvent event, final StringBuilder toAppendTo) {
107120
throw new UnsupportedOperationException();

‎log4j-core/src/main/java/org/apache/logging/log4j/core/util/Constants.java‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,17 @@ public final class Constants {
5555
"log4j.format.msg.async", false);
5656

5757
/**
58-
* LOG4J2-2109 if {@code true}, MessagePatternConverter will always operate as though
59-
* <pre>%m{nolookups}</pre> is configured.
58+
* LOG4J2-3198 property which used to globally opt out of lookups in pattern layout message text, however
59+
* this is the default and this property is no longer read.
60+
*
61+
* Deprecated in 2.15.
6062
*
6163
* @since 2.10
64+
* @deprecated no longer used, lookups are only used when {@code %m{lookups}} is specified
6265
*/
66+
@Deprecated
6367
public static final boolean FORMAT_MESSAGES_PATTERN_DISABLE_LOOKUPS = PropertiesUtil.getProperties().getBooleanProperty(
64-
"log4j2.formatMsgNoLookups", false);
68+
"log4j2.formatMsgNoLookups", true);
6569

6670
/**
6771
* {@code true} if we think we are running in a web container, based on the boolean value of system property

���log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutLookupDateTest.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
*
3030
* This shows the behavior this user wants to disable.
3131
*/
32-
@LoggerContextSource("log4j-list.xml")
32+
@LoggerContextSource("log4j-list-lookups.xml")
3333
public class PatternLayoutLookupDateTest {
3434

3535
@Test

‎log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutNoLookupDateTest.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
/**
2727
* See (LOG4J2-905) Ability to disable (date) lookup completely, compatibility issues with other libraries like camel.
2828
*/
29-
@LoggerContextSource("log4j-list-nolookups.xml")
29+
@LoggerContextSource("log4j-list.xml")
3030
public class PatternLayoutNoLookupDateTest {
3131

3232
@Test

‎log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/MessagePatternConverterTest.java‎

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import org.apache.logging.log4j.core.config.DefaultConfiguration;
2323
import org.apache.logging.log4j.core.config.builder.impl.DefaultConfigurationBuilder;
2424
import org.apache.logging.log4j.core.impl.Log4jLogEvent;
25-
import org.apache.logging.log4j.core.util.Constants;
2625
import org.apache.logging.log4j.message.Message;
2726
import org.apache.logging.log4j.message.ParameterizedMessage;
2827
import org.apache.logging.log4j.message.SimpleMessage;
@@ -76,12 +75,7 @@ public void testPatternAndParameterizedMessageDateLookup() {
7675
}
7776

7877
@Test
79-
public void testLookupEnabledByDefault() {
80-
assertFalse(Constants.FORMAT_MESSAGES_PATTERN_DISABLE_LOOKUPS, "Expected lookups to be enabled");
81-
}
82-
83-
@Test
84-
public void testLookup() {
78+
public void testDefaultDisabledLookup() {
8579
final Configuration config = new DefaultConfigurationBuilder()
8680
.addProperty("foo", "bar")
8781
.build(true);
@@ -93,7 +87,7 @@ public void testLookup() {
9387
.setMessage(msg).build();
9488
final StringBuilder sb = new StringBuilder();
9589
converter.format(event, sb);
96-
assertEquals("bar", sb.toString(), "Unexpected result");
90+
assertEquals("${foo}", sb.toString(), "Unexpected result");
9791
}
9892

9993
@Test
@@ -113,6 +107,23 @@ public void testDisabledLookup() {
113107
assertEquals("${foo}", sb.toString(), "Expected the raw pattern string without lookup");
114108
}
115109

110+
@Test
111+
public void testLookup() {
112+
final Configuration config = new DefaultConfigurationBuilder()
113+
.addProperty("foo", "bar")
114+
.build(true);
115+
final MessagePatternConverter converter =
116+
MessagePatternConverter.newInstance(config, new String[] {"lookups"});
117+
final Message msg = new ParameterizedMessage("${foo}");
118+
final LogEvent event = Log4jLogEvent.newBuilder() //
119+
.setLoggerName("MyLogger") //
120+
.setLevel(Level.DEBUG) //
121+
.setMessage(msg).build();
122+
final StringBuilder sb = new StringBuilder();
123+
converter.format(event, sb);
124+
assertEquals("bar", sb.toString(), "Unexpected result");
125+
}
126+
116127
@Test
117128
public void testPatternWithConfiguration() {
118129
final Configuration config = new DefaultConfiguration();

‎log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/RegexReplacementTest.java‎

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@
1616
*/
1717
package org.apache.logging.log4j.core.pattern;
1818

19+
import static org.junit.jupiter.api.Assertions.assertEquals;
20+
import static org.junit.jupiter.api.Assertions.assertNotNull;
21+
import static org.junit.jupiter.api.Assertions.assertTrue;
22+
23+
import java.util.List;
24+
1925
import org.apache.logging.log4j.ThreadContext;
2026
import org.apache.logging.log4j.core.LoggerContext;
2127
import org.apache.logging.log4j.junit.LoggerContextSource;
@@ -25,10 +31,6 @@
2531
import org.apache.logging.log4j.util.Strings;
2632
import org.junit.jupiter.api.Test;
2733

28-
import java.util.List;
29-
30-
import static org.junit.jupiter.api.Assertions.*;
31-
3234
@LoggerContextSource("log4j-replace.xml")
3335
@UsingThreadContextMap
3436
public class RegexReplacementTest {
@@ -55,10 +57,14 @@ public void testReplacement() {
5557
assertEquals(1, msgs.size(), "Incorrect number of messages. Should be 1 is " + msgs.size());
5658
assertTrue(
5759
msgs.get(0).endsWith(EXPECTED), "Replacement failed - expected ending " + EXPECTED + " Actual " + msgs.get(0));
58-
app.clear();
60+
61+
}
62+
63+
@Test
64+
public void testMessageReplacement() {
5965
ThreadContext.put("MyKey", "Apache");
6066
logger.error("This is a test for ${ctx:MyKey}");
61-
msgs = app.getMessages();
67+
List<String> msgs = app.getMessages();
6268
assertNotNull(msgs);
6369
assertEquals(1, msgs.size(), "Incorrect number of messages. Should be 1 is " + msgs.size());
6470
assertEquals("LoggerTest This is a test for Apache" + Strings.LINE_SEPARATOR, msgs.get(0));

‎log4j-core/src/test/resources/log4j-list-nolookups.xml‎ renamed to ‎log4j-core/src/test/resources/log4j-list-lookups.xml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
<Configuration status="WARN">
1919
<Appenders>
2020
<List name="List">
21-
<PatternLayout pattern="[%-5level] %c{1.} %msg{ansi}{nolookups}%n" />
21+
<PatternLayout pattern="[%-5level] %c{1.} %msg{ansi}{lookups}%n" />
2222
</List>
2323
</Appenders>
2424
<Loggers>

‎log4j-core/src/test/resources/log4j-replace.xml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@
2121
<List name="List">
2222
<PatternLayout>
2323
<replace regex="\." replacement="/"/>
24-
<Pattern>%logger %msg%n</Pattern>
24+
<Pattern>%logger %msg{lookups}%n</Pattern>
2525
</PatternLayout>
2626
</List>
2727
<List name="List2">
2828
<PatternLayout>
29-
<Pattern>%replace{%logger %C{1.} %msg%n}{\.}{/}</Pattern>
29+
<Pattern>%replace{%logger %C{1.} %msg{lookups}%n}{\.}{/}</Pattern>
3030
</PatternLayout>
3131
</List>
3232
</Appenders>

‎src/changes/changes.xml‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@
3131
-->
3232
<release version="2.15.0" date="2021-MM-DD" description="GA Release 2.15.0">
3333
<!-- ADDS -->
34+
<action issue="LOG4J2-3198" dev="ckozak" type="add">
35+
Pattern layout no longer enables lookups within message text by default for cleaner API boundaries and reduced
36+
formatting overhead. The old 'log4j2.formatMsgNoLookups' which enabled this behavior has been removed as well
37+
as the 'nolookups' message pattern converter option. The old behavior can be enabled on a per-pattern basis
38+
using '%m{lookups}'.
39+
</action>
3440
<action issue="LOG4J2-3194" dev="rgoers" type="add" due-to="markuss">
3541
Allow fractional attributes for size attribute of SizeBsaedTriggeringPolicy.
3642
</action>

‎src/site/xdoc/manual/configuration.xml.vm‎

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1264,14 +1264,13 @@ rootLogger.appenderRef.stdout.ref = STDOUT
12641264
<code>app.properties</code> would be used as the default value.
12651265
</p>
12661266
</subsection>
1267-
<a name="DisablingMessagePatternLookups"/>
1268-
<subsection name="Disables Message Pattern Lookups">
1267+
<a name="EnablingMessagePatternLookups"/>
1268+
<subsection name="Enabling Message Pattern Lookups">
12691269
<p>
1270-
A message is processed (by default) by lookups, for example if you defined
1270+
A message is processed (by default) without using lookups, for example if you defined
12711271
<code> &lt;Property name="foo.bar">FOO_BAR &lt;/Property></code>, then <code>logger.info("${foo.bar}")</code>
1272-
will output <code>FOO_BAR</code> instead of <code>${dollar}{foo.bar}</code>. You could disable message pattern
1273-
lookups globally by setting system property <code>log4j2.formatMsgNoLookups</code> to true,
1274-
or defining message pattern using %m{nolookups}.
1272+
will output <code>${dollar}{foo.bar}</code> instead of <code>FOO_BAR</code>. You could enable message pattern
1273+
lookups by defining message pattern using %m{lookups}.
12751274
</p>
12761275
</subsection>
12771276
<a name="RuntimeLookup"/>
@@ -2672,16 +2671,6 @@ public class AwesomeTest {
26722671
<td>Prints a stacktrace to the <a href="#StatusMessages">status logger</a> at DEBUG level
26732672
when the LoggerContext is started. For debug purposes.</td>
26742673
</tr>
2675-
<tr>
2676-
<td><a name="formatMsgNoLookups"/>log4j2.formatMsgNoLookups
2677-
<br />
2678-
(<a name="log4j2.formatMsgNoLookups" />log4j2.formatMsgNoLookups)
2679-
</td>
2680-
<td>FORMAT_MESSAGES_PATTERN_DISABLE_LOOKUPS</td>
2681-
<td>false</td>
2682-
<td>Disables message pattern lookups globally when set to <tt>true</tt>.
2683-
This is equivalent to defining all message patterns using <tt>%m{nolookups}</tt>.</td>
2684-
</tr>
26852674
<tr>
26862675
<td><a name="log4j2.trustStoreLocation "/>log4j2.trustStoreLocation</td>
26872676
<td>LOG4J_TRUST_STORE_LOCATION</td>

0 commit comments

Comments
 (0)