You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spark.apache.org by ge...@apache.org on 2024/08/13 21:32:47 UTC

(spark) branch master updated: [SPARK-49216][CORE] Fix to not log message context with explicitly LogEntry constructed when Structured Logging conf is off

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 20d98a1ca594 [SPARK-49216][CORE] Fix to not log message context with explicitly LogEntry constructed when Structured Logging conf is off
20d98a1ca594 is described below

commit 20d98a1ca59443fe1e1c96aa1b5a6028dbeca2db
Author: Xinyi Yu <xi...@databricks.com>
AuthorDate: Tue Aug 13 14:32:33 2024 -0700

    [SPARK-49216][CORE] Fix to not log message context with explicitly LogEntry constructed when Structured Logging conf is off
    
    ### What changes were proposed in this pull request?
    
    To use structured logging developers usually do
    ```scala
    logInfo(log"Lost executor ${MDC(LogKeys.EXECUTOR_ID, "1")}."),
    ```
    When the structured logging conf is off, the context is not logged.
    However if explicitly constructing the LogEntry and calling the public API,
    ```scala
    logInfo(
      MessageWithContext(
        "Lost executor 1.",
        new java.util.HashMap[String, String] { put(LogKeys.EXECUTOR_ID.name, "1") }
      )
    )
    ```
    the conf does not take effect and even when it is off, the context is still logged.
    
    This PR creates a fix for both cases to observe the conf, by toggling in the `withLogContext` function.
    
    This PR also adds a extra small test on explicitly setting MDC.
    
    ### Why are the changes needed?
    To keep consistency between APIs.
    
    ### Does this PR introduce _any_ user-facing change?
    No.
    
    ### How was this patch tested?
    Added new unit tests.
    
    ### Was this patch authored or co-authored using generative AI tooling?
    No.
    
    Closes #47732 from anchovYu/structured-logging-conf.
    
    Authored-by: Xinyi Yu <xi...@databricks.com>
    Signed-off-by: Gengliang Wang <ge...@apache.org>
---
 .../scala/org/apache/spark/internal/Logging.scala  | 10 ++++--
 .../apache/spark/util/StructuredLoggingSuite.scala | 40 +++++++++++++++++++++-
 2 files changed, 47 insertions(+), 3 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 8eea9b44da26..7ffaef0855fd 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
@@ -165,11 +165,17 @@ trait Logging {
   }
 
   protected def withLogContext(context: java.util.HashMap[String, String])(body: => Unit): Unit = {
-    val threadContext = CloseableThreadContext.putAll(context)
+    // put into thread context only when structured logging is enabled
+    val closeableThreadContextOpt = if (Logging.isStructuredLoggingEnabled) {
+      Some(CloseableThreadContext.putAll(context))
+    } else {
+      None
+    }
+
     try {
       body
     } finally {
-      threadContext.close()
+      closeableThreadContextOpt.foreach(_.close())
     }
   }
 
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 b3e103f46337..48951c2084f1 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
@@ -40,7 +40,7 @@ trait LoggingSuiteBase
   }
 
   // Return the newly added log contents in the log file after executing the function `f`
-  private def captureLogOutput(f: () => Unit): String = {
+  protected def captureLogOutput(f: () => Unit): String = {
     val content = if (logFile.exists()) {
       Files.readString(logFile.toPath)
     } else {
@@ -438,6 +438,44 @@ class StructuredLoggingSuite extends LoggingSuiteBase {
     assert((log"\r" + log"\n" + log"\t" + log"\b").message == "\r\n\t\b")
     assert((log"\r${MDC(LogKeys.EXECUTOR_ID, 1)}\n".message == "\r1\n"))
   }
+
+  test("disabled structured logging won't log context") {
+    Logging.disableStructuredLogging()
+    val expectedPatternWithoutContext = compactAndToRegexPattern(
+      s"""
+        {
+          "ts": "<timestamp>",
+          "level": "INFO",
+          "msg": "Lost executor 1.",
+          "logger": "$className"
+        }""")
+
+    Seq(
+      () => logInfo(log"Lost executor ${MDC(LogKeys.EXECUTOR_ID, "1")}."),
+      () => logInfo( // blocked when explicitly constructing the MessageWithContext
+        MessageWithContext(
+          "Lost executor 1.",
+          new java.util.HashMap[String, String] { put(LogKeys.EXECUTOR_ID.name, "1") }
+        )
+      )
+    ).foreach { f =>
+      val logOutput = captureLogOutput(f)
+      assert(expectedPatternWithoutContext.r.matches(logOutput))
+    }
+    Logging.enableStructuredLogging()
+  }
+
+  test("setting to MDC gets logged") {
+    val mdcPattern = s""""${LogKeys.DATA.name}":"some-data""""
+
+    org.slf4j.MDC.put(LogKeys.DATA.name, "some-data")
+    val logOutputWithMDCSet = captureLogOutput(() => logInfo(msgWithMDC))
+    assert(mdcPattern.r.findFirstIn(logOutputWithMDCSet).isDefined)
+
+    org.slf4j.MDC.remove(LogKeys.DATA.name)
+    val logOutputWithoutMDCSet = captureLogOutput(() => logInfo(msgWithMDC))
+    assert(mdcPattern.r.findFirstIn(logOutputWithoutMDCSet).isEmpty)
+  }
 }
 
 object CustomLogKeys {


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