This is an automated email from the ASF dual-hosted git repository.
hansva 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 633e4cb27b fix error line highlighting, #6245 (#6312)
633e4cb27b is described below
commit 633e4cb27bb8c4e7ec3efb72b0847731440c8388
Author: Hans Van Akelyen <[email protected]>
AuthorDate: Wed Jan 7 21:08:39 2026 +0100
fix error line highlighting, #6245 (#6312)
* fix error line highlighting, #6245
* Add color coding to console output
---
core/src/main/java/org/apache/hop/core/Const.java | 12 +++
.../core/logging/ConsoleLoggingEventListener.java | 40 +++++++++-
.../apache/hop/core/logging/HopLoggingEvent.java | 29 ++-----
.../hop/ui/core/widget/LogStyledTextComp.java | 43 -----------
.../hop/ui/core/widget/highlight/LogHighlight.java | 88 ----------------------
.../ui/hopgui/file/pipeline/HopGuiLogBrowser.java | 60 +++++++++++++--
.../delegates/HopGuiPipelineLogDelegate.java | 15 ++--
.../delegates/HopGuiWorkflowLogDelegate.java | 15 ++--
8 files changed, 125 insertions(+), 177 deletions(-)
diff --git a/core/src/main/java/org/apache/hop/core/Const.java
b/core/src/main/java/org/apache/hop/core/Const.java
index b94bac31ec..49887bfc85 100644
--- a/core/src/main/java/org/apache/hop/core/Const.java
+++ b/core/src/main/java/org/apache/hop/core/Const.java
@@ -517,6 +517,18 @@ public class Const {
description = "Set this variable to 'Y' to redirect stdout to Hop
logging.")
public static final String HOP_REDIRECT_STDOUT = "HOP_REDIRECT_STDOUT";
+ /**
+ * System wide flag to enable ANSI color codes in console output. Values:
'true', 'false', or
+ * 'auto' (default). 'auto' detects if output is to a terminal and enables
colors only when
+ * appropriate (not when piped to files or log collectors).
+ */
+ @Variable(
+ scope = VariableScope.SYSTEM,
+ value = "auto",
+ description =
+ "Enable ANSI color codes in console output. Values: 'true' (always),
'false' (never), or 'auto' (only when output is to a terminal)")
+ public static final String HOP_CONSOLE_COLORS = "HOP_CONSOLE_COLORS";
+
/** System wide flag to log stack traces in a simpler, more human readable
format */
@Variable(
scope = VariableScope.SYSTEM,
diff --git
a/core/src/main/java/org/apache/hop/core/logging/ConsoleLoggingEventListener.java
b/core/src/main/java/org/apache/hop/core/logging/ConsoleLoggingEventListener.java
index c709fbf08d..fd981e4512 100644
---
a/core/src/main/java/org/apache/hop/core/logging/ConsoleLoggingEventListener.java
+++
b/core/src/main/java/org/apache/hop/core/logging/ConsoleLoggingEventListener.java
@@ -17,20 +17,58 @@
package org.apache.hop.core.logging;
+import org.apache.hop.core.Const;
+import org.apache.hop.core.util.EnvUtil;
+
+/**
+ * Console logging event listener that writes log messages to stdout/stderr.
Supports ANSI color
+ * codes for error messages when configured.
+ */
public class ConsoleLoggingEventListener implements IHopLoggingEventListener {
+ // ANSI color codes for terminal output
+ private static final String ANSI_RESET = "\u001B[0m";
+ private static final String ANSI_RED = "\u001B[31m";
+
private HopLogLayout layout;
+ private boolean useColors;
public ConsoleLoggingEventListener() {
this.layout = new HopLogLayout(true);
+
+ // Determine whether to use ANSI color codes based on configuration
+ // Check both system property (-D flag) and environment variable
+ String colorConfig = EnvUtil.getSystemProperty(Const.HOP_CONSOLE_COLORS);
+ if (colorConfig == null) {
+ colorConfig = System.getenv(Const.HOP_CONSOLE_COLORS);
+ }
+ if (colorConfig == null) {
+ colorConfig = "auto"; // default
+ }
+ colorConfig = colorConfig.toLowerCase();
+
+ if ("true".equals(colorConfig)) {
+ // Always use colors
+ this.useColors = true;
+ } else if ("false".equals(colorConfig)) {
+ // Never use colors
+ this.useColors = false;
+ } else {
+ // Auto-detect: only use colors if output is to a terminal (not
piped/redirected)
+ // System.console() returns null when output is redirected to a file or
pipe
+ this.useColors = System.console() != null;
+ }
}
@Override
public void eventAdded(HopLoggingEvent event) {
-
String logText = layout.format(event);
if (event.getLevel() == LogLevel.ERROR) {
+ // Apply red color to error messages if colors are enabled
+ if (useColors) {
+ logText = ANSI_RED + logText + ANSI_RESET;
+ }
HopLogStore.OriginalSystemErr.println(logText);
HopLogStore.OriginalSystemErr.flush();
} else {
diff --git
a/core/src/main/java/org/apache/hop/core/logging/HopLoggingEvent.java
b/core/src/main/java/org/apache/hop/core/logging/HopLoggingEvent.java
index 466a9944aa..fcb7e853cb 100644
--- a/core/src/main/java/org/apache/hop/core/logging/HopLoggingEvent.java
+++ b/core/src/main/java/org/apache/hop/core/logging/HopLoggingEvent.java
@@ -17,6 +17,11 @@
package org.apache.hop.core.logging;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
public class HopLoggingEvent {
private Object message;
@@ -35,28 +40,4 @@ public class HopLoggingEvent {
this.timeStamp = timeStamp;
this.level = level;
}
-
- public Object getMessage() {
- return message;
- }
-
- public void setMessage(Object message) {
- this.message = message;
- }
-
- public long getTimeStamp() {
- return timeStamp;
- }
-
- public void setTimeStamp(long timeStamp) {
- this.timeStamp = timeStamp;
- }
-
- public LogLevel getLevel() {
- return level;
- }
-
- public void setLevel(LogLevel level) {
- this.level = level;
- }
}
diff --git
a/ui/src/main/java/org/apache/hop/ui/core/widget/LogStyledTextComp.java
b/ui/src/main/java/org/apache/hop/ui/core/widget/LogStyledTextComp.java
deleted file mode 100644
index e6675f5d54..0000000000
--- a/ui/src/main/java/org/apache/hop/ui/core/widget/LogStyledTextComp.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.ui.core.widget;
-
-import org.apache.hop.core.variables.IVariables;
-import org.apache.hop.ui.core.widget.highlight.LogHighlight;
-import org.apache.hop.ui.util.EnvironmentUtils;
-import org.eclipse.swt.widgets.Composite;
-
-public class LogStyledTextComp extends StyledTextVar {
- public LogStyledTextComp(IVariables variables, Composite parent, int style) {
- super(variables, parent, style, false, false);
- }
-
- @Override
- public void addLineStyleListener() {
- // Only add highlighting in SWT mode (RWT doesn't have StyledText)
- if (!EnvironmentUtils.getInstance().isWeb()) {
- addLineStyleListener(new LogHighlight());
- }
- }
-
- @Override
- public void addLineStyleListener(java.util.List<String> keywords) {
- // Log highlighting doesn't use keywords, just use default
- addLineStyleListener();
- }
-}
diff --git
a/ui/src/main/java/org/apache/hop/ui/core/widget/highlight/LogHighlight.java
b/ui/src/main/java/org/apache/hop/ui/core/widget/highlight/LogHighlight.java
deleted file mode 100644
index b53b802742..0000000000
--- a/ui/src/main/java/org/apache/hop/ui/core/widget/highlight/LogHighlight.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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.ui.core.widget.highlight;
-
-import org.apache.hop.ui.core.gui.GuiResource;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.custom.LineStyleEvent;
-import org.eclipse.swt.custom.LineStyleListener;
-import org.eclipse.swt.custom.StyleRange;
-
-public class LogHighlight implements LineStyleListener {
- private static final String[] ERROR_KEYWORDS = {"ERROR", "EXCEPTION",
"FATAL", "SEVERE"};
- private static final String[] WARNING_KEYWORDS = {"WARN", "WARNING",
"CAUTION"};
-
- private StyleAttribute errorStyle;
- private StyleAttribute warningStyle;
-
- public LogHighlight() {
- initializeStyles();
- }
-
- void initializeStyles() {
- GuiResource resource = GuiResource.getInstance();
- // Red color for errors
- errorStyle = new StyleAttribute(GuiResource.getInstance().getColorRed(),
SWT.NORMAL);
- // Orange/Yellow color for warnings
- warningStyle = new
StyleAttribute(GuiResource.getInstance().getColorOrange(), SWT.NORMAL);
- }
-
- @Override
- public void lineGetStyle(LineStyleEvent event) {
- String lineText = event.lineText;
- if (lineText == null || lineText.isEmpty()) {
- event.styles = new StyleRange[0];
- return;
- }
-
- String upperLine = lineText.toUpperCase();
-
- // Check for error keywords
- for (String keyword : ERROR_KEYWORDS) {
- if (upperLine.contains(keyword)) {
- StyleRange styleRange =
- new StyleRange(
- event.lineOffset,
- lineText.length(),
- errorStyle.getForeground(),
- null,
- errorStyle.getStyle());
- event.styles = new StyleRange[] {styleRange};
- return;
- }
- }
-
- // Check for warning keywords
- for (String keyword : WARNING_KEYWORDS) {
- if (upperLine.contains(keyword)) {
- StyleRange styleRange =
- new StyleRange(
- event.lineOffset,
- lineText.length(),
- warningStyle.getForeground(),
- null,
- warningStyle.getStyle());
- event.styles = new StyleRange[] {styleRange};
- return;
- }
- }
-
- // No highlighting needed
- event.styles = new StyleRange[0];
- }
-}
diff --git
a/ui/src/main/java/org/apache/hop/ui/hopgui/file/pipeline/HopGuiLogBrowser.java
b/ui/src/main/java/org/apache/hop/ui/hopgui/file/pipeline/HopGuiLogBrowser.java
index a5976a99b4..0c376a31fc 100644
---
a/ui/src/main/java/org/apache/hop/ui/hopgui/file/pipeline/HopGuiLogBrowser.java
+++
b/ui/src/main/java/org/apache/hop/ui/hopgui/file/pipeline/HopGuiLogBrowser.java
@@ -34,6 +34,7 @@ import org.apache.hop.core.logging.HopLoggingEvent;
import org.apache.hop.core.logging.IHasLogChannel;
import org.apache.hop.core.logging.ILogChannel;
import org.apache.hop.core.logging.ILogParentProvided;
+import org.apache.hop.core.logging.LogLevel;
import org.apache.hop.core.logging.LoggingRegistry;
import org.apache.hop.core.util.EnvUtil;
import org.apache.hop.core.util.ExecutorUtil;
@@ -42,9 +43,12 @@ import org.apache.hop.core.variables.DescribedVariable;
import org.apache.hop.i18n.BaseMessages;
import org.apache.hop.ui.core.ConstUi;
import org.apache.hop.ui.core.gui.GuiResource;
+import org.apache.hop.ui.core.widget.StyledTextVar;
import org.apache.hop.ui.core.widget.TextComposite;
import org.apache.hop.ui.hopgui.HopGui;
import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StyleRange;
+import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
@@ -137,23 +141,59 @@ public class HopGuiLogBrowser {
Const.toInt(describedVariable.getValue(),
Const.MAX_NR_LOG_LINES);
}
+ // Get the StyledText widget if available for
direct style application
+ StyledText styledText = null;
+ if (text instanceof StyledTextVar) {
+ styledText = ((StyledTextVar)
text).getTextWidget();
+ }
+
synchronized (text) {
for (HopLoggingEvent event : logLines) {
String line = logLayout.format(event).trim();
int length = line.length();
if (length > 0) {
- // Append by inserting at end
- String currentText = text.getText();
- text.setText(currentText + line + Const.CR);
+ boolean isError =
+ event.getLevel() != null
+ && event.getLevel().getLevel()
+ == LogLevel.ERROR.getLevel();
+
+ if (styledText != null &&
!styledText.isDisposed()) {
+ try {
+ // Get the current text length (this is
where we'll insert)
+ int startOffset =
styledText.getCharCount();
+ String textToAdd = line + Const.CR;
+
+ // Use replaceTextRange to add text at
the end
+ styledText.replaceTextRange(startOffset,
0, textToAdd);
+
+ // Apply red color directly if this is
an ERROR level event
+ if (isError) {
+ StyleRange styleRange = new
StyleRange();
+ styleRange.start = startOffset;
+ styleRange.length = line.length();
+ styleRange.foreground =
+
GuiResource.getInstance().getColorRed();
+ styleRange.fontStyle = SWT.NORMAL;
+ styledText.setStyleRange(styleRange);
+ }
+ } catch (Exception e) {
+ // Fallback to setText if there's any
error
+ String currentText = text.getText();
+ text.setText(currentText + line +
Const.CR);
+ }
+ } else {
+ // Fallback for non-StyledText widgets
(e.g., web mode)
+ String currentText = text.getText();
+ text.setText(currentText + line +
Const.CR);
+ }
}
}
}
- // Erase it all in one go
- // This makes it a bit more efficient
- String textContent = text.getText();
+ // Trim old lines if needed to stay within maxSize
// Calculate line count
+ String textContent = text.getText();
int size;
if (textContent == null || textContent.isEmpty()) {
size = 0;
@@ -169,7 +209,13 @@ public class HopGuiLogBrowser {
if (maxSize > 0 && size > maxSize) {
int dropIndex =
StringUtils.lastOrdinalIndexOf(textContent,
"\n", maxSize + 1);
- text.setText(textContent.substring(dropIndex +
1));
+ if (styledText != null &&
!styledText.isDisposed()) {
+ // Use replaceTextRange to preserve styles on
remaining text
+ styledText.replaceTextRange(0, dropIndex + 1,
"");
+ } else {
+ // Fallback for non-StyledText widgets
+ text.setText(textContent.substring(dropIndex +
1));
+ }
}
text.setSelection(text.getCharCount());
diff --git
a/ui/src/main/java/org/apache/hop/ui/hopgui/file/pipeline/delegates/HopGuiPipelineLogDelegate.java
b/ui/src/main/java/org/apache/hop/ui/hopgui/file/pipeline/delegates/HopGuiPipelineLogDelegate.java
index 7ab4fee70b..41b7720563 100644
---
a/ui/src/main/java/org/apache/hop/ui/hopgui/file/pipeline/delegates/HopGuiPipelineLogDelegate.java
+++
b/ui/src/main/java/org/apache/hop/ui/hopgui/file/pipeline/delegates/HopGuiPipelineLogDelegate.java
@@ -33,9 +33,9 @@ import org.apache.hop.ui.core.PropsUi;
import org.apache.hop.ui.core.dialog.EnterSelectionDialog;
import org.apache.hop.ui.core.gui.GuiResource;
import org.apache.hop.ui.core.gui.GuiToolbarWidgets;
-import org.apache.hop.ui.core.widget.LogStyledTextComp;
import org.apache.hop.ui.core.widget.OsHelper;
import org.apache.hop.ui.core.widget.StyledTextComp;
+import org.apache.hop.ui.core.widget.StyledTextVar;
import org.apache.hop.ui.core.widget.TextComposite;
import org.apache.hop.ui.hopgui.HopGui;
import org.apache.hop.ui.hopgui.file.IHopFileTypeHandler;
@@ -116,8 +116,8 @@ public class HopGuiPipelineLogDelegate {
fd.right = new FormAttachment(100, 0);
toolbar.setLayoutData(fd);
- // Use StyledTextComp for web (uses Text widget), LogStyledTextComp for
desktop (with
- // highlighting)
+ // Use StyledTextComp for web (uses Text widget), StyledTextVar for
desktop (uses StyledText
+ // for highlighting)
if (EnvironmentUtils.getInstance().isWeb()) {
pipelineLogText =
new StyledTextComp(
@@ -126,12 +126,13 @@ public class HopGuiPipelineLogDelegate {
SWT.READ_ONLY | SWT.BORDER | SWT.MULTI | SWT.V_SCROLL |
SWT.H_SCROLL);
} else {
pipelineLogText =
- new LogStyledTextComp(
+ new StyledTextVar(
pipelineGraph.getVariables(),
pipelineLogComposite,
- SWT.READ_ONLY | SWT.BORDER | SWT.MULTI | SWT.V_SCROLL |
SWT.H_SCROLL);
- // Add log highlighting (only works in SWT, not RWT)
- pipelineLogText.addLineStyleListener();
+ SWT.READ_ONLY | SWT.BORDER | SWT.MULTI | SWT.V_SCROLL |
SWT.H_SCROLL,
+ false,
+ false);
+ // Error highlighting is applied directly in HopGuiLogBrowser when
adding lines
}
PropsUi.setLook(pipelineLogText);
FormData fdText = new FormData();
diff --git
a/ui/src/main/java/org/apache/hop/ui/hopgui/file/workflow/delegates/HopGuiWorkflowLogDelegate.java
b/ui/src/main/java/org/apache/hop/ui/hopgui/file/workflow/delegates/HopGuiWorkflowLogDelegate.java
index a71f88f659..50964aea83 100644
---
a/ui/src/main/java/org/apache/hop/ui/hopgui/file/workflow/delegates/HopGuiWorkflowLogDelegate.java
+++
b/ui/src/main/java/org/apache/hop/ui/hopgui/file/workflow/delegates/HopGuiWorkflowLogDelegate.java
@@ -29,9 +29,9 @@ import org.apache.hop.ui.core.PropsUi;
import org.apache.hop.ui.core.dialog.EnterSelectionDialog;
import org.apache.hop.ui.core.gui.GuiResource;
import org.apache.hop.ui.core.gui.GuiToolbarWidgets;
-import org.apache.hop.ui.core.widget.LogStyledTextComp;
import org.apache.hop.ui.core.widget.OsHelper;
import org.apache.hop.ui.core.widget.StyledTextComp;
+import org.apache.hop.ui.core.widget.StyledTextVar;
import org.apache.hop.ui.core.widget.TextComposite;
import org.apache.hop.ui.hopgui.HopGui;
import org.apache.hop.ui.hopgui.file.IHopFileTypeHandler;
@@ -117,8 +117,8 @@ public class HopGuiWorkflowLogDelegate {
fd.right = new FormAttachment(100, 0);
toolbar.setLayoutData(fd);
- // Use StyledTextComp for web (uses Text widget), LogStyledTextComp for
desktop (with
- // highlighting)
+ // Use StyledTextComp for web (uses Text widget), StyledTextVar for
desktop (uses StyledText
+ // for highlighting)
if (EnvironmentUtils.getInstance().isWeb()) {
workflowLogText =
new StyledTextComp(
@@ -127,12 +127,13 @@ public class HopGuiWorkflowLogDelegate {
SWT.READ_ONLY | SWT.BORDER | SWT.MULTI | SWT.V_SCROLL |
SWT.H_SCROLL);
} else {
workflowLogText =
- new LogStyledTextComp(
+ new StyledTextVar(
workflowGraph.getVariables(),
workflowLogComposite,
- SWT.READ_ONLY | SWT.BORDER | SWT.MULTI | SWT.V_SCROLL |
SWT.H_SCROLL);
- // Add log highlighting (only works in SWT, not RWT)
- workflowLogText.addLineStyleListener();
+ SWT.READ_ONLY | SWT.BORDER | SWT.MULTI | SWT.V_SCROLL |
SWT.H_SCROLL,
+ false,
+ false);
+ // Error highlighting is applied directly in HopGuiLogBrowser when
adding lines
}
PropsUi.setLook(workflowLogText);
FormData fdText = new FormData();