This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch fix/camel-tui-polish in repository https://gitbox.apache.org/repos/asf/camel.git
commit 5ac79efefc30b007584165599558e3f17531b09d Author: Claus Ibsen <[email protected]> AuthorDate: Sat May 16 19:59:53 2026 +0200 TUI: enrich overview info panel with runtime, JVM, heap and thread details Add an info panel beside the throughput chart on the Overview tab showing: - Runtime platform and Camel version - JVM version, vendor, and VM name (new fields added to LocalCliConnector) - Uptime, heap (used/max/%), non-heap (metaspace), and thread counts Also emits javaVendor and javaVmName from LocalCliConnector via RuntimeMXBean. Co-Authored-By: Claude Sonnet 4.6 <[email protected]> --- .../camel/cli/connector/LocalCliConnector.java | 2 + .../dsl/jbang/core/commands/tui/CamelMonitor.java | 131 +++++++++++++++------ 2 files changed, 96 insertions(+), 37 deletions(-) diff --git a/dsl/camel-cli-connector/src/main/java/org/apache/camel/cli/connector/LocalCliConnector.java b/dsl/camel-cli-connector/src/main/java/org/apache/camel/cli/connector/LocalCliConnector.java index aa98e238b689..438e7d426006 100644 --- a/dsl/camel-cli-connector/src/main/java/org/apache/camel/cli/connector/LocalCliConnector.java +++ b/dsl/camel-cli-connector/src/main/java/org/apache/camel/cli/connector/LocalCliConnector.java @@ -1098,6 +1098,8 @@ public class LocalCliConnector extends ServiceSupport implements CliConnector, C RuntimeMXBean mb = ManagementFactory.getRuntimeMXBean(); if (mb != null) { rc.put("javaVersion", mb.getVmVersion()); + rc.put("javaVendor", mb.getVmVendor()); + rc.put("javaVmName", mb.getVmName()); } root.put("runtime", rc); diff --git a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java index 7f27d0da2b73..3f369a0219f7 100644 --- a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java +++ b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java @@ -1002,10 +1002,17 @@ public class CamelMonitor extends CamelCommand { if (hasSparkline && chunks.size() > 1) { Rect chartTotalArea = chunks.get(1); + // Split chart area horizontally: bar chart (fill) + info panel (30 cols) + List<Rect> chartHSplit = Layout.horizontal() + .constraints(Constraint.fill(), Constraint.length(30)) + .split(chartTotalArea); + Rect chartArea = chartHSplit.get(0); + Rect infoArea = chartHSplit.get(1); + // Split chart area: chart rows (13) + x-axis label row (1) List<Rect> vChunks = Layout.vertical() .constraints(Constraint.fill(), Constraint.length(1)) - .split(chartTotalArea); + .split(chartArea); // Split chart rows: y-axis labels (4 cols) + bar chart (fill) List<Rect> hChunks = Layout.horizontal() @@ -1114,9 +1121,84 @@ public class CamelMonitor extends CamelCommand { } } } + + // Info panel: heap and threads for the selected integration + renderOverviewInfoPanel(frame, infoArea); } } + private void renderOverviewInfoPanel(Frame frame, Rect area) { + IntegrationInfo sel = findSelectedIntegration(); + // Fall back to the single active integration when nothing is explicitly selected + if (sel == null) { + List<IntegrationInfo> active = data.get().stream().filter(i -> !i.vanishing).toList(); + if (active.size() == 1) { + sel = active.get(0); + } + } + Block infoBlock = Block.builder().borderType(BorderType.ROUNDED).build(); + frame.renderWidget(infoBlock, area); + Rect inner = infoBlock.inner(area); + List<Line> lines = new ArrayList<>(); + Style dim = Style.EMPTY.dim(); + if (sel != null) { + // Identity + if (sel.platform != null) { + String plat = sel.platformVersion != null + ? sel.platform + "/" + sel.platformVersion + : sel.platform; + lines.add(Line.from( + Span.styled("Runtime: ", dim), + Span.raw(TuiHelper.truncate(plat, inner.width() - 9)))); + } + if (sel.camelVersion != null) { + lines.add(Line.from( + Span.styled("Version: ", dim), + Span.raw(TuiHelper.truncate(sel.camelVersion, inner.width() - 9)))); + } + lines.add(Line.from(Span.raw(""))); + // Resources + if (sel.javaVersion != null) { + lines.add(Line.from( + Span.styled("JVM: ", dim), + Span.raw(TuiHelper.truncate(sel.javaVersion, inner.width() - 6)))); + } + if (sel.javaVendor != null) { + lines.add(Line.from( + Span.styled(" ", dim), + Span.raw(TuiHelper.truncate(sel.javaVendor, inner.width() - 6)))); + } + if (sel.javaVmName != null) { + lines.add(Line.from( + Span.styled(" ", dim), + Span.raw(TuiHelper.truncate(sel.javaVmName, inner.width() - 6)))); + } + lines.add(Line.from( + Span.styled("Uptime: ", dim), + Span.raw(sel.ago != null ? sel.ago : "-"))); + if (sel.heapMemUsed > 0) { + String heap = formatMemory(sel.heapMemUsed, sel.heapMemMax); + long pct = sel.heapMemMax > 0 ? sel.heapMemUsed * 100 / sel.heapMemMax : 0; + lines.add(Line.from( + Span.styled("Heap: ", dim), + Span.raw(heap + " " + pct + "%"))); + } + if (sel.nonHeapMemUsed > 0) { + lines.add(Line.from( + Span.styled("Meta: ", dim), + Span.raw(formatMemory(sel.nonHeapMemUsed, 0)))); + } + if (sel.threadCount > 0) { + lines.add(Line.from( + Span.styled("Thds: ", dim), + Span.raw(sel.threadCount + " / " + sel.peakThreadCount))); + } + } else { + lines.add(Line.from(Span.raw("-"))); + } + frame.renderWidget(Paragraph.builder().text(Text.from(lines)).build(), inner); + } + // ---- Tab 2: Routes ---- private void renderRoutes(Frame frame, Rect area) { @@ -1633,24 +1715,13 @@ public class CamelMonitor extends CamelCommand { } private void renderDiagram(Frame frame, Rect area) { - IntegrationInfo sel = findSelectedIntegration(); - - // Split: diagram (fill) + info panel (24 cols) - List<Rect> hSplit = Layout.horizontal() - .constraints(Constraint.fill(), Constraint.length(24)) - .split(area); - Rect diagramArea = hSplit.get(0); - Rect infoArea = hSplit.get(1); - - Rect area2 = diagramArea; Block block = Block.builder() .borderType(BorderType.ROUNDED) .title(diagramTextMode ? "" : " Diagram [" + diagramRouteId + "] ") .build(); if (diagramFullImageData != null) { - renderImageDiagram(frame, area2, block); - renderDiagramInfoPanel(frame, infoArea, sel); + renderImageDiagram(frame, area, block); return; } @@ -1660,7 +1731,7 @@ public class CamelMonitor extends CamelCommand { maxWidth = Math.max(maxWidth, CharWidth.of(line)); } - Rect inner = block.inner(area2); + Rect inner = block.inner(area); // Reserve 1 col for vertical scrollbar, 1 row for horizontal scrollbar int visibleLines = Math.max(1, inner.height() - 1); int visibleCols = Math.max(1, inner.width() - 1); @@ -1682,7 +1753,7 @@ public class CamelMonitor extends CamelCommand { } // Layout: outer block wraps everything, inner splits content + scrollbars - frame.renderWidget(block, area2); + frame.renderWidget(block, area); // Vertical layout inside the block: [content row (fill), horizontal scrollbar (1 row)] List<Rect> vChunks = Layout.vertical() @@ -1717,28 +1788,6 @@ public class CamelMonitor extends CamelCommand { Scrollbar.horizontal(), vChunks.get(1), diagramHScrollState); } - - renderDiagramInfoPanel(frame, infoArea, sel); - } - - private void renderDiagramInfoPanel(Frame frame, Rect area, IntegrationInfo sel) { - List<Line> infoLines = new ArrayList<>(); - if (sel != null) { - infoLines.add(Line.from(Span.styled("HEAP", Style.EMPTY.bold()))); - String heap = formatMemory(sel.heapMemUsed, sel.heapMemMax); - long pct = sel.heapMemMax > 0 ? sel.heapMemUsed * 100 / sel.heapMemMax : 0; - infoLines.add(Line.from(Span.raw(heap.isEmpty() ? "-" : heap + " (" + pct + "%)"))); - infoLines.add(Line.from(Span.raw(""))); - infoLines.add(Line.from(Span.styled("THREADS", Style.EMPTY.bold()))); - infoLines.add(Line.from(Span.raw("Current: " + sel.threadCount))); - infoLines.add(Line.from(Span.raw("Peak: " + sel.peakThreadCount))); - } - frame.renderWidget( - Paragraph.builder() - .text(Text.from(infoLines)) - .block(Block.builder().borderType(BorderType.ROUNDED).title(" Info ").build()) - .build(), - area); } private void renderImageDiagram(Frame frame, Rect area, Block block) { @@ -3850,6 +3899,9 @@ public class CamelMonitor extends CamelCommand { JsonObject runtime = (JsonObject) root.get("runtime"); info.platform = runtime != null ? runtime.getString("platform") : null; info.platformVersion = runtime != null ? runtime.getString("platformVersion") : null; + info.javaVersion = runtime != null ? runtime.getString("javaVersion") : null; + info.javaVendor = runtime != null ? runtime.getString("javaVendor") : null; + info.javaVmName = runtime != null ? runtime.getString("javaVmName") : null; Map<String, ?> stats = context.getMap("statistics"); if (stats != null) { @@ -3884,6 +3936,7 @@ public class CamelMonitor extends CamelCommand { if (mem != null) { info.heapMemUsed = mem.getLongOrDefault("heapMemoryUsed", 0L); info.heapMemMax = mem.getLongOrDefault("heapMemoryMax", 0L); + info.nonHeapMemUsed = mem.getLongOrDefault("nonHeapMemoryUsed", 0L); } JsonObject threads = (JsonObject) root.get("threads"); @@ -4186,6 +4239,9 @@ public class CamelMonitor extends CamelCommand { String camelVersion; String platform; String platformVersion; + String javaVersion; + String javaVendor; + String javaVmName; String profile; String ready; int state; @@ -4205,6 +4261,7 @@ public class CamelMonitor extends CamelCommand { int routeTotal; long heapMemUsed; long heapMemMax; + long nonHeapMemUsed; int threadCount; int peakThreadCount; boolean vanishing;
