This is an automated email from the ASF dual-hosted git repository.

gengliang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/spark.git


The following commit(s) were added to refs/heads/master by this push:
     new 114164bd3f6b [SPARK-48490][CORE] Unescapes any literals for message of 
MessageWithContext
114164bd3f6b is described below

commit 114164bd3f6bfb67e58f8ead93c5bba0d08b8a0a
Author: panbingkun <panbing...@baidu.com>
AuthorDate: Fri May 31 16:45:07 2024 -0700

    [SPARK-48490][CORE] Unescapes any literals for message of MessageWithContext
    
    ### What changes were proposed in this pull request?
    The pr aims to `unescapes` any literals for `message` of 
`MessageWithContext`
    
    ### Why are the changes needed?
    - For example, before this PR
    ```
    logInfo("This is a log message\nThis is a new line \t other msg")
    ```
    It will output:
    ```
    24/05/31 22:53:27 INFO PatternLoggingSuite: This is a log message
    This is a new line       other msg
    ```
    
    But:
    
    ```
    logInfo(log"This is a log message\nThis is a new line \t other msg")
    ```
    It will output:
    ```
    24/05/31 22:53:59 ERROR PatternLoggingSuite: This is a log message\nThis is 
a new line \t other msg
    ```
    
    Obviously, the latter is not the result we `expected`.
    
    ### Does this PR introduce _any_ user-facing change?
    Yes, fix bug.
    
    ### How was this patch tested?
    - Add new UT.
    - Pass GA.
    
    ### Was this patch authored or co-authored using generative AI tooling?
    No.
    
    Closes #46824 from panbingkun/SPARK-48490.
    
    Authored-by: panbingkun <panbing...@baidu.com>
    Signed-off-by: Gengliang Wang <gengli...@apache.org>
---
 .../scala/org/apache/spark/internal/Logging.scala  |  3 +-
 .../apache/spark/util/PatternSparkLoggerSuite.java |  6 +++
 .../apache/spark/util/SparkLoggerSuiteBase.java    | 53 ++++++++++++++------
 .../spark/util/StructuredSparkLoggerSuite.java     | 11 +++++
 .../apache/spark/util/PatternLoggingSuite.scala    |  8 +++
 .../apache/spark/util/StructuredLoggingSuite.scala | 57 ++++++++++++++++++++++
 6 files changed, 121 insertions(+), 17 deletions(-)

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 72c7cdfa6236..9500ed4b174e 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
@@ -19,6 +19,7 @@ package org.apache.spark.internal
 
 import scala.jdk.CollectionConverters._
 
+import org.apache.commons.text.StringEscapeUtils
 import org.apache.logging.log4j.{CloseableThreadContext, Level, LogManager}
 import org.apache.logging.log4j.core.{Filter, LifeCycle, LogEvent, Logger => 
Log4jLogger, LoggerContext}
 import org.apache.logging.log4j.core.appender.ConsoleAppender
@@ -99,7 +100,7 @@ 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
+  def message: String = 
StringEscapeUtils.unescapeJava(messageWithContext.message)
 
   def context: java.util.HashMap[String, String] = messageWithContext.context
 }
diff --git 
a/common/utils/src/test/java/org/apache/spark/util/PatternSparkLoggerSuite.java 
b/common/utils/src/test/java/org/apache/spark/util/PatternSparkLoggerSuite.java
index 1d2e6d76a759..6bfe595def1d 100644
--- 
a/common/utils/src/test/java/org/apache/spark/util/PatternSparkLoggerSuite.java
+++ 
b/common/utils/src/test/java/org/apache/spark/util/PatternSparkLoggerSuite.java
@@ -53,6 +53,12 @@ public class PatternSparkLoggerSuite extends 
SparkLoggerSuiteBase {
     return toRegexPattern(level, ".*<level> <className>: This is a log 
message\n");
   }
 
+  @Override
+  String expectedPatternForBasicMsgWithEscapeChar(Level level) {
+    return toRegexPattern(level,
+      ".*<level> <className>: This is a log message\\nThis is a new line \\t 
other msg\\n");
+  }
+
   @Override
   String expectedPatternForBasicMsgWithException(Level level) {
     return toRegexPattern(level, """
diff --git 
a/common/utils/src/test/java/org/apache/spark/util/SparkLoggerSuiteBase.java 
b/common/utils/src/test/java/org/apache/spark/util/SparkLoggerSuiteBase.java
index 079899581dc0..37b5372885b8 100644
--- a/common/utils/src/test/java/org/apache/spark/util/SparkLoggerSuiteBase.java
+++ b/common/utils/src/test/java/org/apache/spark/util/SparkLoggerSuiteBase.java
@@ -68,16 +68,17 @@ public abstract class SparkLoggerSuiteBase {
     }
   }
 
-  private String basicMsg() {
-    return "This is a log message";
-  }
+  private final String basicMsg = "This is a log message";
+
+  private final String basicMsgWithEscapeChar =
+    "This is a log message\nThis is a new line \t other msg";
 
   private final MDC executorIDMDC = MDC.of(LogKeys.EXECUTOR_ID$.MODULE$, "1");
   private final String msgWithMDC = "Lost executor {}.";
 
   private final MDC[] mdcs = new MDC[] {
-      MDC.of(LogKeys.EXECUTOR_ID$.MODULE$, "1"),
-      MDC.of(LogKeys.REASON$.MODULE$, "the shuffle data is too large")};
+    MDC.of(LogKeys.EXECUTOR_ID$.MODULE$, "1"),
+    MDC.of(LogKeys.REASON$.MODULE$, "the shuffle data is too large")};
   private final String msgWithMDCs = "Lost executor {}, reason: {}";
 
   private final MDC executorIDMDCValueIsNull = 
MDC.of(LogKeys.EXECUTOR_ID$.MODULE$, null);
@@ -91,6 +92,9 @@ public abstract class SparkLoggerSuiteBase {
   // test for basic message (without any mdc)
   abstract String expectedPatternForBasicMsg(Level level);
 
+  // test for basic message (with escape char)
+  abstract String expectedPatternForBasicMsgWithEscapeChar(Level level);
+
   // test for basic message and exception
   abstract String expectedPatternForBasicMsgWithException(Level level);
 
@@ -113,12 +117,12 @@ public abstract class SparkLoggerSuiteBase {
   abstract String expectedPatternForJavaCustomLogKey(Level level);
 
   @Test
-  public void testBasicMsgLogger() {
-    Runnable errorFn = () -> logger().error(basicMsg());
-    Runnable warnFn = () -> logger().warn(basicMsg());
-    Runnable infoFn = () -> logger().info(basicMsg());
-    Runnable debugFn = () -> logger().debug(basicMsg());
-    Runnable traceFn = () -> logger().trace(basicMsg());
+  public void testBasicMsg() {
+    Runnable errorFn = () -> logger().error(basicMsg);
+    Runnable warnFn = () -> logger().warn(basicMsg);
+    Runnable infoFn = () -> logger().info(basicMsg);
+    Runnable debugFn = () -> logger().debug(basicMsg);
+    Runnable traceFn = () -> logger().trace(basicMsg);
     List.of(
         Pair.of(Level.ERROR, errorFn),
         Pair.of(Level.WARN, warnFn),
@@ -128,14 +132,31 @@ public abstract class SparkLoggerSuiteBase {
       checkLogOutput(pair.getLeft(), pair.getRight(), 
this::expectedPatternForBasicMsg));
   }
 
+  @Test
+  public void testBasicMsgWithEscapeChar() {
+    Runnable errorFn = () -> logger().error(basicMsgWithEscapeChar);
+    Runnable warnFn = () -> logger().warn(basicMsgWithEscapeChar);
+    Runnable infoFn = () -> logger().info(basicMsgWithEscapeChar);
+    Runnable debugFn = () -> logger().debug(basicMsgWithEscapeChar);
+    Runnable traceFn = () -> logger().trace(basicMsgWithEscapeChar);
+    List.of(
+        Pair.of(Level.ERROR, errorFn),
+        Pair.of(Level.WARN, warnFn),
+        Pair.of(Level.INFO, infoFn),
+        Pair.of(Level.DEBUG, debugFn),
+        Pair.of(Level.TRACE, traceFn)).forEach(pair ->
+      checkLogOutput(pair.getLeft(), pair.getRight(),
+        this::expectedPatternForBasicMsgWithEscapeChar));
+  }
+
   @Test
   public void testBasicLoggerWithException() {
     Throwable exception = new RuntimeException("OOM");
-    Runnable errorFn = () -> logger().error(basicMsg(), exception);
-    Runnable warnFn = () -> logger().warn(basicMsg(), exception);
-    Runnable infoFn = () -> logger().info(basicMsg(), exception);
-    Runnable debugFn = () -> logger().debug(basicMsg(), exception);
-    Runnable traceFn = () -> logger().trace(basicMsg(), exception);
+    Runnable errorFn = () -> logger().error(basicMsg, exception);
+    Runnable warnFn = () -> logger().warn(basicMsg, exception);
+    Runnable infoFn = () -> logger().info(basicMsg, exception);
+    Runnable debugFn = () -> logger().debug(basicMsg, exception);
+    Runnable traceFn = () -> logger().trace(basicMsg, exception);
     List.of(
         Pair.of(Level.ERROR, errorFn),
         Pair.of(Level.WARN, warnFn),
diff --git 
a/common/utils/src/test/java/org/apache/spark/util/StructuredSparkLoggerSuite.java
 
b/common/utils/src/test/java/org/apache/spark/util/StructuredSparkLoggerSuite.java
index ec19014e117c..6959fe11820f 100644
--- 
a/common/utils/src/test/java/org/apache/spark/util/StructuredSparkLoggerSuite.java
+++ 
b/common/utils/src/test/java/org/apache/spark/util/StructuredSparkLoggerSuite.java
@@ -69,6 +69,17 @@ public class StructuredSparkLoggerSuite extends 
SparkLoggerSuiteBase {
       }""");
   }
 
+  @Override
+  String expectedPatternForBasicMsgWithEscapeChar(Level level) {
+    return compactAndToRegexPattern(level, """
+      {
+        "ts": "<timestamp>",
+        "level": "<level>",
+        "msg": "This is a log message\\\\nThis is a new line \\\\t other msg",
+        "logger": "<className>"
+      }""");
+  }
+
   @Override
   String expectedPatternForBasicMsgWithException(Level level) {
     return compactAndToRegexPattern(level, """
diff --git 
a/common/utils/src/test/scala/org/apache/spark/util/PatternLoggingSuite.scala 
b/common/utils/src/test/scala/org/apache/spark/util/PatternLoggingSuite.scala
index ab9803d83bf6..6af5f2d4f19f 100644
--- 
a/common/utils/src/test/scala/org/apache/spark/util/PatternLoggingSuite.scala
+++ 
b/common/utils/src/test/scala/org/apache/spark/util/PatternLoggingSuite.scala
@@ -34,6 +34,14 @@ class PatternLoggingSuite extends LoggingSuiteBase with 
BeforeAndAfterAll {
     s""".*$level $className: This is a log message\n"""
   }
 
+  override def expectedPatternForBasicMsgWithEscapeChar(level: Level): String 
= {
+    s""".*$level $className: This is a log message\nThis is a new line \t 
other msg\n"""
+  }
+
+  override def expectedPatternForBasicMsgWithEscapeCharMDC(level: Level): 
String = {
+    s""".*$level $className: This is a log message\nThis is a new line \t 
other msg\n"""
+  }
+
   override def expectedPatternForBasicMsgWithException(level: Level): String = 
{
     s""".*$level $className: This is a log message\n[\\s\\S]*"""
   }
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 694f06706421..598ae90402a8 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
@@ -53,6 +53,11 @@ trait LoggingSuiteBase
 
   def basicMsg: String = "This is a log message"
 
+  def basicMsgWithEscapeChar: String = "This is a log message\nThis is a new 
line \t other msg"
+
+  def basicMsgWithEscapeCharMDC: LogEntry =
+    log"This is a log message\nThis is a new line \t other msg"
+
   def msgWithMDC: LogEntry = log"Lost executor ${MDC(LogKeys.EXECUTOR_ID, 
"1")}."
 
   def msgWithMDCValueIsNull: LogEntry = log"Lost executor 
${MDC(LogKeys.EXECUTOR_ID, null)}."
@@ -66,6 +71,12 @@ trait LoggingSuiteBase
   // test for basic message (without any mdc)
   def expectedPatternForBasicMsg(level: Level): String
 
+  // test for basic message (with escape char)
+  def expectedPatternForBasicMsgWithEscapeChar(level: Level): String
+
+  // test for basic message (with escape char mdc)
+  def expectedPatternForBasicMsgWithEscapeCharMDC(level: Level): String
+
   // test for basic message and exception
   def expectedPatternForBasicMsgWithException(level: Level): String
 
@@ -95,6 +106,30 @@ trait LoggingSuiteBase
     }
   }
 
+  test("Basic logging with escape char") {
+    Seq(
+      (Level.ERROR, () => logError(basicMsgWithEscapeChar)),
+      (Level.WARN, () => logWarning(basicMsgWithEscapeChar)),
+      (Level.INFO, () => logInfo(basicMsgWithEscapeChar)),
+      (Level.DEBUG, () => logDebug(basicMsgWithEscapeChar)),
+      (Level.TRACE, () => logTrace(basicMsgWithEscapeChar))).foreach { case 
(level, logFunc) =>
+      val logOutput = captureLogOutput(logFunc)
+      
assert(expectedPatternForBasicMsgWithEscapeChar(level).r.matches(logOutput))
+    }
+  }
+
+  test("Basic logging with escape char MDC") {
+    Seq(
+      (Level.ERROR, () => logError(basicMsgWithEscapeCharMDC)),
+      (Level.WARN, () => logWarning(basicMsgWithEscapeCharMDC)),
+      (Level.INFO, () => logInfo(basicMsgWithEscapeCharMDC)),
+      (Level.DEBUG, () => logDebug(basicMsgWithEscapeCharMDC)),
+      (Level.TRACE, () => logTrace(basicMsgWithEscapeCharMDC))).foreach { case 
(level, logFunc) =>
+      val logOutput = captureLogOutput(logFunc)
+      
assert(expectedPatternForBasicMsgWithEscapeCharMDC(level).r.matches(logOutput))
+    }
+  }
+
   test("Basic logging with Exception") {
     val exception = new RuntimeException("OOM")
     Seq(
@@ -197,6 +232,28 @@ class StructuredLoggingSuite extends LoggingSuiteBase {
         }""")
   }
 
+  override def expectedPatternForBasicMsgWithEscapeChar(level: Level): String 
= {
+    compactAndToRegexPattern(
+      s"""
+        {
+          "ts": "<timestamp>",
+          "level": "$level",
+          "msg": "This is a log message\\\\nThis is a new line \\\\t other 
msg",
+          "logger": "$className"
+        }""")
+  }
+
+  override def expectedPatternForBasicMsgWithEscapeCharMDC(level: Level): 
String = {
+    compactAndToRegexPattern(
+      s"""
+        {
+          "ts": "<timestamp>",
+          "level": "$level",
+          "msg": "This is a log message\\\\nThis is a new line \\\\t other 
msg",
+          "logger": "$className"
+        }""")
+  }
+
   override def expectedPatternForBasicMsgWithException(level: Level): String = 
{
     compactAndToRegexPattern(
       s"""


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@spark.apache.org
For additional commands, e-mail: commits-h...@spark.apache.org

Reply via email to