diff --git a/common/utils/src/main/scala/org/apache/spark/internal/Logging.scala b/common/utils/src/main/scala/org/apache/spark/internal/Logging.scala index 1d43bda6e4fc..8eea9b44da26 100644 --- a/common/utils/src/main/scala/org/apache/spark/internal/Logging.scala +++ b/common/utils/src/main/scala/org/apache/spark/internal/Logging.scala @@ -99,9 +99,11 @@ case class MessageWithContext(message: String, context: java.util.HashMap[String * Companion class for lazy evaluation of the MessageWithContext instance. */ class LogEntry(messageWithContext: => MessageWithContext) { - def message: String = messageWithContext.message + private lazy val cachedMessageWithContext: MessageWithContext = messageWithContext - def context: java.util.HashMap[String, String] = messageWithContext.context + def message: String = cachedMessageWithContext.message + + def context: java.util.HashMap[String, String] = cachedMessageWithContext.context } /** diff --git a/common/utils/src/test/scala/org/apache/spark/util/StructuredLoggingSuite.scala b/common/utils/src/test/scala/org/apache/spark/util/StructuredLoggingSuite.scala index 52380b2edc7c..b3e103f46337 100644 --- a/common/utils/src/test/scala/org/apache/spark/util/StructuredLoggingSuite.scala +++ b/common/utils/src/test/scala/org/apache/spark/util/StructuredLoggingSuite.scala @@ -25,7 +25,7 @@ import com.fasterxml.jackson.module.scala.DefaultScalaModule import org.apache.logging.log4j.Level import org.scalatest.funsuite.AnyFunSuite // scalastyle:ignore funsuite -import org.apache.spark.internal.{LogEntry, Logging, LogKey, LogKeys, MDC} +import org.apache.spark.internal.{LogEntry, Logging, LogKey, LogKeys, MDC, MessageWithContext} trait LoggingSuiteBase extends AnyFunSuite // scalastyle:ignore funsuite @@ -228,6 +228,37 @@ trait LoggingSuiteBase verifyMsgWithConcat(level, logOutput) } } + + test("LogEntry should construct MessageWithContext only once") { + var constructionCount = 0 + + def constructMessageWithContext(): MessageWithContext = { + constructionCount += 1 + log"Lost executor ${MDC(LogKeys.EXECUTOR_ID, "1")}." + } + logInfo(constructMessageWithContext()) + assert(constructionCount === 1) + } + + test("LogEntry should construct MessageWithContext only once II") { + var constructionCount = 0 + var constructionCount2 = 0 + + def executorId(): String = { + constructionCount += 1 + "1" + } + + def workerId(): String = { + constructionCount2 += 1 + "2" + } + + logInfo(log"Lost executor ${MDC(LogKeys.EXECUTOR_ID, executorId())}." + + log"worker id ${MDC(LogKeys.WORKER_ID, workerId())}") + assert(constructionCount === 1) + assert(constructionCount2 === 1) + } } class StructuredLoggingSuite extends LoggingSuiteBase {