This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch fix/camel-tui-load-avg in repository https://gitbox.apache.org/repos/asf/camel.git
commit 7ae71757258923e2a9424f5d6c48800a55d005e6 Author: Claus Ibsen <[email protected]> AuthorDate: Sun May 17 19:50:52 2026 +0200 TUI: fix overview selection bugs - sort consistency and inflight load from JSON - Extract sortedOverviewInfos() so renderOverview, syncSelectedPidFromOverview, selectCurrentIntegration, and navigateDown all use the same sorted order; previously UP/DOWN keys resolved row index against an unsorted list while the table rendered a sorted one, causing the wrong integration to be selected - Read inflight load01/05/15 directly from the management JSON (already computed by ManagedCamelContext.LoadTriplet and serialized by ContextDevConsole) instead of maintaining a redundant local EWMA; works correctly for remote processes too Co-Authored-By: Claude Sonnet 4.6 <[email protected]> --- .../dsl/jbang/core/commands/tui/CamelMonitor.java | 48 +++++++++++++++------- 1 file changed, 33 insertions(+), 15 deletions(-) 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 5cc05f6bf56b..85bdcbc3eb37 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 @@ -184,9 +184,8 @@ public class CamelMonitor extends CamelCommand { private final Map<String, LinkedList<long[]>> endpointRemoteSamples = new ConcurrentHashMap<>(); private final Map<String, Long> previousEndpointRemoteTime = new ConcurrentHashMap<>(); - // Load averages (EWMA) — CPU% and inflight exchanges, per PID + // Load averages (EWMA) — CPU%, per PID (inflight EWMA is read from the management JSON) private final Map<String, LoadAvg> cpuLoadAvg = new ConcurrentHashMap<>(); - private final Map<String, LoadAvg> inflightLoadAvg = new ConcurrentHashMap<>(); private final Map<String, long[]> prevCpuSample = new ConcurrentHashMap<>(); // Overview sort state @@ -868,11 +867,19 @@ public class CamelMonitor extends CamelCommand { return true; } + // Returns integrations in the same order the overview table renders them. + // Must be used anywhere that translates a table row index to a PID. + private List<IntegrationInfo> sortedOverviewInfos() { + List<IntegrationInfo> infos = new ArrayList<>(data.get()); + infos.sort(this::sortOverview); + return infos; + } + private void selectCurrentIntegration() { if (selectedPid != null) { return; } - List<IntegrationInfo> infos = data.get().stream().filter(i -> !i.vanishing).toList(); + List<IntegrationInfo> infos = sortedOverviewInfos(); Integer sel = overviewTableState.selected(); if (sel != null && sel >= 0 && sel < infos.size()) { selectedPid = infos.get(sel).pid; @@ -889,7 +896,7 @@ public class CamelMonitor extends CamelCommand { } private void syncSelectedPidFromOverview() { - List<IntegrationInfo> infos = data.get().stream().filter(i -> !i.vanishing).toList(); + List<IntegrationInfo> infos = sortedOverviewInfos(); Integer sel = overviewTableState.selected(); String newPid = null; if (sel != null && sel >= 0 && sel < infos.size()) { @@ -977,7 +984,7 @@ public class CamelMonitor extends CamelCommand { List<IntegrationInfo> infos = data.get().stream().filter(i -> !i.vanishing).toList(); switch (tabsState.selected()) { case TAB_OVERVIEW -> { - overviewTableState.selectNext(infos.size()); + overviewTableState.selectNext(sortedOverviewInfos().size()); syncSelectedPidFromOverview(); } case TAB_ROUTES -> { @@ -1129,8 +1136,17 @@ public class CamelMonitor extends CamelCommand { // ---- Tab 1: Overview ---- private void renderOverview(Frame frame, Rect area) { - List<IntegrationInfo> infos = new ArrayList<>(data.get()); - infos.sort(this::sortOverview); + List<IntegrationInfo> infos = sortedOverviewInfos(); + + // Keep the table selection index tracking the same PID across sort changes and data refreshes + if (selectedPid != null) { + for (int i = 0; i < infos.size(); i++) { + if (selectedPid.equals(infos.get(i).pid)) { + overviewTableState.select(i); + break; + } + } + } // Split: table (fill) + chart (14 rows: 13 chart + 1 x-axis) if we have data boolean hasSparkline = !throughputHistory.isEmpty(); @@ -1464,8 +1480,8 @@ public class CamelMonitor extends CamelCommand { Span.raw(sel.threadCount + " / " + sel.peakThreadCount))); } LoadAvg cpu = cpuLoadAvg.get(sel.pid); - LoadAvg infl = inflightLoadAvg.get(sel.pid); - if (cpu != null || infl != null) { + boolean hasInfl = sel.inflightLoad01 != null && !sel.inflightLoad01.isEmpty(); + if (cpu != null || hasInfl) { lines.add(Line.from(Span.raw(""))); lines.add(Line.from(Span.styled("Load (1m/5m/15m):", dim))); if (cpu != null) { @@ -1473,10 +1489,10 @@ public class CamelMonitor extends CamelCommand { Span.styled("CPU: ", dim), Span.raw(cpu.format("%.1f / %.1f / %.1f %%")))); } - if (infl != null) { + if (hasInfl) { lines.add(Line.from( Span.styled("Infl: ", dim), - Span.raw(infl.format("%.1f / %.1f / %.1f")))); + Span.raw(sel.inflightLoad01 + " / " + sel.inflightLoad05 + " / " + sel.inflightLoad15))); } } } else { @@ -4165,7 +4181,6 @@ public class CamelMonitor extends CamelCommand { endpointRemoteSamples.remove(entry.getKey()); previousEndpointRemoteTime.remove(entry.getKey()); cpuLoadAvg.remove(entry.getKey()); - inflightLoadAvg.remove(entry.getKey()); prevCpuSample.remove(entry.getKey()); } else if (!livePids.contains(entry.getKey())) { IntegrationInfo ghost = entry.getValue().info; @@ -4343,9 +4358,6 @@ public class CamelMonitor extends CamelCommand { private void updateLoadMetrics(ProcessHandle ph, IntegrationInfo info) { String pid = info.pid; - // Inflight EWMA — feed current inflight count directly - inflightLoadAvg.computeIfAbsent(pid, k -> new LoadAvg()).update(info.inflight); - // CPU EWMA — compute % from ProcessHandle CPU duration delta Optional<Duration> durOpt = ph.info().totalCpuDuration(); if (durOpt.isPresent()) { @@ -4793,6 +4805,9 @@ public class CamelMonitor extends CamelCommand { info.exchangesTotal = objToLong(stats.get("exchangesTotal")); info.failed = objToLong(stats.get("exchangesFailed")); info.inflight = objToLong(stats.get("exchangesInflight")); + info.inflightLoad01 = objToString(stats.get("load01")); + info.inflightLoad05 = objToString(stats.get("load05")); + info.inflightLoad15 = objToString(stats.get("load15")); info.last = objToString(stats.get("lastProcessingTime")); info.delta = objToString(stats.get("deltaProcessingTime")); long tsStarted = objToLong(stats.get("lastCreatedExchangeTimestamp")); @@ -5164,6 +5179,9 @@ public class CamelMonitor extends CamelCommand { long exchangesTotal; long failed; long inflight; + String inflightLoad01; + String inflightLoad05; + String inflightLoad15; String last; String delta; String sinceLastStarted;
