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);
+            };
+        }
+    }
+}

Reply via email to