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

fmariani pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-spring-boot.git


The following commit(s) were added to refs/heads/main by this push:
     new 1bb2b737a4c Add undertow micrometer metrics
1bb2b737a4c is described below

commit 1bb2b737a4cc1301945a1084e5a5cbb2e4744690
Author: Croway <[email protected]>
AuthorDate: Wed Sep 3 12:50:58 2025 +0200

    Add undertow micrometer metrics
---
 .../camel-platform-http-starter/pom.xml            |  18 ++
 .../metrics/undertow/UndertowComponents.java       |  25 ++
 .../actuate/metrics/undertow/UndertowMetrics.java  | 338 +++++++++++++++++++++
 .../undertow/UndertowMetricsAutoConfiguration.java |  47 +++
 .../metrics/undertow/UndertowMetricsBinder.java    |  86 ++++++
 ...rk.boot.autoconfigure.AutoConfiguration.imports |   3 +-
 .../src/test/resources/application.properties      |   2 +
 .../src/main/docs/spring-boot.adoc                 |  51 ++++
 8 files changed, 569 insertions(+), 1 deletion(-)

diff --git a/components-starter/camel-platform-http-starter/pom.xml 
b/components-starter/camel-platform-http-starter/pom.xml
index aed93ec90f6..e8a2ff8617b 100644
--- a/components-starter/camel-platform-http-starter/pom.xml
+++ b/components-starter/camel-platform-http-starter/pom.xml
@@ -49,6 +49,24 @@
       <artifactId>spring-boot-starter-web</artifactId>
       <version>${spring-boot-version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-undertow</artifactId>
+      <version>${spring-boot-version}</version>
+      <optional>true</optional>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-actuator</artifactId>
+      <version>${spring-boot-version}</version>
+      <optional>true</optional>
+    </dependency>
+    <dependency>
+      <groupId>io.micrometer</groupId>
+      <artifactId>micrometer-core</artifactId>
+      <version>${micrometer-version}</version>
+      <optional>true</optional>
+    </dependency>
     <dependency>
       <groupId>io.rest-assured</groupId>
       <artifactId>rest-assured</artifactId>
diff --git 
a/components-starter/camel-platform-http-starter/src/main/java/org/apache/camel/component/platform/http/springboot/actuate/metrics/undertow/UndertowComponents.java
 
b/components-starter/camel-platform-http-starter/src/main/java/org/apache/camel/component/platform/http/springboot/actuate/metrics/undertow/UndertowComponents.java
new file mode 100644
index 00000000000..0aab75a8846
--- /dev/null
+++ 
b/components-starter/camel-platform-http-starter/src/main/java/org/apache/camel/component/platform/http/springboot/actuate/metrics/undertow/UndertowComponents.java
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+package 
org.apache.camel.component.platform.http.springboot.actuate.metrics.undertow;
+
+import io.undertow.Undertow;
+import io.undertow.server.session.SessionManager;
+import io.undertow.servlet.api.Deployment;
+import org.xnio.XnioWorker;
+
+public record UndertowComponents(XnioWorker xnioWorker, SessionManager 
sessionManager,
+                                 Deployment deployment, Undertow undertow) { }
diff --git 
a/components-starter/camel-platform-http-starter/src/main/java/org/apache/camel/component/platform/http/springboot/actuate/metrics/undertow/UndertowMetrics.java
 
b/components-starter/camel-platform-http-starter/src/main/java/org/apache/camel/component/platform/http/springboot/actuate/metrics/undertow/UndertowMetrics.java
new file mode 100644
index 00000000000..1b64570dff6
--- /dev/null
+++ 
b/components-starter/camel-platform-http-starter/src/main/java/org/apache/camel/component/platform/http/springboot/actuate/metrics/undertow/UndertowMetrics.java
@@ -0,0 +1,338 @@
+/*
+ * 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.
+ */
+package 
org.apache.camel.component.platform.http.springboot.actuate.metrics.undertow;
+
+import io.micrometer.core.instrument.FunctionCounter;
+import io.micrometer.core.instrument.Gauge;
+import io.micrometer.core.instrument.MeterRegistry;
+import io.micrometer.core.instrument.Tag;
+import io.micrometer.core.instrument.Tags;
+import io.micrometer.core.instrument.binder.BaseUnits;
+import io.micrometer.core.instrument.binder.MeterBinder;
+import io.undertow.server.session.SessionManager;
+import io.undertow.servlet.api.Deployment;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xnio.XnioWorker;
+
+import javax.management.AttributeNotFoundException;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanException;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+import java.lang.management.ManagementFactory;
+import java.util.function.Supplier;
+
+/**
+ * {@link MeterBinder} for Undertow.
+ * <p>
+ * This binder provides metrics for XNIO worker threads and session management.
+ *
+ */
+public class UndertowMetrics implements MeterBinder, AutoCloseable {
+    private static final Logger LOG = 
LoggerFactory.getLogger(UndertowMetrics.class);
+
+    private final XnioWorker xnioWorker;
+    private final SessionManager sessionManager;
+    private final Deployment deployment;
+    private final Iterable<Tag> tags;
+    private final MBeanServer mBeanServer;
+
+    public UndertowMetrics(XnioWorker xnioWorker,
+                           SessionManager sessionManager,
+                           Iterable<Tag> tags) {
+        this(xnioWorker, sessionManager, null, tags, 
ManagementFactory.getPlatformMBeanServer());
+    }
+
+    public UndertowMetrics(XnioWorker xnioWorker,
+                           SessionManager sessionManager,
+                           Deployment deployment,
+                           Iterable<Tag> tags) {
+        this(xnioWorker, sessionManager, deployment, tags, 
ManagementFactory.getPlatformMBeanServer());
+    }
+
+    public UndertowMetrics(XnioWorker xnioWorker,
+                           SessionManager sessionManager,
+                           Deployment deployment,
+                           Iterable<Tag> tags,
+                           MBeanServer mBeanServer) {
+        this.xnioWorker = xnioWorker;
+        this.sessionManager = sessionManager;
+        this.deployment = deployment;
+        this.tags = tags;
+        this.mBeanServer = mBeanServer;
+    }
+
+    public static void monitor(MeterRegistry registry,
+                               XnioWorker xnioWorker,
+                               SessionManager sessionManager,
+                               String... tags) {
+        monitor(registry, xnioWorker, sessionManager, Tags.of(tags));
+    }
+
+    public static void monitor(MeterRegistry registry,
+                               XnioWorker xnioWorker,
+                               SessionManager sessionManager,
+                               Iterable<Tag> tags) {
+        new UndertowMetrics(xnioWorker, sessionManager, tags).bindTo(registry);
+    }
+
+    public static void monitor(MeterRegistry registry,
+                               XnioWorker xnioWorker,
+                               SessionManager sessionManager,
+                               Deployment deployment,
+                               Iterable<Tag> tags) {
+        new UndertowMetrics(xnioWorker, sessionManager, deployment, 
tags).bindTo(registry);
+    }
+
+    @Override
+    public void bindTo(MeterRegistry registry) {
+        registerWorkerThreadMetrics(registry);
+        registerSessionMetrics(registry);
+        registerJmxMetrics(registry);
+    }
+
+    private void registerWorkerThreadMetrics(MeterRegistry registry) {
+        if (xnioWorker == null) {
+            return;
+        }
+
+        // Core worker pool size
+        Gauge.builder("undertow.threads.worker.core", xnioWorker, 
this::getCoreWorkerPoolSize)
+                .tags(tags)
+                .baseUnit(BaseUnits.THREADS)
+                .description("Core worker thread pool size")
+                .register(registry);
+
+        // Maximum worker pool size
+        Gauge.builder("undertow.threads.worker.max", xnioWorker, 
this::getMaxWorkerPoolSize)
+                .tags(tags)
+                .baseUnit(BaseUnits.THREADS)
+                .description("Maximum worker thread pool size")
+                .register(registry);
+
+        // Current worker thread count
+        Gauge.builder("undertow.threads.worker.current", xnioWorker, 
this::getCurrentWorkerThreadCount)
+                .tags(tags)
+                .baseUnit(BaseUnits.THREADS)
+                .description("Current worker thread count")
+                .register(registry);
+
+        // Busy worker thread count
+        Gauge.builder("undertow.threads.worker.busy", xnioWorker, 
this::getBusyWorkerThreadCount)
+                .tags(tags)
+                .baseUnit(BaseUnits.THREADS)
+                .description("Busy worker thread count")
+                .register(registry);
+
+        // Worker thread utilization percentage
+        Gauge.builder("undertow.threads.worker.utilization", xnioWorker, 
this::getWorkerThreadUtilization)
+                .tags(tags)
+                .baseUnit(BaseUnits.PERCENT)
+                .description("Worker thread utilization percentage")
+                .register(registry);
+
+        // Worker queue size
+        Gauge.builder("undertow.threads.worker.queue.size", xnioWorker, 
this::getWorkerQueueSize)
+                .tags(tags)
+                .description("Worker thread queue size")
+                .register(registry);
+
+        // IO thread count
+        Gauge.builder("undertow.threads.io", xnioWorker, 
XnioWorker::getIoThreadCount)
+                .tags(tags)
+                .baseUnit(BaseUnits.THREADS)
+                .description("IO thread count")
+                .register(registry);
+    }
+
+    private void registerSessionMetrics(MeterRegistry registry) {
+        if (sessionManager == null) {
+            return;
+        }
+
+        // Active sessions
+        Gauge.builder("undertow.sessions.active.current", sessionManager, 
this::getActiveSessions)
+                .tags(tags)
+                .baseUnit(BaseUnits.SESSIONS)
+                .description("Current active sessions")
+                .register(registry);
+
+        // Maximum sessions (if available)
+        Gauge.builder("undertow.sessions.active.max", sessionManager, 
this::getMaxSessions)
+                .tags(tags)
+                .baseUnit(BaseUnits.SESSIONS)
+                .description("Maximum sessions allowed")
+                .register(registry);
+
+        // Session creation rate (if statistics are available)
+        FunctionCounter.builder("undertow.sessions.created", sessionManager, 
this::getCreatedSessions)
+                .tags(tags)
+                .baseUnit(BaseUnits.SESSIONS)
+                .description("Total sessions created")
+                .register(registry);
+
+        // Expired sessions
+        FunctionCounter.builder("undertow.sessions.expired", sessionManager, 
this::getExpiredSessions)
+                .tags(tags)
+                .baseUnit(BaseUnits.SESSIONS)
+                .description("Total sessions expired")
+                .register(registry);
+    }
+
+    private void registerJmxMetrics(MeterRegistry registry) {
+        // Register any available JMX-based metrics for Undertow
+        // This is a placeholder for when JMX beans are available
+        registerJmxMetricsIfAvailable(":type=thread-pool,name=*", registry);
+    }
+
+    private void registerJmxMetricsIfAvailable(String objectNamePattern, 
MeterRegistry registry) {
+        try {
+            ObjectName pattern = new ObjectName("jboss.threads" + 
objectNamePattern);
+            var objectNames = mBeanServer.queryNames(pattern, null);
+
+            for (ObjectName objectName : objectNames) {
+                // Register JMX-based thread pool metrics if available
+                registerJmxThreadPoolMetrics(objectName, registry);
+            }
+        } catch (Exception e) {
+            // JMX beans not available, skip
+        }
+    }
+
+    private void registerJmxThreadPoolMetrics(ObjectName objectName, 
MeterRegistry registry) {
+        Iterable<Tag> allTags = Tags.concat(tags, Tags.of("name", 
getNameFromObjectName(objectName)));
+
+        Gauge.builder("undertow.threads.jmx.active", mBeanServer,
+                        s -> safeDouble(() -> {
+                            try {
+                                return s.getAttribute(objectName, 
"ActiveCount");
+                            } catch (Exception e) {
+                                throw new RuntimeException(e);
+                            }
+                        }))
+                .tags(allTags)
+                .baseUnit(BaseUnits.THREADS)
+                .description("Active threads from JMX")
+                .register(registry);
+
+        Gauge.builder("undertow.threads.jmx.pool.size", mBeanServer,
+                        s -> safeDouble(() -> {
+                            try {
+                                return s.getAttribute(objectName, "PoolSize");
+                            } catch (Exception e) {
+                                throw new RuntimeException(e);
+                            }
+                        }))
+                .tags(allTags)
+                .baseUnit(BaseUnits.THREADS)
+                .description("Thread pool size from JMX")
+                .register(registry);
+    }
+
+    private double getCoreWorkerPoolSize(XnioWorker worker) {
+        return safeDouble(() -> 
this.xnioWorker.getMXBean().getCoreWorkerPoolSize());
+    }
+
+    private double getMaxWorkerPoolSize(XnioWorker worker) {
+        return safeDouble(() -> 
this.xnioWorker.getMXBean().getMaxWorkerPoolSize());
+    }
+
+    private double getCurrentWorkerThreadCount(XnioWorker worker) {
+        return safeDouble(() -> worker.getMXBean().getWorkerPoolSize());
+    }
+
+    private double getBusyWorkerThreadCount(XnioWorker worker) {
+        return safeDouble(() -> worker.getMXBean().getBusyWorkerThreadCount());
+    }
+
+    private double getWorkerThreadUtilization(XnioWorker worker) {
+        double current = getCurrentWorkerThreadCount(worker);
+        double total = getCoreWorkerPoolSize(worker);
+        if (total > 0 && !Double.isNaN(current) && !Double.isNaN(total)) {
+            return (current / total) * 100.0;
+        }
+        return Double.NaN;
+    }
+
+    private double getWorkerQueueSize(XnioWorker worker) {
+        return safeDouble(() -> worker.getMXBean().getWorkerQueueSize());
+    }
+
+    // Session metrics
+    private double getActiveSessions(SessionManager manager) {
+        if (manager.getStatistics() != null) {
+            return safeDouble(() -> 
manager.getStatistics().getActiveSessionCount());
+        }
+        if (deployment != null && deployment.getSessionManager() != null) {
+            return safeDouble(() -> 
deployment.getSessionManager().getActiveSessions().size());
+        }
+        return Double.NaN;
+    }
+
+    private double getMaxSessions(SessionManager manager) {
+        if (manager.getStatistics() != null) {
+            return safeDouble(() -> 
manager.getStatistics().getMaxActiveSessions());
+        }
+        return Double.NaN;
+    }
+
+    private double getCreatedSessions(SessionManager manager) {
+        if (manager.getStatistics() != null) {
+            return safeDouble(() -> 
manager.getStatistics().getCreatedSessionCount());
+        }
+        return Double.NaN;
+    }
+
+    private double getExpiredSessions(SessionManager manager) {
+        if (manager.getStatistics() != null) {
+            return safeDouble(() -> 
manager.getStatistics().getExpiredSessionCount());
+        }
+        return Double.NaN;
+    }
+
+    // Utility methods
+    private double safeDouble(Supplier<Object> supplier) {
+        try {
+            Object result = supplier.get();
+            if (result == null) {
+                return Double.NaN;
+            }
+            if (result instanceof Number) {
+                return ((Number) result).doubleValue();
+            }
+            return Double.parseDouble(result.toString());
+        } catch (Exception e) {
+            LOG.trace(e.getMessage(), e);
+            return Double.NaN;
+        }
+    }
+
+    private String getNameFromObjectName(ObjectName objectName) {
+        String name = objectName.getKeyProperty("name");
+        return name != null ? name.replace("\"", "") : "unknown";
+    }
+
+
+    @Override
+    public void close() {
+        // Cleanup any resources if needed
+        // Currently no resources to clean up, but this provides the interface
+        // for future enhancements
+    }
+}
diff --git 
a/components-starter/camel-platform-http-starter/src/main/java/org/apache/camel/component/platform/http/springboot/actuate/metrics/undertow/UndertowMetricsAutoConfiguration.java
 
b/components-starter/camel-platform-http-starter/src/main/java/org/apache/camel/component/platform/http/springboot/actuate/metrics/undertow/UndertowMetricsAutoConfiguration.java
new file mode 100644
index 00000000000..f0eb998574f
--- /dev/null
+++ 
b/components-starter/camel-platform-http-starter/src/main/java/org/apache/camel/component/platform/http/springboot/actuate/metrics/undertow/UndertowMetricsAutoConfiguration.java
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+package 
org.apache.camel.component.platform.http.springboot.actuate.metrics.undertow;
+
+import io.micrometer.core.instrument.MeterRegistry;
+import io.micrometer.core.instrument.binder.MeterBinder;
+import io.undertow.Undertow;
+import 
org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import 
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import 
org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
+import org.springframework.context.annotation.Bean;
+
+/**
+ * {@link EnableAutoConfiguration Auto-configuration} for {@link 
UndertowMetrics}.
+ *
+ */
+@AutoConfiguration(after = CompositeMeterRegistryAutoConfiguration.class)
+@ConditionalOnWebApplication
+@ConditionalOnClass({ Undertow.class, MeterBinder.class })
+public class UndertowMetricsAutoConfiguration {
+
+    @Bean
+    @ConditionalOnBean(MeterRegistry.class)
+    @ConditionalOnMissingBean({ UndertowMetrics.class, 
UndertowMetricsBinder.class })
+    public UndertowMetricsBinder undertowMetricsBinder(MeterRegistry 
meterRegistry) {
+        return new UndertowMetricsBinder(meterRegistry);
+    }
+
+}
diff --git 
a/components-starter/camel-platform-http-starter/src/main/java/org/apache/camel/component/platform/http/springboot/actuate/metrics/undertow/UndertowMetricsBinder.java
 
b/components-starter/camel-platform-http-starter/src/main/java/org/apache/camel/component/platform/http/springboot/actuate/metrics/undertow/UndertowMetricsBinder.java
new file mode 100644
index 00000000000..fe1a23c1ecd
--- /dev/null
+++ 
b/components-starter/camel-platform-http-starter/src/main/java/org/apache/camel/component/platform/http/springboot/actuate/metrics/undertow/UndertowMetricsBinder.java
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+package 
org.apache.camel.component.platform.http.springboot.actuate.metrics.undertow;
+
+import io.micrometer.core.instrument.MeterRegistry;
+import io.micrometer.core.instrument.Tag;
+import io.undertow.Undertow;
+import io.undertow.servlet.api.DeploymentManager;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.boot.context.event.ApplicationStartedEvent;
+import org.springframework.boot.web.context.WebServerApplicationContext;
+import org.springframework.boot.web.embedded.undertow.UndertowServletWebServer;
+import org.springframework.boot.web.server.WebServer;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationListener;
+import org.xnio.XnioWorker;
+
+import java.util.Collections;
+
+public class UndertowMetricsBinder implements 
ApplicationListener<ApplicationStartedEvent>, DisposableBean {
+
+    private final MeterRegistry meterRegistry;
+    private final Iterable<Tag> tags;
+    private volatile UndertowMetrics undertowMetrics;
+
+    public UndertowMetricsBinder(MeterRegistry meterRegistry) {
+        this(meterRegistry, Collections.emptyList());
+    }
+
+    public UndertowMetricsBinder(MeterRegistry meterRegistry, Iterable<Tag> 
tags) {
+        this.meterRegistry = meterRegistry;
+        this.tags = tags;
+    }
+
+    @Override
+    public void destroy() {
+        if (this.undertowMetrics != null) {
+            this.undertowMetrics.close();
+        }
+    }
+
+    @Override
+    public void onApplicationEvent(ApplicationStartedEvent event) {
+        ApplicationContext applicationContext = event.getApplicationContext();
+        UndertowComponents undertowComponents = 
findUndertowComponents(applicationContext);
+        if (undertowComponents != null) {
+            this.undertowMetrics = new 
UndertowMetrics(undertowComponents.xnioWorker(), 
undertowComponents.sessionManager(),
+                    undertowComponents.deployment(), tags);
+            this.undertowMetrics.bindTo(this.meterRegistry);
+        }
+    }
+
+    private UndertowComponents findUndertowComponents(ApplicationContext 
applicationContext) {
+        if (applicationContext instanceof WebServerApplicationContext 
webServerApplicationContext) {
+            WebServer webServer = webServerApplicationContext.getWebServer();
+            if (webServer instanceof UndertowServletWebServer 
undertowServletWebServer) {
+                Undertow undertow = undertowServletWebServer.getUndertow();
+                XnioWorker xnioWorker = 
undertowServletWebServer.getUndertow().getWorker();
+                DeploymentManager deploymentManager = 
undertowServletWebServer.getDeploymentManager();
+
+                return new UndertowComponents(
+                        xnioWorker,
+                        deploymentManager.getDeployment().getSessionManager(),
+                        deploymentManager.getDeployment(),
+                        undertow
+                );
+            }
+        }
+        return null;
+    }
+
+}
diff --git 
a/components-starter/camel-platform-http-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
 
b/components-starter/camel-platform-http-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
index f8179d9a1b7..84a0a5df88d 100644
--- 
a/components-starter/camel-platform-http-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
+++ 
b/components-starter/camel-platform-http-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -18,4 +18,5 @@
 
org.apache.camel.component.platform.http.springboot.PlatformHttpComponentConverter
 
org.apache.camel.component.platform.http.springboot.PlatformHttpComponentAutoConfiguration
 
org.apache.camel.component.platform.http.springboot.SpringBootPlatformHttpAutoConfiguration
-org.apache.camel.component.platform.http.springboot.SpringBootPlatformWebMvcConfiguration
\ No newline at end of file
+org.apache.camel.component.platform.http.springboot.SpringBootPlatformWebMvcConfiguration
+org.apache.camel.component.platform.http.springboot.actuate.metrics.undertow.UndertowMetricsAutoConfiguration
\ No newline at end of file
diff --git 
a/components-starter/camel-platform-http-starter/src/test/resources/application.properties
 
b/components-starter/camel-platform-http-starter/src/test/resources/application.properties
index f3183eb5542..c7b1a60dc11 100644
--- 
a/components-starter/camel-platform-http-starter/src/test/resources/application.properties
+++ 
b/components-starter/camel-platform-http-starter/src/test/resources/application.properties
@@ -18,3 +18,5 @@
 #logging.level.org.springframework.web=TRACE
 #logging.level.org.springframework.boot.web=TRACE
 #spring.mvc.log-request-details=true
+
+spring.autoconfigure.exclude=org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration
\ No newline at end of file
diff --git a/core/camel-spring-boot/src/main/docs/spring-boot.adoc 
b/core/camel-spring-boot/src/main/docs/spring-boot.adoc
index ad7e02f49cd..675e087ae04 100644
--- a/core/camel-spring-boot/src/main/docs/spring-boot.adoc
+++ b/core/camel-spring-boot/src/main/docs/spring-boot.adoc
@@ -496,6 +496,57 @@ public class MyRoute extends RouteBuilder {
 }
 ----
 
+===== Undertow Metrics
+
+When using the Platform HTTP component with Undertow as the underlying web 
server, comprehensive metrics are automatically available through Spring Boot 
Actuator. To enable Undertow metrics:
+
+1. Exclude Tomcat from Spring Boot Web starter in your `pom.xml`:
++
+[source,xml]
+----
+<dependency>
+    <groupId>org.springframework.boot</groupId>
+    <artifactId>spring-boot-starter-web</artifactId>
+    <exclusions>
+        <exclusion>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-tomcat</artifactId>
+        </exclusion>
+    </exclusions>
+</dependency>
+----
+
+2. Add Spring Boot Undertow starter:
++
+[source,xml]
+----
+<dependency>
+    <groupId>org.springframework.boot</groupId>
+    <artifactId>spring-boot-starter-undertow</artifactId>
+</dependency>
+----
+
+3. Include Spring Boot Actuator:
++
+[source,xml]
+----
+<dependency>
+    <groupId>org.springframework.boot</groupId>
+    <artifactId>spring-boot-starter-actuator</artifactId>
+</dependency>
+----
+
+4. Expose actuator metrics and enable Undertow session statistics
++
+[source,properties]
+----
+server.undertow.options.server.ENABLE_STATISTICS=true
+management.endpoints.web.exposure.include=metrics,health,info
+----
+
+With this configuration, Undertow-specific metrics will be automatically 
exposed under `/actuator/metrics`, providing detailed insights into HTTP server 
including: session management, connection pools and thread usage
+These metrics help monitor the health and performance of your Platform HTTP 
endpoints running on Undertow.
+
 ==== JMS and AMQP Components
 
 JMS and AMQP components benefit from virtual threads through the global 
virtual thread configuration. When `spring.threads.virtual.enabled=true` is 
set, these components will use virtual threads for message processing through 
the standard Spring Boot virtual thread integration:

Reply via email to