This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch CAMEL-26700-about in repository https://gitbox.apache.org/repos/asf/camel.git
commit fca75e237f10eeaf4615cb2b7ddb0f944a4ee4fb Author: Claus Ibsen <[email protected]> AuthorDate: Sat Nov 7 16:28:45 2026 +0100 CAMEL-26700: About - the seconds a circuit breaker of a route was open, as on the Timeline Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: Claus Ibsen <[email protected]> --- .../dsl/jbang/core/commands/tui/AboutView.java | 14 +++++++++++--- .../dsl/jbang/core/commands/tui/AboutViewTest.java | 21 +++++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/AboutView.java b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/AboutView.java index cd90522c73bd..77376ba71cc5 100644 --- a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/AboutView.java +++ b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/AboutView.java @@ -139,7 +139,7 @@ final class AboutView { /** * The keys of What happened: + zooms in on the last trouble in the window (a failure, a handled error, a - * redelivery, a route down), - zooms out, and ← → move a zoomed window. + * redelivery, a route down, a circuit breaker open), - zooms out, and ← → move a zoomed window. */ boolean handleKeyEvent(KeyEvent ke, IntegrationInfo info) { if (info == null) { @@ -226,7 +226,7 @@ final class AboutView { for (Timeline.RouteSeries r : ctx.timeline.routes(info.pid, routeOrder(info), windowEnd, seconds)) { for (int i = seconds - 1; i >= 0; i--) { if (r.failed()[i] > 0 || r.handled()[i] > 0 || r.recovered()[i] > 0 || r.attempts()[i] > 0 - || r.down()[i] > 0) { + || r.down()[i] > 0 || r.open()[i] > 0) { last = Math.max(last, windowEnd - seconds + 1 + i); break; } @@ -350,7 +350,7 @@ final class AboutView { long max = 1; // completed, recovered, handled, failed, down, redelivery attempts: the height is the exchanges done, the // attempts only colour the column (an exchange retried many times is still one exchange) - long[][] col = new long[columns][6]; + long[][] col = new long[columns][7]; for (int i = 0; i < seconds; i++) { long[] c = col[i / per]; c[0] += Math.max(0, r.completed()[i]); @@ -359,6 +359,7 @@ final class AboutView { c[3] += Math.max(0, r.failed()[i]); c[4] += Math.max(0, r.down()[i]); c[5] += Math.max(0, r.attempts()[i]); + c[6] = Math.max(c[6], r.open()[i]); } for (long[] c : col) { max = Math.max(max, c[0] + c[1] + c[2] + c[3]); @@ -367,6 +368,9 @@ final class AboutView { long t = c[0] + c[1] + c[2] + c[3]; if (c[4] > 0) { spans.add(Span.styled("░", Theme.error())); + } else if (c[6] > 0) { + // a circuit breaker of the route was open (half open dim), as on the Timeline + spans.add(Span.styled("▒", c[6] >= 2 ? Theme.notice() : Theme.muted())); } else if (t == 0 && c[5] == 0) { spans.add(Span.styled("·", Theme.muted())); } else { @@ -379,6 +383,10 @@ final class AboutView { } long done = r.total(r.completed()) + r.total(r.recovered()) + r.total(r.handled()) + r.total(r.failed()); spans.add(Span.styled(" " + done, Theme.success())); + if (r.openSeconds() > 0) { + spans.add(Span.styled(" ⚡ open " + r.openSeconds() + "s " + ago(last - lastAt(r.open(), end, seconds)), + Theme.notice())); + } // the worst that happened, when it last did, and for a recovery the failure it recovered from (a failed or // handled one has its cause on the Last 5m line and on the Timeline) long[] worst = r.total(r.failed()) > 0 ? r.failed() : r.total(r.handled()) > 0 ? r.handled() diff --git a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/AboutViewTest.java b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/AboutViewTest.java index 4701e5c185fc..adb4bdb54da3 100644 --- a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/AboutViewTest.java +++ b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/AboutViewTest.java @@ -144,6 +144,27 @@ class AboutViewTest { assertThat(render(about, info)).contains("1 recovered 2m ago · Connection refused"); } + @Test + void theSecondsACircuitBreakerOfARouteWasOpen() { + IntegrationInfo info = new IntegrationInfo(); + info.pid = "1234"; + RouteInfo r = new RouteInfo(); + r.routeId = "orders"; + info.routes.add(r); + MonitorContext ctx = new MonitorContext(new AtomicReference<>(List.of(info)), new AtomicReference<>(List.of())); + TimelineJson t = new TimelineJson(T0 / 1000 + 299, 300); + long[] states = new long[300]; + for (int i = 0; i < 300; i++) { + t.route("orders", "completed", i, 1); + states[i] = i >= 230 && i < 240 ? 2 : 0; + } + ctx.timeline.merge("1234", t.breaker("orders", "cb1", states).json(), true); + AboutView about = new AboutView(ctx); + // the bolt is two columns wide: the screen has a blank cell after it + String screen = render(about, info).replace("⚡ ", "⚡"); + assertThat(screen).contains("⚡ open 10s 1m ago").contains("▒"); + } + @Test void theSendsOfARouteToAnEndpoint() { IntegrationInfo info = new IntegrationInfo();
