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: