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

davsclaus pushed a commit to branch fix/camel-tui-circuit-breaker
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/fix/camel-tui-circuit-breaker 
by this push:
     new 28fe407af695 TUI: split throughput bar chart into green/red ok/failed 
bars
28fe407af695 is described below

commit 28fe407af69560fcff00cd423c615a2a829bafa0
Author: Claus Ibsen <[email protected]>
AuthorDate: Sat May 16 15:45:03 2026 +0200

    TUI: split throughput bar chart into green/red ok/failed bars
    
    Track failed/s alongside total/s in the sparkline history. Each time
    slot in the overview chart now renders as two bars side-by-side:
    - green bar = ok exchanges per second (total - failed)
    - red bar = failed exchanges per second
    
    30 time slots × 2 bars × width=1 = ~60 columns, preserving the same
    visual footprint as the previous single-bar chart. Chart title shows
    current throughput broken down as 'N ok / M failed'.
    
    Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
---
 .../dsl/jbang/core/commands/tui/CamelMonitor.java  | 68 +++++++++++++++-------
 1 file changed, 47 insertions(+), 21 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 3d8a9e154f21..2414b4c60683 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
@@ -152,7 +152,9 @@ public class CamelMonitor extends CamelCommand {
 
     // Sparkline: throughput history per PID (one point per second)
     private final Map<String, LinkedList<Long>> throughputHistory = new 
ConcurrentHashMap<>();
-    // Sliding window of [timestamp, exchangesTotal] samples for smoothing
+    // Sparkline: failed throughput history per PID (one point per second)
+    private final Map<String, LinkedList<Long>> failedHistory = new 
ConcurrentHashMap<>();
+    // Sliding window of [timestamp, exchangesTotal, exchangesFailed] samples 
for smoothing
     private final Map<String, LinkedList<long[]>> throughputSamples = new 
ConcurrentHashMap<>();
     // Track last time a sparkline point was recorded
     private final Map<String, Long> previousExchangesTime = new 
ConcurrentHashMap<>();
@@ -974,28 +976,43 @@ public class CamelMonitor extends CamelCommand {
 
         frame.renderStatefulWidget(table, chunks.get(0), overviewTableState);
 
-        // Sparkline for throughput
+        // Split green/red throughput bar chart
         if (hasSparkline && chunks.size() > 1) {
-            // Merge all throughput histories for overview chart
-            LinkedList<Long> merged = new LinkedList<>();
-            for (int i = 0; i < MAX_SPARKLINE_POINTS; i++) {
-                long sum = 0;
+            // Render last 30 ticks as pairs of bars (ok=green, failed=red) to 
keep ~60 columns
+            int renderPoints = Math.min(30, MAX_SPARKLINE_POINTS);
+            long[] mergedTotal = new long[renderPoints];
+            long[] mergedFailed = new long[renderPoints];
+            for (int i = 0; i < renderPoints; i++) {
                 for (LinkedList<Long> hist : throughputHistory.values()) {
-                    if (i < hist.size()) {
-                        sum += hist.get(hist.size() - 1 - i);
+                    int idx = hist.size() - renderPoints + i;
+                    if (idx >= 0) {
+                        mergedTotal[i] += hist.get(idx);
+                    }
+                }
+                for (LinkedList<Long> hist : failedHistory.values()) {
+                    int idx = hist.size() - renderPoints + i;
+                    if (idx >= 0) {
+                        mergedFailed[i] += hist.get(idx);
                     }
                 }
-                merged.addFirst(sum);
             }
 
-            // Compute stats for title display
-            long maxTp = 
merged.stream().mapToLong(Long::longValue).max().orElse(0);
-            long curTp = merged.isEmpty() ? 0 : merged.get(merged.size() - 1);
-            String chartTitle = String.format(" Throughput: %d msg/s (peak: 
%d) ", curTp, maxTp);
+            long maxTp = 0;
+            for (long v : mergedTotal) {
+                maxTp = Math.max(maxTp, v);
+            }
+            long curTp = mergedTotal[renderPoints - 1];
+            long curFailed = mergedFailed[renderPoints - 1];
+            long curOk = Math.max(0, curTp - curFailed);
+            String chartTitle = String.format(" Throughput: %d msg/s (%d ok / 
%d failed) ", curTp, curOk, curFailed);
 
             List<BarGroup> groups = new ArrayList<>();
-            for (Long value : merged) {
-                groups.add(BarGroup.of(Bar.of(value)));
+            for (int i = 0; i < renderPoints; i++) {
+                long failed = Math.min(mergedFailed[i], mergedTotal[i]);
+                long ok = Math.max(0, mergedTotal[i] - failed);
+                groups.add(BarGroup.of(
+                        
Bar.builder().value(ok).style(Style.EMPTY.fg(Color.GREEN)).build(),
+                        
Bar.builder().value(failed).style(Style.EMPTY.fg(Color.RED)).build()));
             }
 
             BarChart barChart = BarChart.builder()
@@ -1003,7 +1020,7 @@ public class CamelMonitor extends CamelCommand {
                     .max(maxTp > 0 ? maxTp + 2 : 2)
                     .barWidth(1)
                     .barGap(0)
-                    .barStyle(Style.EMPTY.fg(Color.GREEN))
+                    .groupGap(0)
                     
.block(Block.builder().borderType(BorderType.ROUNDED).title(chartTitle).build())
                     .build();
 
@@ -3047,6 +3064,7 @@ public class CamelMonitor extends CamelCommand {
                 if (now - entry.getValue().startTime > VANISH_DURATION_MS) {
                     it.remove();
                     throughputHistory.remove(entry.getKey());
+                    failedHistory.remove(entry.getKey());
                 } else if (!livePids.contains(entry.getKey())) {
                     IntegrationInfo ghost = entry.getValue().info;
                     ghost.vanishing = true;
@@ -3077,13 +3095,14 @@ public class CamelMonitor extends CamelCommand {
     }
 
     private void updateThroughputHistory(IntegrationInfo info) {
-        // Track exchangesTotal over a 1-second sliding window for stable 
throughput
+        // Track exchangesTotal and exchangesFailed over a 1-second sliding 
window
         long currentTotal = info.exchangesTotal;
+        long currentFailed = info.failed;
         long now = System.currentTimeMillis();
 
         String pid = info.pid;
         LinkedList<long[]> samples = throughputSamples.computeIfAbsent(pid, k 
-> new LinkedList<>());
-        samples.add(new long[] { now, currentTotal });
+        samples.add(new long[] { now, currentTotal, currentFailed });
 
         // Remove samples older than 1 second
         while (!samples.isEmpty() && now - samples.get(0)[0] > 1000) {
@@ -3094,19 +3113,26 @@ public class CamelMonitor extends CamelCommand {
         if (samples.size() >= 2) {
             long[] oldest = samples.get(0);
             long[] newest = samples.get(samples.size() - 1);
-            long deltaExchanges = newest[1] - oldest[1];
+            long deltaTotal = newest[1] - oldest[1];
+            long deltaFailed = newest[2] - oldest[2];
             long deltaTimeMs = newest[0] - oldest[0];
-            long tp = deltaTimeMs > 0 ? (deltaExchanges * 1000) / deltaTimeMs 
: 0;
+            long tp = deltaTimeMs > 0 ? (deltaTotal * 1000) / deltaTimeMs : 0;
+            long fp = deltaTimeMs > 0 ? (deltaFailed * 1000) / deltaTimeMs : 0;
 
-            LinkedList<Long> hist = throughputHistory.computeIfAbsent(pid, k 
-> new LinkedList<>());
             // Only add one point per second to keep the sparkline meaningful
             Long lastTime = previousExchangesTime.get(pid);
             if (lastTime == null || now - lastTime >= 1000) {
                 previousExchangesTime.put(pid, now);
+                LinkedList<Long> hist = throughputHistory.computeIfAbsent(pid, 
k -> new LinkedList<>());
                 hist.add(tp);
                 while (hist.size() > MAX_SPARKLINE_POINTS) {
                     hist.remove(0);
                 }
+                LinkedList<Long> fhist = failedHistory.computeIfAbsent(pid, k 
-> new LinkedList<>());
+                fhist.add(fp);
+                while (fhist.size() > MAX_SPARKLINE_POINTS) {
+                    fhist.remove(0);
+                }
             }
         }
     }

Reply via email to