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

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


The following commit(s) were added to refs/heads/main by this push:
     new fb0b9fbfc835 CAMEL-25732: camel-docker - log the throwable at DEBUG 
when the events stream fails before it opens (#29439)
fb0b9fbfc835 is described below

commit fb0b9fbfc835dfee776a440d1e222d11b9e83b22
Author: allthingssecurity <[email protected]>
AuthorDate: Mon Nov 9 15:04:59 2026 +0530

    CAMEL-25732: camel-docker - log the throwable at DEBUG when the events 
stream fails before it opens (#29439)
    
    * CAMEL-25732: camel-docker - log the throwable at DEBUG when the events 
stream fails before it opens
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
 .../docker/consumer/DockerEventsConsumer.java      |  2 +
 .../consumer/DockerEventsConsumerStreamTest.java   | 68 ++++++++++++++++++++++
 2 files changed, 70 insertions(+)

diff --git 
a/components/camel-docker/src/main/java/org/apache/camel/component/docker/consumer/DockerEventsConsumer.java
 
b/components/camel-docker/src/main/java/org/apache/camel/component/docker/consumer/DockerEventsConsumer.java
index b0c7917c3476..ae080e01dbbd 100644
--- 
a/components/camel-docker/src/main/java/org/apache/camel/component/docker/consumer/DockerEventsConsumer.java
+++ 
b/components/camel-docker/src/main/java/org/apache/camel/component/docker/consumer/DockerEventsConsumer.java
@@ -239,8 +239,10 @@ public class DockerEventsConsumer extends DefaultConsumer {
                 LOG.warn("The Docker event stream of {} failed, subscribing 
again in {} ms: {}", endpoint, delay,
                         throwable.getMessage(), throwable);
             } else {
+                // repeats for every attempt while the daemon is down, so one 
line, and the stack trace at DEBUG
                 LOG.warn("Failed to subscribe to the Docker events of {}, 
trying again in {} ms: {}", endpoint, delay,
                         throwable.getMessage());
+                LOG.debug("Failed to subscribe to the Docker events of {}", 
endpoint, throwable);
             }
             subscribeAgain(delay);
         }
diff --git 
a/components/camel-docker/src/test/java/org/apache/camel/component/docker/consumer/DockerEventsConsumerStreamTest.java
 
b/components/camel-docker/src/test/java/org/apache/camel/component/docker/consumer/DockerEventsConsumerStreamTest.java
index 6a8691e34935..875327a150f2 100644
--- 
a/components/camel-docker/src/test/java/org/apache/camel/component/docker/consumer/DockerEventsConsumerStreamTest.java
+++ 
b/components/camel-docker/src/test/java/org/apache/camel/component/docker/consumer/DockerEventsConsumerStreamTest.java
@@ -22,6 +22,7 @@ import java.net.ConnectException;
 import java.util.List;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import com.github.dockerjava.api.DockerClient;
@@ -37,6 +38,12 @@ import org.apache.camel.component.docker.DockerConfiguration;
 import org.apache.camel.component.docker.util.DockerTestUtils;
 import org.apache.camel.component.mock.MockEndpoint;
 import org.apache.camel.test.junit6.CamelTestSupport;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.Logger;
+import org.apache.logging.log4j.core.appender.AbstractAppender;
+import org.apache.logging.log4j.core.config.Property;
 import org.junit.jupiter.api.Test;
 
 import static org.awaitility.Awaitility.await;
@@ -55,6 +62,8 @@ class DockerEventsConsumerStreamTest extends CamelTestSupport 
{
     private final DockerClient dockerClient = mock(DockerClient.class);
     private final List<ResultCallback<Event>> eventCallbacks = new 
CopyOnWriteArrayList<>();
     private final List<ResultCallback<Statistics>> statsCallbacks = new 
CopyOnWriteArrayList<>();
+    private final AtomicInteger eventExecs = new AtomicInteger();
+    private final AtomicBoolean failEventExec = new AtomicBoolean();
 
     @Override
     public boolean isUseRouteBuilder() {
@@ -75,6 +84,12 @@ class DockerEventsConsumerStreamTest extends 
CamelTestSupport {
             EventsCmd cmd = mock(EventsCmd.class);
             when(cmd.withSince(anyString())).thenReturn(cmd);
             when(cmd.exec(any())).thenAnswer(e -> {
+                eventExecs.incrementAndGet();
+                if (failEventExec.getAndSet(false)) {
+                    // what the default Netty transport does when the daemon 
cannot be reached: the connect fails
+                    // synchronously, and the callback is not called
+                    throw new ConnectException("Connection refused");
+                }
                 ResultCallback<Event> callback = e.getArgument(0);
                 eventCallbacks.add(callback);
                 return callback;
@@ -148,6 +163,59 @@ class DockerEventsConsumerStreamTest extends 
CamelTestSupport {
         mock.assertIsSatisfied();
     }
 
+    @Test
+    void failingExecWhenSubscribingAgainIsTriedAgain() throws Exception {
+        addRoute("docker://events?host=localhost&port=2375");
+        eventCallbacks.get(0).onStart(() -> {
+        });
+
+        // the daemon goes away: the stream fails, and the first attempt to 
subscribe again cannot connect
+        failEventExec.set(true);
+        eventCallbacks.get(0).onError(new IOException("Connection reset by 
peer"));
+
+        // the consumer keeps subscribing: the next attempt opens a new stream
+        await().atMost(15, TimeUnit.SECONDS).until(() -> eventCallbacks.size() 
== 2);
+        assertEquals(3, eventExecs.get(), "the start, the attempt that failed 
and the one that succeeded");
+
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedBodiesReceived(new Event("start", "c2", "image", 2L));
+        eventCallbacks.get(1).onStart(() -> {
+        });
+        eventCallbacks.get(1).onNext(new Event("start", "c2", "image", 2L));
+        mock.assertIsSatisfied();
+    }
+
+    @Test
+    void streamThatFailsBeforeItIsOpenLogsTheStackTraceAtDebug() throws 
Exception {
+        addRoute("docker://events?host=localhost&port=2375");
+        List<LogEvent> events = new CopyOnWriteArrayList<>();
+        AbstractAppender appender = new AbstractAppender("subscribeFailures", 
null, null, true, Property.EMPTY_ARRAY) {
+            @Override
+            public void append(LogEvent event) {
+                events.add(event.toImmutable());
+            }
+        };
+        appender.start();
+        Logger logger = (Logger) 
LogManager.getLogger(DockerEventsConsumer.class);
+        Level level = logger.getLevel();
+        logger.addAppender(appender);
+        logger.setLevel(Level.DEBUG);
+        ConnectException refused = new ConnectException("Connection refused");
+        try {
+            // the stream fails before it is open (the daemon cannot be 
reached)
+            eventCallbacks.get(0).onError(refused);
+        } finally {
+            logger.setLevel(level);
+            logger.removeAppender(appender);
+            appender.stop();
+        }
+
+        // one WARN line without the stack trace, and the stack trace at DEBUG
+        assertEquals(1, events.stream().filter(e -> e.getLevel() == Level.WARN 
&& e.getThrown() == null).count());
+        assertEquals(0, events.stream().filter(e -> e.getLevel() == Level.WARN 
&& e.getThrown() != null).count());
+        assertEquals(1, events.stream().filter(e -> e.getLevel() == 
Level.DEBUG && e.getThrown() == refused).count());
+    }
+
     @Test
     void eventStreamThatEndsIsOpenedAgain() throws Exception {
         addRoute("docker://events?host=localhost&port=2375");

Reply via email to