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

bamaer 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 162362a306 early start log4j2 and minor improvement in the scripts, 
fixes #9150 (#9151)
162362a306 is described below

commit 162362a306abae9ac519179c954184c3350eceef
Author: Hans Van Akelyen <[email protected]>
AuthorDate: Thu Oct 29 21:01:07 2026 +0100

    early start log4j2 and minor improvement in the scripts, fixes #9150 (#9151)
---
 assemblies/static/src/main/resources/hop           |  9 ++-
 assemblies/static/src/main/resources/hop-conf.sh   |  9 ++-
 .../static/src/main/resources/hop-encrypt.sh       |  9 ++-
 assemblies/static/src/main/resources/hop-export.sh |  9 ++-
 assemblies/static/src/main/resources/hop-gui.sh    |  6 +-
 assemblies/static/src/main/resources/hop-import.sh |  9 ++-
 assemblies/static/src/main/resources/hop-run.sh    |  9 ++-
 assemblies/static/src/main/resources/hop-search.sh |  9 ++-
 assemblies/static/src/main/resources/hop-server.sh |  9 ++-
 .../java/org/apache/hop/core/HopEnvironment.java   | 76 +++++++++++++++++++++-
 engine/src/main/java/org/apache/hop/hop/Hop.java   |  2 +
 .../src/main/java/org/apache/hop/run/HopRun.java   |  1 +
 .../main/java/org/apache/hop/www/HopServer.java    |  2 +
 .../HopEnvironmentSystemPropertiesArgsTest.java    | 44 +++++++++++++
 14 files changed, 161 insertions(+), 42 deletions(-)

diff --git a/assemblies/static/src/main/resources/hop 
b/assemblies/static/src/main/resources/hop
index 4581032399..573fa25c6c 100755
--- a/assemblies/static/src/main/resources/hop
+++ b/assemblies/static/src/main/resources/hop
@@ -92,11 +92,10 @@ Linux)
   if [ "${XDG_SESSION_TYPE}" = "wayland" ]; then
     export GDK_BACKEND=x11
   fi
-  if "${_HOP_JAVA}" -XshowSettings:properties -version 2>&1 | grep -q "os.arch 
= aarch64"; then
-    CLASSPATH="lib/core/*:lib/spark-client/*:lib/swt/linux/arm64/*"
-  else
-    CLASSPATH="lib/core/*:lib/spark-client/*:lib/swt/linux/$(uname -m)/*"
-  fi
+  case "$(uname -m)" in
+  aarch64 | arm64) 
CLASSPATH="lib/core/*:lib/spark-client/*:lib/swt/linux/arm64/*" ;;
+  *) CLASSPATH="lib/core/*:lib/spark-client/*:lib/swt/linux/$(uname -m)/*" ;;
+  esac
   ;;
 Darwin)
   if "${_HOP_JAVA}" -XshowSettings:properties -version 2>&1 | grep -q "os.arch 
= aarch64"; then
diff --git a/assemblies/static/src/main/resources/hop-conf.sh 
b/assemblies/static/src/main/resources/hop-conf.sh
index b37f14c4ff..92d238d360 100755
--- a/assemblies/static/src/main/resources/hop-conf.sh
+++ b/assemblies/static/src/main/resources/hop-conf.sh
@@ -87,11 +87,10 @@ Linux)
   fi
 
 
-  if "${_HOP_JAVA}" -XshowSettings:properties -version 2>&1 | grep -q "os.arch 
= aarch64"; then
-    CLASSPATH="lib/core/*:lib/spark-client/*:lib/swt/linux/arm64/*"
-  else
-    CLASSPATH="lib/core/*:lib/spark-client/*:lib/swt/linux/$(uname -m)/*"
-  fi
+  case "$(uname -m)" in
+  aarch64 | arm64) 
CLASSPATH="lib/core/*:lib/spark-client/*:lib/swt/linux/arm64/*" ;;
+  *) CLASSPATH="lib/core/*:lib/spark-client/*:lib/swt/linux/$(uname -m)/*" ;;
+  esac
   ;;
 Darwin)
   if "${_HOP_JAVA}" -XshowSettings:properties -version 2>&1 | grep -q "os.arch 
= aarch64"; then
diff --git a/assemblies/static/src/main/resources/hop-encrypt.sh 
b/assemblies/static/src/main/resources/hop-encrypt.sh
index 0e5f3d40cf..f78a1bda91 100755
--- a/assemblies/static/src/main/resources/hop-encrypt.sh
+++ b/assemblies/static/src/main/resources/hop-encrypt.sh
@@ -87,11 +87,10 @@ Linux)
   fi
 
 
-  if "${_HOP_JAVA}" -XshowSettings:properties -version 2>&1 | grep -q "os.arch 
= aarch64"; then
-    CLASSPATH="lib/core/*:lib/spark-client/*:lib/swt/linux/arm64/*"
-  else
-    CLASSPATH="lib/core/*:lib/spark-client/*:lib/swt/linux/$(uname -m)/*"
-  fi
+  case "$(uname -m)" in
+  aarch64 | arm64) 
CLASSPATH="lib/core/*:lib/spark-client/*:lib/swt/linux/arm64/*" ;;
+  *) CLASSPATH="lib/core/*:lib/spark-client/*:lib/swt/linux/$(uname -m)/*" ;;
+  esac
   ;;
 Darwin)
   if "${_HOP_JAVA}" -XshowSettings:properties -version 2>&1 | grep -q "os.arch 
= aarch64"; then
diff --git a/assemblies/static/src/main/resources/hop-export.sh 
b/assemblies/static/src/main/resources/hop-export.sh
index a93c3c3ca8..b9b2c77b0b 100755
--- a/assemblies/static/src/main/resources/hop-export.sh
+++ b/assemblies/static/src/main/resources/hop-export.sh
@@ -87,11 +87,10 @@ Linux)
   fi
 
 
-  if "${_HOP_JAVA}" -XshowSettings:properties -version 2>&1 | grep -q "os.arch 
= aarch64"; then
-    CLASSPATH="lib/core/*:lib/spark-client/*:lib/swt/linux/arm64/*"
-  else
-    CLASSPATH="lib/core/*:lib/spark-client/*:lib/swt/linux/$(uname -m)/*"
-  fi
+  case "$(uname -m)" in
+  aarch64 | arm64) 
CLASSPATH="lib/core/*:lib/spark-client/*:lib/swt/linux/arm64/*" ;;
+  *) CLASSPATH="lib/core/*:lib/spark-client/*:lib/swt/linux/$(uname -m)/*" ;;
+  esac
   ;;
 Darwin)
   if "${_HOP_JAVA}" -XshowSettings:properties -version 2>&1 | grep -q "os.arch 
= aarch64"; then
diff --git a/assemblies/static/src/main/resources/hop-gui.sh 
b/assemblies/static/src/main/resources/hop-gui.sh
index c833874a6e..bb0aab7e7a 100755
--- a/assemblies/static/src/main/resources/hop-gui.sh
+++ b/assemblies/static/src/main/resources/hop-gui.sh
@@ -80,7 +80,11 @@ fi
 HOP_OPTIONS="${HOP_OPTIONS} -DHOP_PLATFORM_RUNTIME=GUI 
-DHOP_AUTO_CREATE_CONFIG=Y -DHOP_PLATFORM_OS="$(uname -s)
 HOP_OPTIONS="${HOP_OPTIONS} --add-opens java.xml/jdk.xml.internal=ALL-UNNAMED 
--add-opens java.base/java.lang=ALL-UNNAMED --add-opens 
java.base/java.lang.invoke=ALL-UNNAMED --add-opens 
java.base/java.lang.reflect=ALL-UNNAMED --add-opens 
java.base/java.io=ALL-UNNAMED --add-opens java.base/java.net=ALL-UNNAMED 
--add-opens java.base/java.nio=ALL-UNNAMED --add-opens 
java.base/java.util=ALL-UNNAMED --add-opens 
java.base/java.util.concurrent=ALL-UNNAMED --add-opens 
java.base/java.util.concurre [...]
 
-os_arch="$(${_HOP_JAVA} -XshowSettings:properties -version 2>&1 | grep 
"os.arch" | awk -F= '{print $2}' | xargs)"
+if [ "$(uname -s)" = "Linux" ]; then
+  os_arch="$(uname -m)"
+else
+  os_arch="$(${_HOP_JAVA} -XshowSettings:properties -version 2>&1 | grep 
"os.arch" | awk -F= '{print $2}' | xargs)"
+fi
 arch_path="$(echo "$os_arch" | sed 's/aarch/arm/g' | sed 's/amd/x86_/g')"
 case $(uname -s) in
 Linux)
diff --git a/assemblies/static/src/main/resources/hop-import.sh 
b/assemblies/static/src/main/resources/hop-import.sh
index b7af9463a6..c0775f61e5 100755
--- a/assemblies/static/src/main/resources/hop-import.sh
+++ b/assemblies/static/src/main/resources/hop-import.sh
@@ -87,11 +87,10 @@ Linux)
   fi
 
 
-  if "${_HOP_JAVA}" -XshowSettings:properties -version 2>&1 | grep -q "os.arch 
= aarch64"; then
-    CLASSPATH="lib/core/*:lib/spark-client/*:lib/swt/linux/arm64/*"
-  else
-    CLASSPATH="lib/core/*:lib/spark-client/*:lib/swt/linux/$(uname -m)/*"
-  fi
+  case "$(uname -m)" in
+  aarch64 | arm64) 
CLASSPATH="lib/core/*:lib/spark-client/*:lib/swt/linux/arm64/*" ;;
+  *) CLASSPATH="lib/core/*:lib/spark-client/*:lib/swt/linux/$(uname -m)/*" ;;
+  esac
   ;;
 Darwin)
   if "${_HOP_JAVA}" -XshowSettings:properties -version 2>&1 | grep -q "os.arch 
= aarch64"; then
diff --git a/assemblies/static/src/main/resources/hop-run.sh 
b/assemblies/static/src/main/resources/hop-run.sh
index 38f353a421..456372fc56 100755
--- a/assemblies/static/src/main/resources/hop-run.sh
+++ b/assemblies/static/src/main/resources/hop-run.sh
@@ -87,11 +87,10 @@ Linux)
   fi
 
 
-  if "${_HOP_JAVA}" -XshowSettings:properties -version 2>&1 | grep -q "os.arch 
= aarch64"; then
-    CLASSPATH="lib/core/*:lib/spark-client/*:lib/swt/linux/arm64/*"
-  else
-    CLASSPATH="lib/core/*:lib/spark-client/*:lib/swt/linux/$(uname -m)/*"
-  fi
+  case "$(uname -m)" in
+  aarch64 | arm64) 
CLASSPATH="lib/core/*:lib/spark-client/*:lib/swt/linux/arm64/*" ;;
+  *) CLASSPATH="lib/core/*:lib/spark-client/*:lib/swt/linux/$(uname -m)/*" ;;
+  esac
   ;;
 Darwin)
   if "${_HOP_JAVA}" -XshowSettings:properties -version 2>&1 | grep -q "os.arch 
= aarch64"; then
diff --git a/assemblies/static/src/main/resources/hop-search.sh 
b/assemblies/static/src/main/resources/hop-search.sh
index 265d53bf1c..4d96caa44e 100755
--- a/assemblies/static/src/main/resources/hop-search.sh
+++ b/assemblies/static/src/main/resources/hop-search.sh
@@ -87,11 +87,10 @@ Linux)
   fi
 
 
-  if "${_HOP_JAVA}" -XshowSettings:properties -version 2>&1 | grep -q "os.arch 
= aarch64"; then
-    CLASSPATH="lib/core/*:lib/spark-client/*:lib/swt/linux/arm64/*"
-  else
-    CLASSPATH="lib/core/*:lib/spark-client/*:lib/swt/linux/$(uname -m)/*"
-  fi
+  case "$(uname -m)" in
+  aarch64 | arm64) 
CLASSPATH="lib/core/*:lib/spark-client/*:lib/swt/linux/arm64/*" ;;
+  *) CLASSPATH="lib/core/*:lib/spark-client/*:lib/swt/linux/$(uname -m)/*" ;;
+  esac
   ;;
 Darwin)
   if "${_HOP_JAVA}" -XshowSettings:properties -version 2>&1 | grep -q "os.arch 
= aarch64"; then
diff --git a/assemblies/static/src/main/resources/hop-server.sh 
b/assemblies/static/src/main/resources/hop-server.sh
index d363b2fb43..16fc1a62e1 100755
--- a/assemblies/static/src/main/resources/hop-server.sh
+++ b/assemblies/static/src/main/resources/hop-server.sh
@@ -87,11 +87,10 @@ Linux)
   fi
 
 
-  if "${_HOP_JAVA}" -XshowSettings:properties -version 2>&1 | grep -q "os.arch 
= aarch64"; then
-    CLASSPATH="lib/core/*:lib/spark-client/*:lib/swt/linux/arm64/*"
-  else
-    CLASSPATH="lib/core/*:lib/spark-client/*:lib/swt/linux/$(uname -m)/*"
-  fi
+  case "$(uname -m)" in
+  aarch64 | arm64) 
CLASSPATH="lib/core/*:lib/spark-client/*:lib/swt/linux/arm64/*" ;;
+  *) CLASSPATH="lib/core/*:lib/spark-client/*:lib/swt/linux/$(uname -m)/*" ;;
+  esac
   ;;
 Darwin)
   if "${_HOP_JAVA}" -XshowSettings:properties -version 2>&1 | grep -q "os.arch 
= aarch64"; then
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 9498a3d730..7898d31eaf 100644
--- a/engine/src/main/java/org/apache/hop/core/HopEnvironment.java
+++ b/engine/src/main/java/org/apache/hop/core/HopEnvironment.java
@@ -80,6 +80,9 @@ public class HopEnvironment {
    */
   private static final ThreadLocal<Boolean> initializing = new ThreadLocal<>();
 
+  /** Starts Log4j2 while the plugins are registered, see {@link 
#startLoggingBackend()}. */
+  private static final AtomicReference<Thread> loggingBackendStart = new 
AtomicReference<>();
+
   /**
    * Initializes the Hop environment. This method performs the following 
operations:
    *
@@ -90,6 +93,11 @@ public class HopEnvironment {
    * @throws HopException Any errors that occur during initialization will 
throw a HopException.
    */
   public static void init() throws HopException {
+    if (initialized.get() == null) {
+      // Building the plugin types below already reads the Hop configuration, 
and with it the
+      // logging back end starts
+      startLoggingBackend();
+    }
     init(getStandardPluginTypes());
   }
 
@@ -133,7 +141,7 @@ public class HopEnvironment {
       
System.setProperties(ConcurrentMapProperties.convertProperties(System.getProperties()));
 
       try {
-        silenceVerboseThirdPartyLoggers();
+        startLoggingBackend();
 
         // This creates .hop and hop.properties...
         //
@@ -209,6 +217,7 @@ public class HopEnvironment {
         // If it's a HopException, throw it, otherwise wrap it in a 
HopException
         throw ((t instanceof HopException hopException) ? hopException : new 
HopException(t));
       } finally {
+        awaitLoggingBackend();
         initializing.remove();
       }
 
@@ -303,6 +312,71 @@ public class HopEnvironment {
           
java.util.logging.Logger.getLogger("org.apache.hc.client5.http.wire"),
           java.util.logging.Logger.getLogger("com.microsoft.sqlserver.jdbc"));
 
+  /**
+   * Starting Log4j2 loads several hundred classes and parses its 
configuration, a few hundred
+   * milliseconds that do not depend on the plugins. It runs in the background 
while they are
+   * registered. Loggers handed out before it is done switch to the configured 
back end once it is;
+   * {@link #awaitLoggingBackend()} makes sure it is done when init() returns.
+   *
+   * <p>A command line tool can call this before it parses its arguments, when 
nothing in them can
+   * change the system properties the logging back end reads. init() starts it 
otherwise.
+   */
+  public static void startLoggingBackend() {
+    Thread thread =
+        new Thread(
+            () -> {
+              try {
+                // The same path as the first library that logs: 
commons-logging, then SLF4J
+                
org.apache.commons.logging.LogFactory.getLog(HopEnvironment.class);
+              } catch (LinkageError | Exception ignored) {
+                // Logging falls back to whatever the libraries find themselves
+              }
+              silenceVerboseThirdPartyLoggers();
+            },
+            "Hop logging back end start");
+    thread.setDaemon(true);
+    if (loggingBackendStart.compareAndSet(null, thread)) {
+      thread.start();
+    }
+  }
+
+  /**
+   * Starts the logging back end for a command line tool before it parses its 
arguments, unless the
+   * arguments may set system properties: those must be applied first, as the 
logging back end reads
+   * them.
+   */
+  public static void startLoggingBackend(String[] args) {
+    if (!maySetSystemProperties(args)) {
+      startLoggingBackend();
+    }
+  }
+
+  /**
+   * Whether the arguments may hold system properties: -s or 
--system-properties, possibly in a
+   * group of short options, or an argument file that picocli expands.
+   */
+  static boolean maySetSystemProperties(String[] args) {
+    for (String arg : args) {
+      if (arg.startsWith("--system-properties")
+          || arg.startsWith("@")
+          || (arg.startsWith("-") && !arg.startsWith("--") && arg.indexOf('s') 
> 0)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  private static void awaitLoggingBackend() {
+    Thread thread = loggingBackendStart.getAndSet(null);
+    if (thread != null) {
+      try {
+        thread.join();
+      } catch (InterruptedException e) {
+        Thread.currentThread().interrupt();
+      }
+    }
+  }
+
   /**
    * Default verbose third-party loggers to a non-debug level to prevent 
dumping raw network bytes
    * or driver chatter to the console while preserving explicitly configured 
levels.
diff --git a/engine/src/main/java/org/apache/hop/hop/Hop.java 
b/engine/src/main/java/org/apache/hop/hop/Hop.java
index 3e40715280..77441a793c 100644
--- a/engine/src/main/java/org/apache/hop/hop/Hop.java
+++ b/engine/src/main/java/org/apache/hop/hop/Hop.java
@@ -78,6 +78,8 @@ public class Hop {
   }
 
   public static void main(String[] args) throws Exception {
+    HopEnvironment.startLoggingBackend(args);
+
     Hop hop = new Hop();
 
     hop.cmd = new CommandLine(hop);
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 a45003a9f3..314a62e223 100644
--- a/engine/src/main/java/org/apache/hop/run/HopRun.java
+++ b/engine/src/main/java/org/apache/hop/run/HopRun.java
@@ -46,6 +46,7 @@ public class HopRun extends HopRunBase implements Runnable, 
IHasHopMetadataProvi
   }
 
   public static void main(String[] args) {
+    HopEnvironment.startLoggingBackend(args);
 
     HopRun hopRun = new HopRun();
 
diff --git a/engine/src/main/java/org/apache/hop/www/HopServer.java 
b/engine/src/main/java/org/apache/hop/www/HopServer.java
index b3edd91734..1900085e71 100644
--- a/engine/src/main/java/org/apache/hop/www/HopServer.java
+++ b/engine/src/main/java/org/apache/hop/www/HopServer.java
@@ -694,6 +694,8 @@ public class HopServer implements Runnable, 
IHasHopMetadataProvider, IHopCommand
   }
 
   public static void main(String[] args) {
+    HopEnvironment.startLoggingBackend(args);
+
     String[] arguments =
         Stream.of(args)
             .flatMap(a -> Stream.of(a.split("(?=--)")))
diff --git 
a/engine/src/test/java/org/apache/hop/core/HopEnvironmentSystemPropertiesArgsTest.java
 
b/engine/src/test/java/org/apache/hop/core/HopEnvironmentSystemPropertiesArgsTest.java
new file mode 100644
index 0000000000..a8bd7a0971
--- /dev/null
+++ 
b/engine/src/test/java/org/apache/hop/core/HopEnvironmentSystemPropertiesArgsTest.java
@@ -0,0 +1,44 @@
+/*
+ * 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.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+class HopEnvironmentSystemPropertiesArgsTest {
+
+  @Test
+  void argumentsWithoutSystemProperties() {
+    assertFalse(HopEnvironment.maySetSystemProperties(new String[0]));
+    assertFalse(
+        HopEnvironment.maySetSystemProperties(
+            new String[] {"-j", "project", "-r", "local", "-f", 
"/a/sales/pipeline.hpl"}));
+    assertFalse(
+        HopEnvironment.maySetSystemProperties(new String[] {"--level=Basic", 
"--file=x.hpl"}));
+  }
+
+  @Test
+  void argumentsThatMaySetSystemProperties() {
+    assertTrue(HopEnvironment.maySetSystemProperties(new String[] {"-s", 
"A=1"}));
+    assertTrue(HopEnvironment.maySetSystemProperties(new String[] 
{"-sA=1,B=2"}));
+    assertTrue(HopEnvironment.maySetSystemProperties(new String[] 
{"--system-properties=A=1"}));
+    assertTrue(HopEnvironment.maySetSystemProperties(new String[] {"-f", 
"x.hpl", "@options.txt"}));
+  }
+}

Reply via email to