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

davsclaus pushed a commit to branch CAMEL-23617
in repository https://gitbox.apache.org/repos/asf/camel.git

commit c7a0bdf6fb214f8ca50d69817b8aaa12a17b5a1d
Author: Claus Ibsen <[email protected]>
AuthorDate: Tue May 26 16:33:05 2026 +0200

    CAMEL-23617: Add message-size bundled example and fix Content-Length 
fallback
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
---
 .../main/camel-main-configuration-metadata.json    |   1 +
 .../impl/engine/DefaultMessageSizeStrategy.java    |   6 +-
 .../jbang-commands/camel-jbang-get-endpoint.adoc   |   3 +-
 .../META-INF/camel-jbang-commands-metadata.json    |   2 +-
 .../jbang/core/commands/process/ListEndpoint.java  |   5 +-
 .../examples/camel-jbang-example-catalog.json      |  18 ++++
 .../main/resources/examples/message-size/README.md |  57 ++++++++++++
 .../examples/message-size/message-size.camel.yaml  | 102 +++++++++++++++++++++
 8 files changed, 187 insertions(+), 7 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
index 9e39a3ecdeff..a29587c0c21e 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
@@ -104,6 +104,7 @@
     { "name": "camel.main.mainListeners", "required": false, "description": 
"Sets main listener objects that will be used for MainListener that makes it 
possible to do custom logic during starting and stopping camel-main.", 
"sourceType": "org.apache.camel.main.MainConfigurationProperties", "type": 
"array", "javaType": "java.util.List", "secret": false },
     { "name": "camel.main.mdcLoggingKeysPattern", "required": false, 
"description": "Sets the pattern used for determine which custom MDC keys to 
propagate during message routing when the routing engine continues routing 
asynchronously for the given message. Setting this pattern to will propagate 
all custom keys. Or setting the pattern to foo,bar will propagate any keys 
starting with either foo or bar. Notice that a set of standard Camel MDC keys 
are always propagated which starts with c [...]
     { "name": "camel.main.messageHistory", "required": false, "description": 
"Sets whether message history is enabled or not. Default is false.", 
"sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": 
"boolean", "javaType": "boolean", "defaultValue": false, "secret": false },
+    { "name": "camel.main.messageSizeEnabled", "required": false, 
"description": "Sets whether message size observation is enabled (default is 
false). When enabled, Camel will compute the size of incoming message body and 
headers (in bytes) per route and make this available via JMX MBeans 
(min\/max\/mean body size and headers size).", "sourceType": 
"org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", 
"javaType": "boolean", "defaultValue": false, "secret": false },
     { "name": "camel.main.modeline", "required": false, "description": 
"Whether to support JBang style \/\/DEPS to specify additional dependencies 
when running Camel JBang", "sourceType": 
"org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", 
"javaType": "boolean", "defaultValue": false, "secret": false },
     { "name": "camel.main.name", "required": false, "description": "Sets the 
name of the CamelContext.", "sourceType": 
"org.apache.camel.main.DefaultConfigurationProperties", "type": "string", 
"javaType": "java.lang.String", "secret": false },
     { "name": "camel.main.producerTemplateCacheSize", "required": false, 
"description": "Producer template endpoints cache size.", "sourceType": 
"org.apache.camel.main.DefaultConfigurationProperties", "type": "integer", 
"javaType": "int", "defaultValue": 1000, "secret": false },
diff --git 
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultMessageSizeStrategy.java
 
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultMessageSizeStrategy.java
index 4d2240960ade..2d2a94adf21f 100644
--- 
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultMessageSizeStrategy.java
+++ 
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultMessageSizeStrategy.java
@@ -62,9 +62,6 @@ public class DefaultMessageSizeStrategy extends 
ServiceSupport implements CamelC
     @Override
     public long computeBodySize(Message message) {
         Object body = message.getBody();
-        if (body == null) {
-            return 0;
-        }
         if (body instanceof byte[] bytes) {
             return bytes.length;
         }
@@ -94,6 +91,9 @@ public class DefaultMessageSizeStrategy extends 
ServiceSupport implements CamelC
         if (cl != null && cl >= 0) {
             return cl;
         }
+        if (body == null) {
+            return 0;
+        }
         return -1;
     }
 
diff --git 
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-get-endpoint.adoc
 
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-get-endpoint.adoc
index f8d3f58e1600..5bf9bb5be3d0 100644
--- 
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-get-endpoint.adoc
+++ 
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-get-endpoint.adoc
@@ -25,7 +25,8 @@ camel get endpoint [options]
 | `--json` | Output in JSON Format |  | boolean
 | `--limit` | Filter endpoints by limiting to the given number of rows |  | int
 | `--short-uri` | List endpoint URI without query parameters (short) |  | 
boolean
-| `--sort` | Sort by pid, name, age or total | pid | String
+| `--sort` | Sort by pid, name, age, total, or size | pid | String
+| `--verbose` | Show additional size statistics (min/max body and headers) |  
| boolean
 | `--watch` | Execute periodically and showing output fullscreen |  | boolean
 | `--wide-uri` | List endpoint URI in full details |  | boolean
 | `-h,--help` | Display the help and sub-commands |  | boolean
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 fdc22c91dc6c..194ec512ccdc 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
@@ -14,7 +14,7 @@
     { "name": "eval", "fullName": "eval", "description": "Evaluate Camel 
expressions and scripts", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.EvalCommand", "options": [ { "names": 
"-h,--help", "description": "Display the help and sub-commands", "javaType": 
"boolean", "type": "boolean" } ], "subcommands": [ { "name": "expression", 
"fullName": "eval expression", "description": "Evaluates Camel expression", 
"sourceClass": "org.apache.camel.dsl.jbang.core.commands.action.EvalEx [...]
     { "name": "explain", "fullName": "explain", "description": "Explain what a 
Camel route does using AI\/LLM", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.Explain", "options": [ { "names": 
"--api-key", "description": "API key for authentication. Also reads 
ANTHROPIC_API_KEY, OPENAI_API_KEY, or LLM_API_KEY env vars", "javaType": 
"java.lang.String", "type": "string" }, { "names": "--api-type", "description": 
"API type: 'ollama', 'openai' (OpenAI-compatible), or 'anthropic' (A [...]
     { "name": "export", "fullName": "export", "description": "Export to other 
runtimes (Camel Main, Spring Boot, or Quarkus)", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.Export", "options": [ { "names": 
"--build-property", "description": "Maven build properties, ex. 
--build-property=prop1=foo", "javaType": "java.util.List", "type": "array" }, { 
"names": "--camel-spring-boot-version", "description": "Camel version to use 
with Spring Boot", "javaType": "java.lang.String", "ty [...]
-    { "name": "get", "fullName": "get", "description": "Get status of Camel 
integrations", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.process.CamelStatus", "options": [ { 
"names": "--watch", "description": "Execute periodically and showing output 
fullscreen", "javaType": "boolean", "type": "boolean" }, { "names": 
"-h,--help", "description": "Display the help and sub-commands", "javaType": 
"boolean", "type": "boolean" } ], "subcommands": [ { "name": "bean", 
"fullName": "get  [...]
+    { "name": "get", "fullName": "get", "description": "Get status of Camel 
integrations", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.process.CamelStatus", "options": [ { 
"names": "--watch", "description": "Execute periodically and showing output 
fullscreen", "javaType": "boolean", "type": "boolean" }, { "names": 
"-h,--help", "description": "Display the help and sub-commands", "javaType": 
"boolean", "type": "boolean" } ], "subcommands": [ { "name": "bean", 
"fullName": "get  [...]
     { "name": "harden", "fullName": "harden", "description": "Suggest security 
hardening for Camel routes using AI\/LLM", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.Harden", "options": [ { "names": 
"--api-key", "description": "API key for authentication. Also reads 
OPENAI_API_KEY or LLM_API_KEY env vars", "javaType": "java.lang.String", 
"type": "string" }, { "names": "--api-type", "description": "API type: 'ollama' 
or 'openai' (OpenAI-compatible)", "defaultValue": "ollama", [...]
     { "name": "hawtio", "fullName": "hawtio", "description": "Launch Hawtio 
web console", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.process.Hawtio", "options": [ { 
"names": "--host", "description": "Hostname to bind the Hawtio web console to", 
"defaultValue": "127.0.0.1", "javaType": "java.lang.String", "type": "string" 
}, { "names": "--openUrl", "description": "To automatic open Hawtio web console 
in the web browser", "defaultValue": "true", "javaType": "boolean", "type": 
[...]
     { "name": "infra", "fullName": "infra", "description": "List and Run 
external services for testing and prototyping", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.infra.InfraCommand", "options": [ { 
"names": "--json", "description": "Output in JSON Format", "javaType": 
"boolean", "type": "boolean" }, { "names": "-h,--help", "description": "Display 
the help and sub-commands", "javaType": "boolean", "type": "boolean" } ], 
"subcommands": [ { "name": "get", "fullName": "infra  [...]
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListEndpoint.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListEndpoint.java
index 85449071e587..5059593809af 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListEndpoint.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListEndpoint.java
@@ -20,6 +20,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Locale;
 import java.util.stream.Collectors;
 
 import com.github.freva.asciitable.AsciiTable;
@@ -262,9 +263,9 @@ public class ListEndpoint extends ProcessWatchCommand {
         if (size < 1024) {
             return size + " B";
         } else if (size < 1024 * 1024) {
-            return String.format("%.1f KB", size / 1024.0);
+            return String.format(Locale.US, "%.1f KB", size / 1024.0);
         } else {
-            return String.format("%.1f MB", size / (1024.0 * 1024.0));
+            return String.format(Locale.US, "%.1f MB", size / (1024.0 * 
1024.0));
         }
     }
 
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/camel-jbang-example-catalog.json
 
b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/camel-jbang-example-catalog.json
index 4e42f22e97d8..fca58c3f0788 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/camel-jbang-example-catalog.json
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/camel-jbang-example-catalog.json
@@ -226,6 +226,24 @@
             "rest-api.camel.yaml"
         ]
     },
+    {
+        "name": "message-size",
+        "title": "Message Size",
+        "description": "Track message body and header sizes per endpoint",
+        "level": "beginner",
+        "tags": [
+            "observability",
+            "monitoring",
+            "seda"
+        ],
+        "bundled": true,
+        "requiresDocker": false,
+        "hasCitrusTests": false,
+        "files": [
+            "README.md",
+            "message-size.camel.yaml"
+        ]
+    },
     {
         "name": "mqtt",
         "title": "MQTT",
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/message-size/README.md
 
b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/message-size/README.md
new file mode 100644
index 000000000000..5332bdf435c9
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/message-size/README.md
@@ -0,0 +1,57 @@
+## Message Size
+
+This example demonstrates Camel's message size tracking feature, which captures
+body and header sizes per endpoint for both incoming (IN) and outgoing (OUT) 
directions.
+
+Three timer-driven producers simulate messages of different sizes (small, 
medium, large)
+using the `Content-Length` header and send them to separate SEDA endpoints.
+The size statistics (min, max, mean) are tracked per endpoint and can be 
viewed via the CLI.
+
+### How to run
+
+```sh
+$ camel run *
+```
+
+### Viewing message size statistics
+
+While the integration is running, open another terminal and use the `camel` CLI
+to view endpoint statistics including message sizes:
+
+```sh
+$ camel get endpoint
+```
+
+To see detailed min/max statistics:
+
+```sh
+$ camel get endpoint --verbose
+```
+
+To sort endpoints by body size (largest first):
+
+```sh
+$ camel get endpoint --sort -size
+```
+
+### How it works
+
+Message size tracking is automatically enabled when running with `camel run`
+which uses the dev profile. This sets:
+
+- `camel.main.messageSizeEnabled = true`
+- `camel.main.jmxManagementStatisticsLevel = Extended`
+
+Sizes are tracked per endpoint in the runtime endpoint registry. For incoming 
messages,
+the body and headers sizes are also available as exchange properties
+(`CamelMessageBodySize` and `CamelMessageHeadersSize`) during routing.
+
+### Help and contributions
+
+If you hit any problem using Camel or have some feedback, then please
+[let us know](https://camel.apache.org/community/support/).
+
+We also love contributors, so
+[get involved](https://camel.apache.org/community/contributing/) :-)
+
+The Camel riders!
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/message-size/message-size.camel.yaml
 
b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/message-size/message-size.camel.yaml
new file mode 100644
index 000000000000..9b2e0361c3a4
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/resources/examples/message-size/message-size.camel.yaml
@@ -0,0 +1,102 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Producers: simulate different payload sizes using Content-Length header
+- route:
+    id: small-producer
+    from:
+      uri: timer:small
+      parameters:
+        period: 2000
+      steps:
+        - setHeader:
+            name: Content-Length
+            simple: "${random(100,1023)}"
+        - setHeader:
+            name: source
+            simple: small-producer
+        - to:
+            uri: seda:small
+
+- route:
+    id: medium-producer
+    from:
+      uri: timer:medium
+      parameters:
+        period: 3000
+      steps:
+        - setHeader:
+            name: Content-Length
+            simple: "${random(8192,18432)}"
+        - setHeader:
+            name: source
+            simple: medium-producer
+        - setHeader:
+            name: tracking-id
+            simple: "TRK-${random(10000,99999)}"
+        - to:
+            uri: seda:medium
+
+- route:
+    id: large-producer
+    from:
+      uri: timer:large
+      parameters:
+        period: 5000
+      steps:
+        - setHeader:
+            name: Content-Length
+            simple: "${random(10485760,20971520)}"
+        - setHeader:
+            name: source
+            simple: large-producer
+        - setHeader:
+            name: tracking-id
+            simple: "TRK-${random(10000,99999)}"
+        - setHeader:
+            name: batch-id
+            simple: "BATCH-${random(100,999)}"
+        - setHeader:
+            name: priority
+            simple: "${random(1,5)}"
+        - to:
+            uri: seda:large
+
+# Consumers: process messages from each seda endpoint
+- route:
+    id: process-small
+    from:
+      uri: seda:small
+      steps:
+        - log:
+            message: "Small: Content-Length=${header.Content-Length}"
+
+- route:
+    id: process-medium
+    from:
+      uri: seda:medium
+      steps:
+        - log:
+            message: "Medium: Content-Length=${header.Content-Length}"
+
+- route:
+    id: process-large
+    from:
+      uri: seda:large
+      steps:
+        - log:
+            message: "Large: Content-Length=${header.Content-Length}"

Reply via email to