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

mattcasters pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hop.git


The following commit(s) were added to refs/heads/main by this push:
     new 65b08dc32b move to environment so it's applied everywhere, fixes #7297 
(#8572)
65b08dc32b is described below

commit 65b08dc32b9384a6acabaf7aa1c69f7014eb8d9c
Author: Hans Van Akelyen <[email protected]>
AuthorDate: Thu Sep 24 13:25:53 2026 +0200

    move to environment so it's applied everywhere, fixes #7297 (#8572)
---
 .../java/org/apache/hop/core/HopEnvironment.java   | 34 +++++++----
 .../src/main/java/org/apache/hop/run/HopRun.java   | 21 -------
 .../hop/core/HopEnvironmentJulLoggersTest.java     | 69 ++++++++++++++++++++++
 3 files changed, 92 insertions(+), 32 deletions(-)

diff --git a/engine/src/main/java/org/apache/hop/core/HopEnvironment.java 
b/engine/src/main/java/org/apache/hop/core/HopEnvironment.java
index c55464ac3c..50f7db499f 100644
--- a/engine/src/main/java/org/apache/hop/core/HopEnvironment.java
+++ b/engine/src/main/java/org/apache/hop/core/HopEnvironment.java
@@ -281,26 +281,38 @@ public class HopEnvironment {
   }
 
   /**
-   * Strong reference to prevent java.util.logging.LogManager from 
garbage-collecting the logger.
+   * Verbose third-party JUL loggers that are defaulted to WARNING. The JUL 
LogManager only holds
+   * weak references to loggers: a level set on a logger nobody references is 
lost at the next
+   * garbage collection. That is why these are kept in a static field.
+   *
+   * <ul>
+   *   <li>org.apache.hc.client5.http.wire: raw HTTP byte dumps (#8340)
+   *   <li>com.microsoft.sqlserver.jdbc: MS SQL Server driver INFO messages, 
such as "Discarding
+   *       extra metadata which can be a result of SHOWPLAN settings", written 
to stderr (#7297)
+   * </ul>
    */
   @SuppressWarnings("java:S3985")
-  private static final java.util.logging.Logger JUL_WIRE_LOGGER =
-      java.util.logging.Logger.getLogger("org.apache.hc.client5.http.wire");
+  private static final List<java.util.logging.Logger> JUL_VERBOSE_LOGGERS =
+      List.of(
+          
java.util.logging.Logger.getLogger("org.apache.hc.client5.http.wire"),
+          java.util.logging.Logger.getLogger("com.microsoft.sqlserver.jdbc"));
 
   /**
    * Default verbose third-party loggers to a non-debug level to prevent 
dumping raw network bytes
-   * to the console while preserving explicitly configured debug settings.
+   * or driver chatter to the console while preserving explicitly configured 
levels.
    */
-  private static void silenceVerboseThirdPartyLoggers() {
+  static void silenceVerboseThirdPartyLoggers() {
     String wireLoggerName = "org.apache.hc.client5.http.wire";
 
-    // Silence JUL logger to prevent verbose byte dumps on backends printing 
via java.util.logging
-    try {
-      if (JUL_WIRE_LOGGER.getLevel() == null) {
-        JUL_WIRE_LOGGER.setLevel(java.util.logging.Level.WARNING);
+    // Silence JUL loggers which would otherwise print to stderr via the 
default ConsoleHandler
+    for (java.util.logging.Logger julLogger : JUL_VERBOSE_LOGGERS) {
+      try {
+        if (julLogger.getLevel() == null) {
+          julLogger.setLevel(java.util.logging.Level.WARNING);
+        }
+      } catch (Exception ignored) {
+        // Ignore if JUL cannot be configured
       }
-    } catch (Exception ignored) {
-      // Ignore if JUL cannot be configured
     }
 
     // Configure Log4j2 if present on the classpath, preserving any explicit 
configuration
diff --git a/engine/src/main/java/org/apache/hop/run/HopRun.java 
b/engine/src/main/java/org/apache/hop/run/HopRun.java
index 161f69873d..e0655d6a20 100644
--- a/engine/src/main/java/org/apache/hop/run/HopRun.java
+++ b/engine/src/main/java/org/apache/hop/run/HopRun.java
@@ -17,8 +17,6 @@
 
 package org.apache.hop.run;
 
-import java.util.logging.Level;
-import java.util.logging.Logger;
 import lombok.Getter;
 import lombok.Setter;
 import org.apache.commons.lang3.StringUtils;
@@ -48,12 +46,6 @@ public class HopRun extends HopRunBase implements Runnable, 
IHasHopMetadataProvi
 
   public static void main(String[] args) {
 
-    // Silence verbose JUL loggers from third-party JDBC drivers (e.g. 
Microsoft SQL Server)
-    // that write INFO messages to stderr via the default ConsoleHandler. Hop 
uses its own
-    // logging system (HopLogStore) so this JUL output is unwanted noise. 
(Fixes #7297)
-    //
-    silenceJulJdbcLoggers();
-
     HopRun hopRun = new HopRun();
 
     try {
@@ -152,17 +144,4 @@ public class HopRun extends HopRunBase implements 
Runnable, IHasHopMetadataProvi
 
     cmd.parseArgs(helpArgs);
   }
-
-  /**
-   * Suppress INFO-level JUL output from third-party JDBC drivers that would 
otherwise flood stderr
-   * via the default {@link java.util.logging.ConsoleHandler}. Hop uses its 
own logging subsystem
-   * ({@link HopLogStore}) so JUL console output is unwanted noise.
-   *
-   * <p>This must be called early in {@link #main(String[])} — before {@link 
HopEnvironment#init()}
-   * — so the loggers are silenced before any driver classes are loaded.
-   */
-  private static void silenceJulJdbcLoggers() {
-    // Microsoft SQL Server JDBC driver 
(com.microsoft.sqlserver.jdbc.TDSTokenHandler et al.)
-    Logger.getLogger("com.microsoft.sqlserver.jdbc").setLevel(Level.WARNING);
-  }
 }
diff --git 
a/engine/src/test/java/org/apache/hop/core/HopEnvironmentJulLoggersTest.java 
b/engine/src/test/java/org/apache/hop/core/HopEnvironmentJulLoggersTest.java
new file mode 100644
index 0000000000..8ac1f432cc
--- /dev/null
+++ b/engine/src/test/java/org/apache/hop/core/HopEnvironmentJulLoggersTest.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hop.core;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+/**
+ * The JUL LogManager only keeps weak references to loggers. A level set on an 
unreferenced logger
+ * is lost at the next garbage collection, after which a driver logs at the 
root INFO level again
+ * (#7297). These tests force a GC before looking at the levels.
+ */
+class HopEnvironmentJulLoggersTest {
+
+  @ParameterizedTest
+  @ValueSource(
+      strings = {
+        "com.microsoft.sqlserver.jdbc.TDSTokenHandler",
+        "org.apache.hc.client5.http.wire.Something"
+      })
+  void verboseLoggersStaySilencedAfterGarbageCollection(String 
childLoggerName) {
+    HopEnvironment.silenceVerboseThirdPartyLoggers();
+
+    for (int i = 0; i < 3; i++) {
+      System.gc();
+    }
+
+    Logger childLogger = Logger.getLogger(childLoggerName);
+    assertFalse(childLogger.isLoggable(Level.INFO));
+    assertTrue(childLogger.isLoggable(Level.WARNING));
+  }
+
+  @ParameterizedTest
+  @ValueSource(strings = {"com.microsoft.sqlserver.jdbc", 
"org.apache.hc.client5.http.wire"})
+  void explicitlyConfiguredLevelIsPreserved(String loggerName) {
+    Logger logger = Logger.getLogger(loggerName);
+    Level previousLevel = logger.getLevel();
+    try {
+      logger.setLevel(Level.FINE);
+
+      HopEnvironment.silenceVerboseThirdPartyLoggers();
+
+      assertEquals(Level.FINE, logger.getLevel());
+    } finally {
+      logger.setLevel(previousLevel);
+    }
+  }
+}

Reply via email to