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 a63b4c253c9 CAMEL-22930: Fix camel-observation-starter broken in 4.17.0
a63b4c253c9 is described below
commit a63b4c253c9f80e5cf3aba50140273f32c04c35a
Author: Croway <[email protected]>
AuthorDate: Mon Feb 2 13:39:32 2026 +0100
CAMEL-22930: Fix camel-observation-starter broken in 4.17.0
---
.../camel-observation-starter/pom.xml | 28 ++++
.../starter/ObservationAutoConfiguration.java | 4 +-
.../starter/ObservationAutoConfigurationTest.java | 159 +++++++++++++++++++++
3 files changed, 189 insertions(+), 2 deletions(-)
diff --git a/components-starter/camel-observation-starter/pom.xml
b/components-starter/camel-observation-starter/pom.xml
index f4e0b81ff1c..8b389d2af71 100644
--- a/components-starter/camel-observation-starter/pom.xml
+++ b/components-starter/camel-observation-starter/pom.xml
@@ -45,6 +45,34 @@
<artifactId>camel-observation</artifactId>
<version>${camel-version}</version>
</dependency>
+ <!-- Test dependencies -->
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-web</artifactId>
+ <version>${spring-boot-version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-actuator</artifactId>
+ <version>${spring-boot-version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>io.micrometer</groupId>
+ <artifactId>micrometer-tracing-bridge-otel</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>io.opentelemetry</groupId>
+ <artifactId>opentelemetry-exporter-common</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>io.opentelemetry</groupId>
+ <artifactId>opentelemetry-sdk</artifactId>
+ <scope>test</scope>
+ </dependency>
<!--START OF GENERATED CODE-->
<dependency>
<groupId>org.apache.camel.springboot</groupId>
diff --git
a/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/ObservationAutoConfiguration.java
b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/ObservationAutoConfiguration.java
index 5cf01984ffe..8b97bc5994b 100644
---
a/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/ObservationAutoConfiguration.java
+++
b/components-starter/camel-observation-starter/src/main/java/org/apache/camel/observation/starter/ObservationAutoConfiguration.java
@@ -27,14 +27,14 @@ import
org.apache.camel.observation.MicrometerObservationTracer;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
-import
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import
org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
-@ConditionalOnMissingClass({
"org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration",
+@ConditionalOnClass(name = {
"org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration",
"org.springframework.boot.actuate.autoconfigure.tracing.MicrometerTracingAutoConfiguration"
})
@AutoConfigureAfter(name = {
"org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration",
diff --git
a/components-starter/camel-observation-starter/src/test/java/org/apache/camel/observation/starter/ObservationAutoConfigurationTest.java
b/components-starter/camel-observation-starter/src/test/java/org/apache/camel/observation/starter/ObservationAutoConfigurationTest.java
new file mode 100644
index 00000000000..aa3fbab8807
--- /dev/null
+++
b/components-starter/camel-observation-starter/src/test/java/org/apache/camel/observation/starter/ObservationAutoConfigurationTest.java
@@ -0,0 +1,159 @@
+/*
+ * 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.observation.starter;
+
+import io.micrometer.core.instrument.MeterRegistry;
+import
io.micrometer.core.instrument.observation.DefaultMeterObservationHandler;
+import io.micrometer.observation.Observation;
+import io.micrometer.observation.ObservationRegistry;
+import io.micrometer.tracing.Tracer;
+import io.micrometer.tracing.handler.TracingAwareMeterObservationHandler;
+
+import
org.springframework.boot.actuate.autoconfigure.observation.ObservationRegistryCustomizer;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.observation.MicrometerObservationTracer;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.web.server.LocalManagementPort;
+import org.springframework.boot.web.client.RestTemplateBuilder;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatusCode;
+import org.springframework.http.ResponseEntity;
+import org.springframework.test.annotation.DirtiesContext;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@DirtiesContext
+@CamelSpringBootTest
+@EnableAutoConfiguration
+@SpringBootTest(
+ webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
+ classes = {
+ CamelAutoConfiguration.class,
+ ObservationAutoConfiguration.class,
+ ObservationAutoConfigurationTest.TestConfiguration.class
+ },
+ properties = {
+ "spring.main.banner-mode=off",
+ "management.endpoints.web.exposure.include=health,metrics",
+ "management.endpoint.health.show-details=always"
+ }
+)
+public class ObservationAutoConfigurationTest {
+
+ @Autowired
+ private ApplicationContext applicationContext;
+
+ @Autowired
+ private CamelContext camelContext;
+
+ @Autowired
+ private ProducerTemplate producerTemplate;
+
+ @Autowired
+ private RestTemplateBuilder restTemplateBuilder;
+
+ @LocalManagementPort
+ private int managementPort;
+
+ /**
+ * Test that the MicrometerObservationTracer bean is created when Spring
Actuator
+ * classes are present. This verifies the @ConditionalOnClass annotation
is correct.
+ */
+ @Test
+ public void testObservationTracerBeanCreated() {
+
assertTrue(applicationContext.containsBean("micrometerObservationTracer"),
+ "MicrometerObservationTracer bean should be created when
actuator is present");
+
+ MicrometerObservationTracer tracer =
applicationContext.getBean(MicrometerObservationTracer.class);
+ assertNotNull(tracer, "MicrometerObservationTracer should not be
null");
+ }
+
+ /**
+ * Test that a message can flow through a traced route and the
camel.component metric is recorded.
+ * The metric name "camel.component" is defined in
MicrometerObservationTracer.
+ */
+ @Test
+ public void testTracedRouteExecutionWithCamelMetric() throws Exception {
+ // Send a message through the route - this should be traced and create
metrics
+ producerTemplate.sendBody("direct:test", "Hello Traced World");
+
+ // Verify the metrics list contains the camel.component metric
+ ResponseEntity<String> metricsResponse = restTemplateBuilder
+ .rootUri("http://localhost:" + managementPort + "/actuator")
+ .build()
+ .exchange("/metrics", HttpMethod.GET, new HttpEntity<>(null),
String.class);
+
+
assertThat(metricsResponse.getStatusCode()).isEqualTo(HttpStatusCode.valueOf(200));
+ assertThat(metricsResponse.getBody()).contains("camel.component");
+
+ // Verify the camel.component metric details are accessible
+ ResponseEntity<String> camelMetricResponse = restTemplateBuilder
+ .rootUri("http://localhost:" + managementPort + "/actuator")
+ .build()
+ .exchange("/metrics/camel.component", HttpMethod.GET, new
HttpEntity<>(null), String.class);
+
+
assertThat(camelMetricResponse.getStatusCode()).isEqualTo(HttpStatusCode.valueOf(200));
+ assertThat(camelMetricResponse.getBody()).contains("camel.component",
"camel-direct");
+ }
+
+ @Configuration
+ public static class TestConfiguration {
+
+ @Bean
+ public RouteBuilder testRouteBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() {
+ from("direct:test")
+ .routeId("test-route")
+ .log("Processing: ${body}")
+ .to("mock:result");
+ }
+ };
+ }
+
+ /**
+ * Customizer to register a real MeterObservationHandler that records
metrics.
+ * This replaces the no-op handler from ObservationAutoConfiguration
for testing purposes.
+ */
+ @Bean
+ public ObservationRegistryCustomizer<ObservationRegistry>
metricsObservationRegistryCustomizer(
+ MeterRegistry meterRegistry, Tracer tracer) {
+ return registry -> {
+ TracingAwareMeterObservationHandler<Observation.Context>
handler = new TracingAwareMeterObservationHandler<>(
+ new DefaultMeterObservationHandler(meterRegistry),
+ tracer
+ );
+ registry.observationConfig().observationHandler(handler);
+ };
+ }
+ }
+}