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 04a322abdef5 CAMEL-23662: camel-log - Route logMask setting not
overriding context logMask for log component (#23715)
04a322abdef5 is described below
commit 04a322abdef5c3c16f933342473529c31aa72af3
Author: Claus Ibsen <[email protected]>
AuthorDate: Tue Jun 2 23:13:18 2026 +0200
CAMEL-23662: camel-log - Route logMask setting not overriding context
logMask for log component (#23715)
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.
Signed-off-by: Claus Ibsen <[email protected]>
Co-authored-by: Claude Opus 4.6 <[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}.
*/