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

davsclaus pushed a commit to branch fix/CAMEL-23662
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 19fc1d328362bc8821503dc8705505173701dcfc
Author: Claus Ibsen <[email protected]>
AuthorDate: Tue Jun 2 22:14:29 2026 +0200

    CAMEL-23662: camel-log - Route logMask setting not overriding context 
logMask for log component
    
    The log component endpoint (LogEndpoint) resolved the logMask decision at
    endpoint creation time, consulting only the endpoint URI parameter and the
    CamelContext, but never the route's logMask setting. This caused
    logMask=false on a route to be ignored when using <to uri="log:..."/>.
    
    CamelLogProcessor now checks the route's logMask at process time via the
    exchange's UnitOfWork, respecting the precedence: endpoint > route > 
context.
    This also handles the inverse case where a route enables masking while the
    context has it disabled.
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 .../apache/camel/component/log/LogEndpoint.java    |   5 +-
 .../component/log/LogMaskRouteOverrideTest.java    | 119 +++++++++++++++++++++
 .../camel/support/processor/CamelLogProcessor.java |  60 ++++++++++-
 3 files changed, 180 insertions(+), 4 deletions(-)

diff --git 
a/components/camel-log/src/main/java/org/apache/camel/component/log/LogEndpoint.java
 
b/components/camel-log/src/main/java/org/apache/camel/component/log/LogEndpoint.java
index 1d45a0e1caff..d58bdec70e84 100644
--- 
a/components/camel-log/src/main/java/org/apache/camel/component/log/LogEndpoint.java
+++ 
b/components/camel-log/src/main/java/org/apache/camel/component/log/LogEndpoint.java
@@ -297,9 +297,12 @@ public class LogEndpoint extends ProcessorEndpoint 
implements LineNumberAware {
             Long groupDelay = getGroupDelay();
             answer = new ThroughputLogger(camelLogger, this.getCamelContext(), 
getGroupInterval(), groupDelay, groupActiveOnly);
         } else {
-            answer = new CamelLogProcessor(
+            CamelLogProcessor clp = new CamelLogProcessor(
                     camelLogger, localFormatter, getMaskingFormatter(),
                     
getCamelContext().getCamelContextExtension().getLogListeners());
+            clp.setRouteLogMaskAware(true);
+            clp.setEndpointLogMask(logMask);
+            answer = clp;
         }
         // the logger is the processor
         setProcessor(answer);
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/component/log/LogMaskRouteOverrideTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/component/log/LogMaskRouteOverrideTest.java
new file mode 100644
index 000000000000..0a95d645f64b
--- /dev/null
+++ 
b/core/camel-core/src/test/java/org/apache/camel/component/log/LogMaskRouteOverrideTest.java
@@ -0,0 +1,119 @@
+/*
+ * 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.log;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.spi.MaskingFormatter;
+import org.apache.camel.spi.Registry;
+import org.apache.camel.support.DefaultRegistry;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class LogMaskRouteOverrideTest {
+
+    protected Registry registry;
+
+    protected CamelContext createCamelContext() throws Exception {
+        registry = new DefaultRegistry();
+        CamelContext context = new DefaultCamelContext(registry);
+        context.addRoutes(createRouteBuilder());
+        return context;
+    }
+
+    @Test
+    public void testRouteLogMaskFalseOverridesContextTrue() throws Exception {
+        CamelContext context = createCamelContext();
+        TrackingMaskingFormatter tracker = new TrackingMaskingFormatter();
+        registry.bind(MaskingFormatter.CUSTOM_LOG_MASK_REF, tracker);
+        context.setLogMask(true);
+        context.start();
+
+        MockEndpoint masked = context.getEndpoint("mock:masked", 
MockEndpoint.class);
+        masked.expectedMessageCount(1);
+        MockEndpoint noMask = context.getEndpoint("mock:noMask", 
MockEndpoint.class);
+        noMask.expectedMessageCount(1);
+
+        // send to the route WITH masking (context default)
+        tracker.received = null;
+        context.createProducerTemplate().sendBody("direct:masked", 
"password=secret123");
+        masked.assertIsSatisfied();
+        assertNotNull(tracker.received, "Masking formatter should have been 
called for the masked route");
+
+        // send to the route with logMask=false override
+        tracker.received = null;
+        context.createProducerTemplate().sendBody("direct:noMask", 
"password=secret123");
+        noMask.assertIsSatisfied();
+        assertNull(tracker.received, "Masking formatter should NOT have been 
called for the noMask route");
+
+        context.stop();
+    }
+
+    @Test
+    public void testRouteLogMaskTrueOverridesContextFalse() throws Exception {
+        CamelContext context = createCamelContext();
+        TrackingMaskingFormatter tracker = new TrackingMaskingFormatter();
+        registry.bind(MaskingFormatter.CUSTOM_LOG_MASK_REF, tracker);
+        context.setLogMask(false);
+        context.start();
+
+        MockEndpoint forceMask = context.getEndpoint("mock:forceMask", 
MockEndpoint.class);
+        forceMask.expectedMessageCount(1);
+
+        tracker.received = null;
+        context.createProducerTemplate().sendBody("direct:forceMask", 
"password=secret123");
+        forceMask.assertIsSatisfied();
+        assertNotNull(tracker.received, "Masking formatter should have been 
called for the forceMask route");
+        assertTrue(tracker.received.contains("password=secret123"));
+
+        context.stop();
+    }
+
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct:masked").routeId("masked")
+                        .to("log:masked.logger")
+                        .to("mock:masked");
+
+                from("direct:noMask").routeId("noMask").logMask("false")
+                        .to("log:noMask.logger")
+                        .to("mock:noMask");
+
+                from("direct:forceMask").routeId("forceMask").logMask("true")
+                        .to("log:forceMask.logger")
+                        .to("mock:forceMask");
+            }
+        };
+    }
+
+    public static class TrackingMaskingFormatter implements MaskingFormatter {
+        private String received;
+
+        @Override
+        public String format(String source) {
+            received = source;
+            return source;
+        }
+    }
+}
diff --git 
a/core/camel-support/src/main/java/org/apache/camel/support/processor/CamelLogProcessor.java
 
b/core/camel-support/src/main/java/org/apache/camel/support/processor/CamelLogProcessor.java
index cd06ad998e90..a435775d3707 100644
--- 
a/core/camel-support/src/main/java/org/apache/camel/support/processor/CamelLogProcessor.java
+++ 
b/core/camel-support/src/main/java/org/apache/camel/support/processor/CamelLogProcessor.java
@@ -22,6 +22,7 @@ import org.apache.camel.AsyncCallback;
 import org.apache.camel.Exchange;
 import org.apache.camel.LoggingLevel;
 import org.apache.camel.Processor;
+import org.apache.camel.Route;
 import org.apache.camel.spi.CamelLogger;
 import org.apache.camel.spi.ExchangeFormatter;
 import org.apache.camel.spi.IdAware;
@@ -29,6 +30,7 @@ import org.apache.camel.spi.LogListener;
 import org.apache.camel.spi.MaskingFormatter;
 import org.apache.camel.spi.RouteIdAware;
 import org.apache.camel.spi.StepIdAware;
+import org.apache.camel.spi.UnitOfWork;
 import org.apache.camel.support.AsyncProcessorSupport;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -51,6 +53,8 @@ public class CamelLogProcessor extends AsyncProcessorSupport 
implements IdAware,
     private ExchangeFormatter formatter;
     private MaskingFormatter maskingFormatter;
     private final Set<LogListener> listeners;
+    private boolean routeLogMaskAware;
+    private Boolean endpointLogMask;
 
     public CamelLogProcessor() {
         this(new CamelLogger(CamelLogProcessor.class.getName()));
@@ -109,7 +113,7 @@ public class CamelLogProcessor extends 
AsyncProcessorSupport implements IdAware,
     public boolean process(Exchange exchange, AsyncCallback callback) {
         if (logger.shouldLog()) {
             String output = formatter.format(exchange);
-            if (maskingFormatter != null) {
+            if (shouldMask(exchange)) {
                 output = maskingFormatter.format(output);
             }
             output = fireListeners(exchange, output);
@@ -123,7 +127,7 @@ public class CamelLogProcessor extends 
AsyncProcessorSupport implements IdAware,
     public void process(Exchange exchange, Throwable exception) {
         if (logger.shouldLog()) {
             String output = formatter.format(exchange);
-            if (maskingFormatter != null) {
+            if (shouldMask(exchange)) {
                 output = maskingFormatter.format(output);
             }
             output = fireListeners(exchange, output);
@@ -135,7 +139,7 @@ public class CamelLogProcessor extends 
AsyncProcessorSupport implements IdAware,
     public void process(Exchange exchange, String message) {
         if (logger.shouldLog()) {
             String output = formatter.format(exchange) + message;
-            if (maskingFormatter != null) {
+            if (shouldMask(exchange)) {
                 output = maskingFormatter.format(output);
             }
             output = fireListeners(exchange, output);
@@ -204,6 +208,56 @@ public class CamelLogProcessor extends 
AsyncProcessorSupport implements IdAware,
         this.maskingFormatter = maskingFormatter;
     }
 
+    public void setRouteLogMaskAware(boolean routeLogMaskAware) {
+        this.routeLogMaskAware = routeLogMaskAware;
+    }
+
+    public void setEndpointLogMask(Boolean endpointLogMask) {
+        this.endpointLogMask = endpointLogMask;
+    }
+
+    private boolean shouldMask(Exchange exchange) {
+        if (!routeLogMaskAware) {
+            return maskingFormatter != null;
+        }
+
+        // endpoint-level explicit setting takes highest priority
+        if (endpointLogMask != null) {
+            if (!endpointLogMask) {
+                return false;
+            }
+            if (maskingFormatter == null) {
+                resolveMaskingFormatter(exchange);
+            }
+            return maskingFormatter != null;
+        }
+
+        // check route-level logMask (falls back to context-level)
+        UnitOfWork uow = exchange.getUnitOfWork();
+        if (uow != null) {
+            Route route = uow.getRoute();
+            if (route != null) {
+                if (!route.isLogMask()) {
+                    return false;
+                }
+                if (maskingFormatter == null) {
+                    resolveMaskingFormatter(exchange);
+                }
+                return maskingFormatter != null;
+            }
+        }
+
+        return maskingFormatter != null;
+    }
+
+    private void resolveMaskingFormatter(Exchange exchange) {
+        maskingFormatter = exchange.getContext().getRegistry()
+                .lookupByNameAndType(MaskingFormatter.CUSTOM_LOG_MASK_REF, 
MaskingFormatter.class);
+        if (maskingFormatter == null) {
+            maskingFormatter = new 
DefaultMaskingFormatter(exchange.getContext());
+        }
+    }
+
     /**
      * {@link ExchangeFormatter} that calls <tt>toString</tt> on the {@link 
Exchange}.
      */

Reply via email to