This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 8955af9d7a18 CAMEL-23385: camel-diagram - Show live counters (#23094)
8955af9d7a18 is described below
commit 8955af9d7a1854f52c0553815702e8f5b894ebc9
Author: Claus Ibsen <[email protected]>
AuthorDate: Sun May 10 20:00:16 2026 +0200
CAMEL-23385: camel-diagram - Show live counters (#23094)
* CAMEL-23385: camel-diagram - Show live counters
---
.../camel/diagram/DefaultRouteDiagramDumper.java | 15 ++--
.../apache/camel/diagram/DiagramDevConsole.java | 11 ++-
.../camel/diagram/RouteDiagramLayoutEngine.java | 12 ++--
.../apache/camel/diagram/RouteDiagramRenderer.java | 71 +++++++++++++++++--
.../org/apache/camel/diagram/RouteDiagramTest.java | 3 +-
.../org/apache/camel/spi/RouteDiagramDumper.java | 26 ++++++-
.../camel-jbang-cmd-route-diagram.adoc | 2 +-
.../META-INF/camel-jbang-commands-metadata.json | 2 +-
.../commands/action/CamelRouteDiagramAction.java | 79 ++++++++++++----------
9 files changed, 158 insertions(+), 63 deletions(-)
diff --git
a/components/camel-diagram/src/main/java/org/apache/camel/diagram/DefaultRouteDiagramDumper.java
b/components/camel-diagram/src/main/java/org/apache/camel/diagram/DefaultRouteDiagramDumper.java
index 97a78d434494..364d579cf7dd 100644
---
a/components/camel-diagram/src/main/java/org/apache/camel/diagram/DefaultRouteDiagramDumper.java
+++
b/components/camel-diagram/src/main/java/org/apache/camel/diagram/DefaultRouteDiagramDumper.java
@@ -96,7 +96,7 @@ public class DefaultRouteDiagramDumper extends ServiceSupport
implements CamelCo
root = (JsonObject) dc.call(DevConsole.MediaType.JSON,
Map.of("filter", filter));
var routes = RouteDiagramHelper.parseRoutes(root);
- BufferedImage image = renderImage(routes, theme.name(), 12, 180,
"CODE");
+ BufferedImage image = renderImage(routes, theme.name(), 12, 180,
"CODE", false);
folder.mkdirs();
String name = RouteDiagramHelper.extractSourceName(group);
File f = new File(folder, name + ".png");
@@ -105,13 +105,15 @@ public class DefaultRouteDiagramDumper extends
ServiceSupport implements CamelCo
}
@Override
- public BufferedImage dumpRoutesAsImage(String filter, Theme theme,
NodeLabelMode nodeLabel, int nodeWidth, int fontSize) {
+ public BufferedImage dumpRoutesAsImage(
+ String filter, Theme theme, boolean metrics, NodeLabelMode
nodeLabel, int nodeWidth, int fontSize) {
// use dev-console to render the route structure in json format which
the diagram render expects
DevConsole dc =
getCamelContext().getCamelContextExtension().getContextPlugin(DevConsoleRegistry.class)
.resolveById("route-structure");
- JsonObject root = (JsonObject) dc.call(DevConsole.MediaType.JSON,
Map.of("filter", filter));
+ JsonObject root
+ = (JsonObject) dc.call(DevConsole.MediaType.JSON,
Map.of("filter", filter, "metric", String.valueOf(metrics)));
var routes = RouteDiagramHelper.parseRoutes(root);
- return renderImage(routes, theme.name(), fontSize, nodeWidth,
nodeLabel.name());
+ return renderImage(routes, theme.name(), fontSize, nodeWidth,
nodeLabel.name(), metrics);
}
@Override
@@ -128,9 +130,10 @@ public class DefaultRouteDiagramDumper extends
ServiceSupport implements CamelCo
}
private static BufferedImage renderImage(
- List<RouteDiagramLayoutEngine.RouteInfo> routes, String theme, int
fontSize, int nodeWidth, String nodeLabel) {
+ List<RouteDiagramLayoutEngine.RouteInfo> routes, String theme, int
fontSize, int nodeWidth,
+ String nodeLabel, boolean metrics) {
RouteDiagramRenderer renderer = new RouteDiagramRenderer(
- nodeWidth * RouteDiagramLayoutEngine.SCALE, fontSize *
RouteDiagramLayoutEngine.SCALE);
+ nodeWidth * RouteDiagramLayoutEngine.SCALE, fontSize *
RouteDiagramLayoutEngine.SCALE, metrics);
RouteDiagramLayoutEngine engine = new RouteDiagramLayoutEngine(
nodeWidth, fontSize,
RouteDiagramLayoutEngine.NodeLabelMode.valueOf(nodeLabel.toUpperCase()));
diff --git
a/components/camel-diagram/src/main/java/org/apache/camel/diagram/DiagramDevConsole.java
b/components/camel-diagram/src/main/java/org/apache/camel/diagram/DiagramDevConsole.java
index a4ad608e8722..261ae7e50646 100644
---
a/components/camel-diagram/src/main/java/org/apache/camel/diagram/DiagramDevConsole.java
+++
b/components/camel-diagram/src/main/java/org/apache/camel/diagram/DiagramDevConsole.java
@@ -55,6 +55,11 @@ public class DiagramDevConsole extends AbstractDevConsole {
*/
public static final String NODE_LABEL = "nodeLabel";
+ /**
+ * Whether to include live metric counters. Is default true.
+ */
+ public static final String METRIC = "metric";
+
public DiagramDevConsole() {
super("camel", "route-diagram", "Route Diagram", "Visual route
diagrams");
}
@@ -70,6 +75,7 @@ public class DiagramDevConsole extends AbstractDevConsole {
int nodeWidth = Integer
.parseInt(options.getOrDefault(NODE_WIDTH, "" +
RouteDiagramLayoutEngine.DEFAULT_BOX_WIDTH).toString());
String nodeLabel = (String) options.getOrDefault(NODE_LABEL,
RouteDiagramDumper.NodeLabelMode.CODE.name());
+ boolean metric = "true".equalsIgnoreCase((String)
options.getOrDefault(METRIC, "true"));
// special for text
if ("text".equalsIgnoreCase(theme)) {
@@ -78,7 +84,7 @@ public class DiagramDevConsole extends AbstractDevConsole {
try {
RouteDiagramDumper dumper =
PluginHelper.getRouteDiagramDumper(getCamelContext());
BufferedImage image = dumper.dumpRoutesAsImage(filter,
RouteDiagramDumper.Theme.valueOf(theme.toUpperCase()),
-
RouteDiagramDumper.NodeLabelMode.valueOf(nodeLabel.toUpperCase()), nodeWidth,
fontSize);
+ metric,
RouteDiagramDumper.NodeLabelMode.valueOf(nodeLabel.toUpperCase()), nodeWidth,
fontSize);
String base64 = dumper.imageToBase64(image);
// For HTML embedding:
String html = String.format(
@@ -102,12 +108,13 @@ public class DiagramDevConsole extends AbstractDevConsole
{
int nodeWidth = Integer
.parseInt(options.getOrDefault(NODE_WIDTH, "" +
RouteDiagramLayoutEngine.DEFAULT_BOX_WIDTH).toString());
String nodeLabel = (String) options.getOrDefault(NODE_LABEL,
RouteDiagramDumper.NodeLabelMode.CODE.name());
+ boolean metric = "true".equalsIgnoreCase((String)
options.getOrDefault(METRIC, "true"));
JsonObject root = new JsonObject();
try {
RouteDiagramDumper dumper =
PluginHelper.getRouteDiagramDumper(getCamelContext());
BufferedImage image = dumper.dumpRoutesAsImage(filter,
RouteDiagramDumper.Theme.valueOf(theme.toUpperCase()),
-
RouteDiagramDumper.NodeLabelMode.valueOf(nodeLabel.toUpperCase()), nodeWidth,
fontSize);
+ metric,
RouteDiagramDumper.NodeLabelMode.valueOf(nodeLabel.toUpperCase()), nodeWidth,
fontSize);
String base64 = dumper.imageToBase64(image);
root.put("image", base64);
} catch (Exception e) {
diff --git
a/components/camel-diagram/src/main/java/org/apache/camel/diagram/RouteDiagramLayoutEngine.java
b/components/camel-diagram/src/main/java/org/apache/camel/diagram/RouteDiagramLayoutEngine.java
index 9ca815c03cca..f052e68126c8 100644
---
a/components/camel-diagram/src/main/java/org/apache/camel/diagram/RouteDiagramLayoutEngine.java
+++
b/components/camel-diagram/src/main/java/org/apache/camel/diagram/RouteDiagramLayoutEngine.java
@@ -54,13 +54,13 @@ public class RouteDiagramLayoutEngine {
private final FontMetrics fontMetrics;
private final NodeLabelMode nodeLabelMode;
- private static final Set<String> BRANCHING_EIPS = Set.of(
+ static final Set<String> BRANCHING_EIPS = Set.of(
"choice", "multicast", "doTry", "loadBalance", "recipientList",
"circuitBreaker");
- private static final Set<String> BRANCH_CHILD_TYPES = Set.of(
+ static final Set<String> BRANCH_CHILD_TYPES = Set.of(
"when", "otherwise", "doCatch", "doFinally", "onFallback");
- private static final Set<String> STRUCTURAL_TYPES = Set.of(
+ static final Set<String> STRUCTURAL_TYPES = Set.of(
"route", "from");
static class Bounds {
@@ -162,13 +162,13 @@ public class RouteDiagramLayoutEngine {
public String routeId;
public String source;
public RouteStatInfo stat;
- public List<NodeInfo> nodes = new ArrayList<>();
+ public final List<NodeInfo> nodes = new ArrayList<>();
}
public static class TreeNode {
public final NodeInfo info;
public TreeNode parent;
- public List<TreeNode> children = new ArrayList<>();
+ public final List<TreeNode> children = new ArrayList<>();
public int subtreeWidth;
public LayoutNode layoutNode;
@@ -196,7 +196,7 @@ public class RouteDiagramLayoutEngine {
public int labelY;
public int maxX;
public int maxY;
- public List<LayoutNode> nodes = new ArrayList<>();
+ public final List<LayoutNode> nodes = new ArrayList<>();
}
public static TreeNode buildTree(List<NodeInfo> nodes) {
diff --git
a/components/camel-diagram/src/main/java/org/apache/camel/diagram/RouteDiagramRenderer.java
b/components/camel-diagram/src/main/java/org/apache/camel/diagram/RouteDiagramRenderer.java
index a77ff9722ef4..d261ffbbd135 100644
---
a/components/camel-diagram/src/main/java/org/apache/camel/diagram/RouteDiagramRenderer.java
+++
b/components/camel-diagram/src/main/java/org/apache/camel/diagram/RouteDiagramRenderer.java
@@ -30,6 +30,7 @@ import
org.apache.camel.diagram.RouteDiagramLayoutEngine.RouteInfo;
import org.apache.camel.diagram.RouteDiagramLayoutEngine.TreeNode;
import org.jline.utils.Colors;
+import static
org.apache.camel.diagram.RouteDiagramLayoutEngine.BRANCH_CHILD_TYPES;
import static org.apache.camel.diagram.RouteDiagramLayoutEngine.PADDING;
import static org.apache.camel.diagram.RouteDiagramLayoutEngine.SCALE;
import static org.apache.camel.diagram.RouteDiagramLayoutEngine.SCOPE_BOX_PAD;
@@ -61,6 +62,7 @@ public class RouteDiagramRenderer {
private final int fontSizeNode;
private final int fontSizeLabel;
private final int nodeTextPadding;
+ private final boolean metrics;
private static final String DARK_COLORS
=
"bg=#0d1117:text=#f0f6fc:arrow=#656c76:label=#d1d7e0:from=#238636:to=#1f6feb:eip=#8957e5"
@@ -80,25 +82,30 @@ public class RouteDiagramRenderer {
public RouteDiagramRenderer() {
this(RouteDiagramLayoutEngine.DEFAULT_BOX_WIDTH * SCALE,
RouteDiagramLayoutEngine.DEFAULT_FONT_SIZE * SCALE,
- new RouteDiagramLayoutEngine().getNodeTextPadding());
+ new RouteDiagramLayoutEngine().getNodeTextPadding(),
+ false);
}
- public RouteDiagramRenderer(int nodeWidth, int fontSizeScaled) {
+ public RouteDiagramRenderer(int nodeWidth, int fontSizeScaled, boolean
metrics) {
this(nodeWidth, fontSizeScaled, new RouteDiagramLayoutEngine(
- nodeWidth / SCALE, fontSizeScaled /
SCALE).getNodeTextPadding());
+ nodeWidth / SCALE, fontSizeScaled /
SCALE).getNodeTextPadding(),
+ metrics);
}
- public RouteDiagramRenderer(int nodeWidth, int fontSizeScaled, int
nodeTextPadding) {
+ public RouteDiagramRenderer(int nodeWidth, int fontSizeScaled, int
nodeTextPadding, boolean metrics) {
this.nodeWidth = nodeWidth;
this.fontSizeNode = fontSizeScaled;
this.fontSizeLabel = fontSizeScaled + 1 * SCALE;
this.nodeTextPadding = nodeTextPadding;
+ this.metrics = metrics;
}
public static class DiagramColors {
private Color bg;
private Color text;
private Color arrow;
+ private Color counter;
+ private Color counterFail;
private Color routeLabel;
private Color nodeFrom;
private Color nodeTo;
@@ -127,6 +134,8 @@ public class RouteDiagramRenderer {
c.bg = parseColor(map.get("bg"));
c.text = parseColor(map.getOrDefault("text", "#ffffff"));
c.arrow = parseColor(map.getOrDefault("arrow", "#b4b4b4"));
+ c.counter = parseColor(map.getOrDefault("counter", "#2e7d32"));
+ c.counterFail = parseColor(map.getOrDefault("counter", "#ff0000"));
c.routeLabel = parseColor(map.getOrDefault("label", "#c8c8c8"));
c.nodeFrom = parseColor(map.getOrDefault("from", "#2e7d32"));
c.nodeTo = parseColor(map.getOrDefault("to", "#1565c0"));
@@ -164,6 +173,14 @@ public class RouteDiagramRenderer {
return text;
}
+ public Color getCounter() {
+ return counter;
+ }
+
+ public Color getCounterFail() {
+ return counterFail;
+ }
+
public Color getArrow() {
return arrow;
}
@@ -292,8 +309,17 @@ public class RouteDiagramRenderer {
}
private void drawArrowFromMerge(Graphics2D g, LayoutNode to, DiagramColors
colors) {
+ var stat = to.treeNode.info.stat;
+ long total = stat != null ? stat.exchangesTotal : 0;
+ long failed = stat != null ? stat.exchangesFailed : 0;
+ long ok = total - failed;
+
g.setColor(colors.getArrow());
- g.setStroke(new BasicStroke(STROKE_WIDTH));
+ if (!metrics || total > 0) {
+ g.setStroke(new BasicStroke(STROKE_WIDTH));
+ } else {
+ g.setStroke(DASHED_STROKE);
+ }
int toCx = to.x + nodeWidth / 2;
int toTy = getTopY(to);
@@ -309,6 +335,16 @@ public class RouteDiagramRenderer {
g.drawLine(toCx, midY, toCx, toTy - ARROW_SIZE / 2);
}
drawArrowHead(g, toCx, toTy);
+
+ if (ok > 0) {
+ g.setColor(colors.getCounter());
+ g.drawString("" + ok, toCx + 2 + fontSizeNode, toTy - 2 -
fontSizeNode);
+ }
+ if (failed > 0) {
+ g.setColor(colors.getCounterFail());
+ int width = g.getFontMetrics().stringWidth("" + failed);
+ g.drawString("" + failed, toCx - 2 - fontSizeNode - width, toTy -
2 - fontSizeNode);
+ }
}
private void drawNode(Graphics2D g, LayoutNode node, DiagramColors colors)
{
@@ -345,8 +381,21 @@ public class RouteDiagramRenderer {
}
private void drawArrow(Graphics2D g, LayoutNode from, LayoutNode to,
DiagramColors colors) {
+ var stat = metrics ? to.treeNode.info.stat : null;
+ if (metrics && BRANCH_CHILD_TYPES.contains(to.type) &&
!to.treeNode.children.isEmpty()) {
+ // grab stat from first child (for example choice to have counters
for when/otherwise)
+ stat = to.treeNode.children.get(0).info.stat;
+ }
+ long total = stat != null ? stat.exchangesTotal : 0;
+ long failed = stat != null ? stat.exchangesFailed : 0;
+ long ok = total - failed;
+
g.setColor(colors.getArrow());
- g.setStroke(new BasicStroke(STROKE_WIDTH));
+ if (!metrics || total > 0) {
+ g.setStroke(new BasicStroke(STROKE_WIDTH));
+ } else {
+ g.setStroke(DASHED_STROKE);
+ }
int fromCx = from.x + nodeWidth / 2;
int fromBy = from.y + from.height;
@@ -362,6 +411,16 @@ public class RouteDiagramRenderer {
g.drawLine(toCx, midY, toCx, toTy - ARROW_SIZE / 2);
}
drawArrowHead(g, toCx, toTy);
+
+ if (ok > 0) {
+ g.setColor(colors.getCounter());
+ g.drawString("" + ok, toCx + 2 + fontSizeNode, toTy - 2 -
fontSizeNode);
+ }
+ if (failed > 0) {
+ g.setColor(colors.getCounterFail());
+ int width = g.getFontMetrics().stringWidth("" + failed);
+ g.drawString("" + failed, toCx - 2 - fontSizeNode - width, toTy -
2 - fontSizeNode);
+ }
}
private void drawArrowHead(Graphics2D g, int x, int y) {
diff --git
a/components/camel-diagram/src/test/java/org/apache/camel/diagram/RouteDiagramTest.java
b/components/camel-diagram/src/test/java/org/apache/camel/diagram/RouteDiagramTest.java
index 602fdbeb8d55..80e8f2359541 100644
---
a/components/camel-diagram/src/test/java/org/apache/camel/diagram/RouteDiagramTest.java
+++
b/components/camel-diagram/src/test/java/org/apache/camel/diagram/RouteDiagramTest.java
@@ -584,7 +584,8 @@ class RouteDiagramTest {
RouteDiagramLayoutEngine engine = new RouteDiagramLayoutEngine(250,
16);
LayoutRoute lr = engine.layoutRoute(route,
RouteDiagramLayoutEngine.PADDING);
- RouteDiagramRenderer renderer = new
RouteDiagramRenderer(engine.getNodeWidth(), 16 *
RouteDiagramLayoutEngine.SCALE);
+ RouteDiagramRenderer renderer
+ = new RouteDiagramRenderer(engine.getNodeWidth(), 16 *
RouteDiagramLayoutEngine.SCALE, false);
DiagramColors colors = DiagramColors.parse("dark");
BufferedImage image = renderer.renderDiagram(List.of(lr), lr.maxY +
RouteDiagramLayoutEngine.V_GAP, colors);
diff --git
a/core/camel-api/src/main/java/org/apache/camel/spi/RouteDiagramDumper.java
b/core/camel-api/src/main/java/org/apache/camel/spi/RouteDiagramDumper.java
index be0e9d95f4a7..7060cc5d0da2 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/RouteDiagramDumper.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/RouteDiagramDumper.java
@@ -43,26 +43,46 @@ public interface RouteDiagramDumper {
String FACTORY = "route-diagram-dumper";
/**
- * Dumps the routes into a single combined PNG file
+ * Dumps the routes as PNG files in the given file
+ *
+ * @param filter to filter routes
+ * @param theme the coloring theme
+ * @param file the name of the file to store
*/
void dumpRoutesToFile(String filter, Theme theme, File file) throws
IOException;
/**
* Dumps the routes as PNG files in the given folder
+ *
+ * @param filter to filter routes
+ * @param theme the coloring theme
+ * @param folder the folder to store the files
*/
void dumpRoutesToFolder(String filter, Theme theme, File folder) throws
IOException;
/**
* Dumps the routes as a PNG image
+ *
+ * @param filter to filter routes
+ * @param theme the coloring theme
*/
default BufferedImage dumpRoutesAsImage(String filter, Theme theme) {
- return dumpRoutesAsImage(filter, theme, NodeLabelMode.CODE, 180, 12);
+ return dumpRoutesAsImage(filter, theme, false, NodeLabelMode.CODE,
180, 12);
}
/**
* Dumps the routes as a PNG image
+ *
+ * @param filter to filter routes
+ * @param theme the coloring theme
+ * @param metrics whether to include live metric counters
+ * @param nodeLabel what information to display in the nodes
+ * @param nodeWidth the width in pixels of the node boxes
+ * @param fontSize the font size
*/
- BufferedImage dumpRoutesAsImage(String filter, Theme theme, NodeLabelMode
nodeLabel, int nodeWidth, int fontSize);
+ BufferedImage dumpRoutesAsImage(
+ String filter, Theme theme, boolean metrics,
+ NodeLabelMode nodeLabel, int nodeWidth, int fontSize);
/**
* Converts the image to base64
diff --git
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-cmd-route-diagram.adoc
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-cmd-route-diagram.adoc
index 4a900c5a1a56..be9889a6c1cd 100644
---
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-cmd-route-diagram.adoc
+++
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-cmd-route-diagram.adoc
@@ -23,7 +23,7 @@ camel cmd route-diagram [options]
| `--filter` | Filter route by filename or route id | | String
| `--font-size` | Font size in logical pixels for node text | 12 | int
| `--ignore-loading-error` | Whether to ignore route loading and compilation
errors (use this with care!) | false | boolean
-| `--metric` | Whether to include live metrics (only possible for running
Camel application) | false | boolean
+| `--metric` | Whether to include live metrics (only possible for running
Camel application) | true | boolean
| `--node-label` | What text to display in diagram nodes: code, description,
or both (default) | both | String
| `--output` | Save diagram to a PNG file instead of displaying in terminal |
| String
| `--theme,--colors` | Color theme preset (dark, light, transparent, text) or
custom colors (e.g. bg=#1e1e1e:from=#2e7d32:to=#1565c0). Values can be #hex or
ANSI color names (e.g. from=seagreen:to=steelblue). Use bg= for transparent.
Can also be set via DIAGRAM_COLORS env var. | dark | String
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json
b/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json
index 0553d5478fa5..9e3f577faf42 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json
+++
b/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json
@@ -2,7 +2,7 @@
"commands": [
{ "name": "bind", "fullName": "bind", "description": "DEPRECATED: Bind
source and sink Kamelets as a new Camel integration", "deprecated": true,
"sourceClass": "org.apache.camel.dsl.jbang.core.commands.bind.Bind", "options":
[ { "names": "--error-handler", "description": "Add error handler
(none|log|sink:<endpoint>). Sink endpoints are expected in the format
[[apigroup\/]version:]kind:[namespace\/]name, plain Camel URIs or Kamelet
name.", "javaType": "java.lang.String", "type": "stri [...]
{ "name": "catalog", "fullName": "catalog", "description": "List artifacts
from Camel Catalog", "sourceClass":
"org.apache.camel.dsl.jbang.core.commands.catalog.CatalogCommand", "options": [
{ "names": "-h,--help", "description": "Display the help and sub-commands",
"javaType": "boolean", "type": "boolean" } ], "subcommands": [ { "name":
"component", "fullName": "catalog component", "description": "List components
from the Camel Catalog", "sourceClass": "org.apache.camel.dsl.jbang.co [...]
- { "name": "cmd", "fullName": "cmd", "description": "Performs commands in
the running Camel integrations, such as start\/stop route, or change logging
levels.", "sourceClass":
"org.apache.camel.dsl.jbang.core.commands.action.CamelAction", "options": [ {
"names": "-h,--help", "description": "Display the help and sub-commands",
"javaType": "boolean", "type": "boolean" } ], "subcommands": [ { "name":
"browse", "fullName": "cmd browse", "description": "Browse pending messages on
endpoints [...]
+ { "name": "cmd", "fullName": "cmd", "description": "Performs commands in
the running Camel integrations, such as start\/stop route, or change logging
levels.", "sourceClass":
"org.apache.camel.dsl.jbang.core.commands.action.CamelAction", "options": [ {
"names": "-h,--help", "description": "Display the help and sub-commands",
"javaType": "boolean", "type": "boolean" } ], "subcommands": [ { "name":
"browse", "fullName": "cmd browse", "description": "Browse pending messages on
endpoints [...]
{ "name": "completion", "fullName": "completion", "description": "Generate
completion script for bash\/zsh", "sourceClass":
"org.apache.camel.dsl.jbang.core.commands.Complete", "options": [ { "names":
"-h,--help", "description": "Display the help and sub-commands", "javaType":
"boolean", "type": "boolean" } ] },
{ "name": "config", "fullName": "config", "description": "Get and set user
configuration values", "sourceClass":
"org.apache.camel.dsl.jbang.core.commands.config.ConfigCommand", "options": [ {
"names": "-h,--help", "description": "Display the help and sub-commands",
"javaType": "boolean", "type": "boolean" } ], "subcommands": [ { "name": "get",
"fullName": "config get", "description": "Display user configuration value",
"sourceClass": "org.apache.camel.dsl.jbang.core.commands.config. [...]
{ "name": "debug", "fullName": "debug", "description": "Debug local Camel
integration", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Debug",
"options": [ { "names": "--ago", "description": "Use ago instead of yyyy-MM-dd
HH:mm:ss in timestamp.", "javaType": "boolean", "type": "boolean" }, { "names":
"--background", "description": "Run in the background", "defaultValue":
"false", "javaType": "boolean", "type": "boolean" }, { "names":
"--background-wait", "description": "To [...]
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelRouteDiagramAction.java
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelRouteDiagramAction.java
index 225861b01897..c4989bfc8485 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelRouteDiagramAction.java
+++
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelRouteDiagramAction.java
@@ -89,7 +89,7 @@ public class CamelRouteDiagramAction extends
ActionBaseCommand {
defaultValue = "both")
String nodeLabel;
- @CommandLine.Option(names = { "--metric" }, defaultValue = "false",
+ @CommandLine.Option(names = { "--metric" }, defaultValue = "true",
description = "Whether to include live metrics (only
possible for running Camel application)")
boolean metric;
@@ -103,41 +103,6 @@ public class CamelRouteDiagramAction extends
ActionBaseCommand {
super(main);
}
- /**
- * Renders the routes contained in the given source file as a PNG diagram
saved to {@code outputFile}. Convenience
- * entry point for programmatic invocation (e.g. from MCP tools) that
always targets a non-running source file and
- * skips the running-PID lookup.
- *
- * @param sourceFile path to the route source file (YAML, XML,
Java, ...)
- * @param outputFile path to the PNG file to write
- * @param theme color theme spec (e.g. "dark", "light",
"transparent" or custom)
- * @param filter optional route filter (route id or filename
pattern)
- * @param width image width in pixels (0 = auto)
- * @param ignoreLoadingError whether to ignore route loading and
compilation errors
- * @return exit code; 0 on success, non-zero otherwise
- * @throws Exception if the source cannot be read or the diagram
cannot be rendered
- */
- public Integer renderSourceToFile(
- String sourceFile, String outputFile, String theme, String filter,
- int width, boolean ignoreLoadingError,
- int fontSize, int boxWidth, String nodeLabel)
- throws Exception {
- this.name = sourceFile;
- this.output = outputFile;
- if (theme != null && !theme.isBlank()) {
- this.theme = theme;
- }
- this.filter = filter;
- this.width = width;
- this.ignoreLoadingError = ignoreLoadingError;
- this.fontSize = fontSize;
- this.boxWidth = boxWidth;
- if (nodeLabel != null && !nodeLabel.isBlank()) {
- this.nodeLabel = nodeLabel;
- }
- return doCall();
- }
-
@Override
public Integer doCall() throws Exception {
System.setProperty("java.awt.headless", "true");
@@ -196,7 +161,8 @@ public class CamelRouteDiagramAction extends
ActionBaseCommand {
NodeLabelMode labelMode = parseNodeLabelMode(nodeLabel);
RouteDiagramLayoutEngine engine = new
RouteDiagramLayoutEngine(boxWidth, fontSize, labelMode);
RouteDiagramRenderer renderer = new RouteDiagramRenderer(
- engine.getNodeWidth(), fontSize *
RouteDiagramLayoutEngine.SCALE, engine.getNodeTextPadding());
+ engine.getNodeWidth(), fontSize *
RouteDiagramLayoutEngine.SCALE, engine.getNodeTextPadding(),
+ pid > 0 && metric);
if ("text".equals(theme)) {
for (String line : renderer.printTextDiagram(routes,
labelMode)) {
@@ -327,4 +293,43 @@ public class CamelRouteDiagramAction extends
ActionBaseCommand {
}
return NodeLabelMode.CODE;
}
+
+ /**
+ * Used BY MCP tools
+ *
+ * Renders the routes contained in the given source file as a PNG diagram
saved to {@code outputFile}. Convenience
+ * entry point for programmatic invocation (e.g. from MCP tools) that
always targets a non-running source file and
+ * skips the running-PID lookup.
+ *
+ * @param sourceFile path to the route source file (YAML, XML,
Java, ...)
+ * @param outputFile path to the PNG file to write
+ * @param theme color theme spec (e.g. "dark", "light",
"transparent" or custom)
+ * @param filter optional route filter (route id or filename
pattern)
+ * @param width image width in pixels (0 = auto)
+ * @param ignoreLoadingError whether to ignore route loading and
compilation errors
+ * @return exit code; 0 on success, non-zero otherwise
+ * @throws Exception if the source cannot be read or the diagram
cannot be rendered
+ */
+ public Integer renderSourceToFile(
+ String sourceFile, String outputFile, String theme, String filter,
+ int width, boolean ignoreLoadingError,
+ int fontSize, int boxWidth, String nodeLabel)
+ throws Exception {
+ this.name = sourceFile;
+ this.output = outputFile;
+ if (theme != null && !theme.isBlank()) {
+ this.theme = theme;
+ }
+ this.filter = filter;
+ this.width = width;
+ this.ignoreLoadingError = ignoreLoadingError;
+ this.fontSize = fontSize;
+ this.boxWidth = boxWidth;
+ if (nodeLabel != null && !nodeLabel.isBlank()) {
+ this.nodeLabel = nodeLabel;
+ }
+ this.metric = false;
+ return doCall();
+ }
+
}