Skip to content

Commit db8604c

Browse files
committed
Don't fail on insufficient parameters in ParameterFormatter (#2337)
1 parent c542041 commit db8604c

File tree

4 files changed

+43
-6
lines changed

4 files changed

+43
-6
lines changed

log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/UsingStatusLoggerMock.java

+2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.lang.annotation.Retention;
2525
import java.lang.annotation.Target;
2626
import org.junit.jupiter.api.extension.ExtendWith;
27+
import org.junit.jupiter.api.parallel.ResourceLock;
2728

2829
/**
2930
* Shortcut to {@link StatusLoggerMockExtension}.
@@ -32,4 +33,5 @@
3233
@Target({TYPE, METHOD})
3334
@Documented
3435
@ExtendWith({ExtensionContextAnchor.class, StatusLoggerMockExtension.class})
36+
@ResourceLock("log4j2.StatusLogger")
3537
public @interface UsingStatusLoggerMock {}

log4j-api-test/src/test/java/org/apache/logging/log4j/message/ParameterFormatterTest.java

+24-3
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,27 @@
1717
package org.apache.logging.log4j.message;
1818

1919
import static org.assertj.core.api.Assertions.assertThat;
20+
import static org.mockito.ArgumentMatchers.eq;
21+
import static org.mockito.Mockito.verify;
2022

2123
import java.util.ArrayList;
2224
import java.util.Arrays;
2325
import java.util.Collections;
2426
import java.util.List;
2527
import org.apache.logging.log4j.message.ParameterFormatter.MessagePatternAnalysis;
28+
import org.apache.logging.log4j.status.StatusLogger;
29+
import org.apache.logging.log4j.test.junit.UsingStatusLoggerMock;
2630
import org.junit.jupiter.api.Test;
2731
import org.junit.jupiter.params.ParameterizedTest;
2832
import org.junit.jupiter.params.provider.CsvSource;
2933
import org.junit.jupiter.params.provider.MethodSource;
34+
import org.mockito.ArgumentCaptor;
3035

3136
/**
3237
* Tests {@link ParameterFormatter}.
3338
*/
34-
public class ParameterFormatterTest {
39+
@UsingStatusLoggerMock
40+
class ParameterFormatterTest {
3541

3642
@ParameterizedTest
3743
@CsvSource({
@@ -49,7 +55,7 @@ public class ParameterFormatterTest {
4955
"4,0:2:4:10,false,{}{}{}a{]b{}",
5056
"5,0:2:4:7:10,false,{}{}{}a{}b{}"
5157
})
52-
public void test_pattern_analysis(
58+
void test_pattern_analysis(
5359
final int placeholderCount,
5460
final String placeholderCharIndicesString,
5561
final boolean escapedPlaceholderFound,
@@ -65,9 +71,24 @@ public void test_pattern_analysis(
6571
}
6672
}
6773

74+
@ParameterizedTest
75+
@CsvSource({"1,foo {}", "2,bar {}{}"})
76+
void insufficient_args_should_not_throw_an_exception(final int placeholderCount, final String pattern) {
77+
final int argCount = placeholderCount - 1;
78+
final String formattedPattern = ParameterFormatter.format(pattern, new Object[argCount], argCount);
79+
assertThat(formattedPattern).isEqualTo(pattern);
80+
final ArgumentCaptor<Throwable> errorCaptor = ArgumentCaptor.forClass(Throwable.class);
81+
verify(StatusLogger.getLogger()).error(eq("parameter formatting failure"), errorCaptor.capture());
82+
final Throwable error = errorCaptor.getValue();
83+
assertThat(error)
84+
.hasMessage(
85+
"found %d argument placeholders, but provided %d for pattern `%s`",
86+
placeholderCount, argCount, pattern);
87+
}
88+
6889
@ParameterizedTest
6990
@MethodSource("messageFormattingTestCases")
70-
void assertMessageFormatting(
91+
void test_message_formatting(
7192
final String pattern, final Object[] args, final int argCount, final String expectedFormattedMessage) {
7293
MessagePatternAnalysis analysis = ParameterFormatter.analyzePattern(pattern, -1);
7394
final StringBuilder buffer = new StringBuilder();

log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterFormatter.java

+10-3
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
import java.util.IdentityHashMap;
2727
import java.util.Map;
2828
import java.util.Set;
29+
import org.apache.logging.log4j.Logger;
30+
import org.apache.logging.log4j.status.StatusLogger;
2931
import org.apache.logging.log4j.util.StringBuilders;
3032

3133
/**
@@ -62,6 +64,8 @@ final class ParameterFormatter {
6264
private static final char DELIM_STOP = '}';
6365
private static final char ESCAPE_CHAR = '\\';
6466

67+
private static final Logger STATUS_LOGGER = StatusLogger.getLogger();
68+
6569
private static final DateTimeFormatter DATE_FORMATTER =
6670
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ").withZone(ZoneId.systemDefault());
6771

@@ -236,7 +240,10 @@ static void formatMessage(
236240
final String message = String.format(
237241
"found %d argument placeholders, but provided %d for pattern `%s`",
238242
analysis.placeholderCount, args.length, pattern);
239-
throw new IllegalArgumentException(message);
243+
final Throwable error = new IllegalArgumentException(message);
244+
STATUS_LOGGER.error("parameter formatting failure", error);
245+
buffer.append(pattern);
246+
return;
240247
}
241248

242249
// Fast-path for patterns containing no escapes
@@ -250,7 +257,7 @@ static void formatMessage(
250257
}
251258
}
252259

253-
static void formatMessageContainingNoEscapes(
260+
private static void formatMessageContainingNoEscapes(
254261
final StringBuilder buffer,
255262
final String pattern,
256263
final Object[] args,
@@ -271,7 +278,7 @@ static void formatMessageContainingNoEscapes(
271278
buffer.append(pattern, precedingTextStartIndex, pattern.length());
272279
}
273280

274-
static void formatMessageContainingEscapes(
281+
private static void formatMessageContainingEscapes(
275282
final StringBuilder buffer,
276283
final String pattern,
277284
final Object[] args,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<entry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xmlns="http://logging.apache.org/log4j/changelog"
4+
xsi:schemaLocation="http://logging.apache.org/log4j/changelog https://logging.apache.org/log4j/changelog-0.1.3.xsd"
5+
type="fixed">
6+
<description format="asciidoc">Fix that parameterized message formatting doesn't throw an exception when there are insufficient number of parameters</description>
7+
</entry>

0 commit comments

Comments
 (0)