Skip to content

When the message contains a placeholder({}) but the arguments is 0, an exception will be thrown #2355

@panbingkun

Description

@panbingkun

Description

When the message contains a placeholder({}) but the arguments is 0, an exception will be thrown.
image

https://github.com/panbingkun/spark/actions/runs/8182167017/job/22373124743
This issue was originally discovered during the compilation process of Spark's GitHub workflow. I am not sure if it is a bug or expected behavior, so I am here to ask for your advice.

Configuration

# This log4j config file is for integration test SparkConfPropagateSuite.
rootLogger.level = debug
rootLogger.appenderRef.stdout.ref = console

appender.console.type = Console
appender.console.name = console
appender.console.target = SYSTEM_ERR
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = %d{HH:mm:ss.SSS} %p %c: %maxLen{%m}{512}%n%ex{8}%n

Version:
2.23.0, 2.22.0, 2.21.0, 2.19.0 ...
(I have verified several versions, and it seems that this issue exists in all of them.)

Operating system:
Ubuntu 22.04.4 LTS And macos Sonama 14.3.1.

JDK:
JDK 17

Logs

ERROR StatusConsoleListener An exception occurred processing Appender File
 java.lang.IllegalArgumentException: found 1 argument placeholders, but provided 0 for pattern `0, VisitedIndex{visitedIndexes={}}: [age] r:0`
	at org.apache.logging.log4j.message.ParameterFormatter.formatMessage(ParameterFormatter.java:233)
	at org.apache.logging.log4j.message.ParameterizedMessage.formatTo(ParameterizedMessage.java:266)
	at org.apache.logging.log4j.core.pattern.MessagePatternConverter$SimpleMessagePatternConverter.format(MessagePatternConverter.java:120)
	at org.apache.logging.log4j.core.layout.PatternLayout$NoFormatPatternSerializer.toSerializable(PatternLayout.java:355)
	at org.apache.logging.log4j.core.layout.PatternLayout.toText(PatternLayout.java:252)
	at org.apache.logging.log4j.core.layout.PatternLayout.encode(PatternLayout.java:238)
	at org.apache.logging.log4j.core.layout.PatternLayout.encode(PatternLayout.java:58)
	at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.directEncodeEvent(AbstractOutputStreamAppender.java:227)
	at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.tryAppend(AbstractOutputStreamAppender.java:220)
	at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.append(AbstractOutputStreamAppender.java:211)
	at org.apache.logging.log4j.core.config.AppenderControl.tryCallAppender(AppenderControl.java:160)
	at org.apache.logging.log4j.core.config.AppenderControl.callAppender0(AppenderControl.java:133)
	at org.apache.logging.log4j.core.config.AppenderControl.callAppenderPreventRecursion(AppenderControl.java:124)
	at org.apache.logging.log4j.core.config.AppenderControl.callAppender(AppenderControl.java:88)
	at org.apache.logging.log4j.core.config.LoggerConfig.callAppenders(LoggerConfig.java:705)
	at org.apache.logging.log4j.core.config.LoggerConfig.processLogEvent(LoggerConfig.java:663)
	at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:639)
	at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:575)
	at org.apache.logging.log4j.core.config.AwaitCompletionReliabilityStrategy.log(AwaitCompletionReliabilityStrategy.java:92)
	at org.apache.logging.log4j.core.Logger.log(Logger.java:169)
	at org.apache.logging.log4j.spi.AbstractLogger.tryLogMessage(AbstractLogger.java:2933)
	at org.apache.logging.log4j.spi.AbstractLogger.logMessageTrackRecursion(AbstractLogger.java:2886)
	at org.apache.logging.log4j.spi.AbstractLogger.logMessageSafely(AbstractLogger.java:2868)
	at org.apache.logging.log4j.spi.AbstractLogger.logMessage(AbstractLogger.java:2658)
	at org.apache.logging.log4j.spi.AbstractLogger.logIfEnabled(AbstractLogger.java:2421)
	at org.apache.logging.slf4j.Log4jLogger.debug(Log4jLogger.java:128)
	at org.apache.parquet.io.MessageColumnIO$MessageColumnIORecordConsumer.log(MessageColumnIO.java:283)
	at org.apache.parquet.io.MessageColumnIO$MessageColumnIORecordConsumer.printState(MessageColumnIO.java:269)
	at org.apache.parquet.io.MessageColumnIO$MessageColumnIORecordConsumer.startField(MessageColumnIO.java:318)
	at org.apache.parquet.io.RecordConsumerLoggingWrapper.startField(RecordConsumerLoggingWrapper.java:52)

Reproduction

It can be reproduced in the following simple way:

import java.util.BitSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class TestLog4j2 {

  private static final Logger LOG = LoggerFactory.getLogger(TestLog4j2.class);

  private static BitSet visitedIndexes = new BitSet();

  public static void main(String[] args) {
    System.out.println(visitedIndexes);
    log(visitedIndexes.toString());
    System.out.println("Done");
  }

  private static void log(Object message, Object...parameters) {
    LOG.error("" + message, parameters);
  }
}

The output is:

{}
ERROR StatusConsoleListener An exception occurred processing Appender File
 java.lang.IllegalArgumentException: found 1 argument placeholders, but provided 0 for pattern `{}`
	at org.apache.logging.log4j.message.ParameterFormatter.formatMessage(ParameterFormatter.java:233)
	at org.apache.logging.log4j.message.ParameterizedMessage.formatTo(ParameterizedMessage.java:266)
	at org.apache.logging.log4j.core.pattern.MessagePatternConverter$SimpleMessagePatternConverter.format(MessagePatternConverter.java:120)
	at org.apache.logging.log4j.core.layout.PatternLayout$NoFormatPatternSerializer.toSerializable(PatternLayout.java:355)
	at org.apache.logging.log4j.core.layout.PatternLayout.toText(PatternLayout.java:252)
	at org.apache.logging.log4j.core.layout.PatternLayout.encode(PatternLayout.java:238)
	at org.apache.logging.log4j.core.layout.PatternLayout.encode(PatternLayout.java:58)
	at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.directEncodeEvent(AbstractOutputStreamAppender.java:227)
	at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.tryAppend(AbstractOutputStreamAppender.java:220)
	at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.append(AbstractOutputStreamAppender.java:211)
	at org.apache.logging.log4j.core.config.AppenderControl.tryCallAppender(AppenderControl.java:160)
	at org.apache.logging.log4j.core.config.AppenderControl.callAppender0(AppenderControl.java:133)
	at org.apache.logging.log4j.core.config.AppenderControl.callAppenderPreventRecursion(AppenderControl.java:124)
	at org.apache.logging.log4j.core.config.AppenderControl.callAppender(AppenderControl.java:88)
	at org.apache.logging.log4j.core.config.LoggerConfig.callAppenders(LoggerConfig.java:705)
	at org.apache.logging.log4j.core.config.LoggerConfig.processLogEvent(LoggerConfig.java:663)
	at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:639)
	at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:575)
	at org.apache.logging.log4j.core.config.AwaitCompletionReliabilityStrategy.log(AwaitCompletionReliabilityStrategy.java:92)
	at org.apache.logging.log4j.core.Logger.log(Logger.java:169)
	at org.apache.logging.log4j.spi.AbstractLogger.tryLogMessage(AbstractLogger.java:2933)
	at org.apache.logging.log4j.spi.AbstractLogger.logMessageTrackRecursion(AbstractLogger.java:2886)
	at org.apache.logging.log4j.spi.AbstractLogger.logMessageSafely(AbstractLogger.java:2868)
	at org.apache.logging.log4j.spi.AbstractLogger.logMessage(AbstractLogger.java:2658)
	at org.apache.logging.log4j.spi.AbstractLogger.logIfEnabled(AbstractLogger.java:2421)
	at org.apache.logging.slf4j.Log4jLogger.error(Log4jLogger.java:308)
	at test.org.apache.parquet.column.page.TestLog4j2.log(TestLog4j2.java:20)
	at test.org.apache.parquet.column.page.TestLog4j2.main(TestLog4j2.java:15)
ERROR StatusConsoleListener An exception occurred processing Appender STDOUT
 java.lang.IllegalArgumentException: found 1 argument placeholders, but provided 0 for pattern `{}`
	at org.apache.logging.log4j.message.ParameterFormatter.formatMessage(ParameterFormatter.java:233)
	at org.apache.logging.log4j.message.ParameterizedMessage.formatTo(ParameterizedMessage.java:266)
	at org.apache.logging.log4j.core.pattern.MessagePatternConverter$SimpleMessagePatternConverter.format(MessagePatternConverter.java:120)
	at org.apache.logging.log4j.core.pattern.PatternFormatter.format(PatternFormatter.java:44)
	at org.apache.logging.log4j.core.pattern.MaxLengthConverter.format(MaxLengthConverter.java:88)
	at org.apache.logging.log4j.core.layout.PatternLayout$NoFormatPatternSerializer.toSerializable(PatternLayout.java:355)
	at org.apache.logging.log4j.core.layout.PatternLayout.toText(PatternLayout.java:252)
	at org.apache.logging.log4j.core.layout.PatternLayout.encode(PatternLayout.java:238)
	at org.apache.logging.log4j.core.layout.PatternLayout.encode(PatternLayout.java:58)
	at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.directEncodeEvent(AbstractOutputStreamAppender.java:227)
	at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.tryAppend(AbstractOutputStreamAppender.java:220)
	at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.append(AbstractOutputStreamAppender.java:211)
	at org.apache.logging.log4j.core.config.AppenderControl.tryCallAppender(AppenderControl.java:160)
	at org.apache.logging.log4j.core.config.AppenderControl.callAppender0(AppenderControl.java:133)
	at org.apache.logging.log4j.core.config.AppenderControl.callAppenderPreventRecursion(AppenderControl.java:124)
	at org.apache.logging.log4j.core.config.AppenderControl.callAppender(AppenderControl.java:88)
	at org.apache.logging.log4j.core.config.LoggerConfig.callAppenders(LoggerConfig.java:705)
	at org.apache.logging.log4j.core.config.LoggerConfig.processLogEvent(LoggerConfig.java:663)
	at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:639)
	at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:575)
	at org.apache.logging.log4j.core.config.AwaitCompletionReliabilityStrategy.log(AwaitCompletionReliabilityStrategy.java:92)
	at org.apache.logging.log4j.core.Logger.log(Logger.java:169)
	at org.apache.logging.log4j.spi.AbstractLogger.tryLogMessage(AbstractLogger.java:2933)
	at org.apache.logging.log4j.spi.AbstractLogger.logMessageTrackRecursion(AbstractLogger.java:2886)
	at org.apache.logging.log4j.spi.AbstractLogger.logMessageSafely(AbstractLogger.java:2868)
	at org.apache.logging.log4j.spi.AbstractLogger.logMessage(AbstractLogger.java:2658)
	at org.apache.logging.log4j.spi.AbstractLogger.logIfEnabled(AbstractLogger.java:2421)
	at org.apache.logging.slf4j.Log4jLogger.error(Log4jLogger.java:308)
	at test.org.apache.parquet.column.page.TestLog4j2.log(TestLog4j2.java:20)
	at test.org.apache.parquet.column.page.TestLog4j2.main(TestLog4j2.java:15)
Done

In addition, if we use the following logic, it seems to be able to bypass it (without throwing an exception)

image
import java.util.BitSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class TestLog4j2 {

  private static final Logger LOG = LoggerFactory.getLogger(TestLog4j2.class);

  private static BitSet visitedIndexes = new BitSet();

  public static void main(String[] args) {
    System.out.println(visitedIndexes);
    log(visitedIndexes.toString());
    System.out.println("Done");
  }

  private static void log(Object message, Object...parameters) {
    if (parameters.length == 0) {
      LOG.error("" + message);
    } else {
      LOG.error("" + message, parameters);
    }
  }
}

The output is:

{}
15:19:18.728 ERROR test.org.apache.parquet.column.page.TestLog4j2: {}

Done

I would like to ask very politely, is it an expected behavior (the caller needs to decide whether to call error(String msg) or call error(String format, Object... arguments) based on whether the length of the arguments is 0, bypassing it), or is it a bug?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions