This is an automated email from the ASF dual-hosted git repository. pcongiusti pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel.git
commit e3715c94db48bd21fae6d9bb44c9cb9494c595bf Author: Pasquale Congiusti <[email protected]> AuthorDate: Thu Sep 25 12:00:23 2025 +0200 feat(components): MDC Intercept strategy and UT * Required to wrap any Camel processor * Unit test to cover main use cases --- .../camel/mdc/MDCProcessorsInterceptStrategy.java | 64 +++++++++ .../main/java/org/apache/camel/mdc/MDCService.java | 158 +++++++++++---------- .../org/apache/camel/mdc/MDCAllHeadersTest.java | 79 +++++++++++ .../org/apache/camel/mdc/MDCAllPropertiesTest.java | 79 +++++++++++ .../java/org/apache/camel/mdc/MDCAsyncTest.java | 120 ++++++++++++++++ .../java/org/apache/camel/mdc/MDCDefaultTest.java | 74 ++++++++++ .../apache/camel/mdc/MDCSelectedHeadersTest.java | 84 +++++++++++ .../camel/mdc/MDCSelectedPropertiesTest.java | 84 +++++++++++ .../camel-mdc/src/test/resources/log4j2.properties | 6 +- 9 files changed, 672 insertions(+), 76 deletions(-) diff --git a/components/camel-mdc/src/main/java/org/apache/camel/mdc/MDCProcessorsInterceptStrategy.java b/components/camel-mdc/src/main/java/org/apache/camel/mdc/MDCProcessorsInterceptStrategy.java new file mode 100644 index 00000000000..3306a40e90d --- /dev/null +++ b/components/camel-mdc/src/main/java/org/apache/camel/mdc/MDCProcessorsInterceptStrategy.java @@ -0,0 +1,64 @@ +/* + * 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.mdc; + +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.NamedNode; +import org.apache.camel.Processor; +import org.apache.camel.spi.InterceptStrategy; +import org.apache.camel.support.processor.DelegateAsyncProcessor; + +/** + * MDCProcessorsInterceptStrategy is used to wrap each processor calls and generate the MDC context for each process + * execution. + */ +public class MDCProcessorsInterceptStrategy implements InterceptStrategy { + + private MDCService mdcService; + + public MDCProcessorsInterceptStrategy(MDCService mdcService) { + this.mdcService = mdcService; + } + + @Override + public Processor wrapProcessorInInterceptors( + CamelContext camelContext, + NamedNode processorDefinition, Processor target, Processor nextTarget) + throws Exception { + return new DelegateAsyncProcessor(new TraceProcessor(target)); + } + + private class TraceProcessor implements Processor { + private final Processor target; + + public TraceProcessor(Processor target) { + this.target = target; + } + + @Override + public void process(Exchange exchange) throws Exception { + mdcService.setMDC(exchange); + try { + target.process(exchange); + } finally { + mdcService.unsetMDC(); + } + } + } + +} diff --git a/components/camel-mdc/src/main/java/org/apache/camel/mdc/MDCService.java b/components/camel-mdc/src/main/java/org/apache/camel/mdc/MDCService.java index bd38d6a9a16..5ac3a429881 100644 --- a/components/camel-mdc/src/main/java/org/apache/camel/mdc/MDCService.java +++ b/components/camel-mdc/src/main/java/org/apache/camel/mdc/MDCService.java @@ -22,6 +22,7 @@ import org.apache.camel.ExchangePropertyKey; import org.apache.camel.RuntimeCamelException; import org.apache.camel.spi.CamelLogger; import org.apache.camel.spi.CamelMDCService; +import org.apache.camel.spi.InterceptStrategy; import org.apache.camel.spi.LogListener; import org.apache.camel.spi.annotations.JdkService; import org.apache.camel.support.service.ServiceSupport; @@ -33,12 +34,12 @@ import org.slf4j.MDC; @JdkService("mdc-service") public class MDCService extends ServiceSupport implements CamelMDCService { - private String MDC_BREADCRUMB_ID = "camel.breadcrumbId"; - private String MDC_EXCHANGE_ID = "camel.exchangeId"; - private String MDC_MESSAGE_ID = "camel.messageId"; - private String MDC_CORRELATION_ID = "camel.correlationId"; - private String MDC_ROUTE_ID = "camel.routeId"; - private String MDC_CAMEL_CONTEXT_ID = "camel.contextId"; + static String MDC_BREADCRUMB_ID = "camel.breadcrumbId"; + static String MDC_EXCHANGE_ID = "camel.exchangeId"; + static String MDC_MESSAGE_ID = "camel.messageId"; + static String MDC_CORRELATION_ID = "camel.correlationId"; + static String MDC_ROUTE_ID = "camel.routeId"; + static String MDC_CAMEL_CONTEXT_ID = "camel.contextId"; private static final Logger LOG = LoggerFactory.getLogger(MDCService.class); @@ -90,7 +91,9 @@ public class MDCService extends ServiceSupport implements CamelMDCService { @Override public void doInit() { ObjectHelper.notNull(camelContext, "CamelContext", this); - camelContext.getCamelContextExtension().addLogListener(new TracingLogListener()); + camelContext.getCamelContextExtension().addLogListener(new MDCLogListener()); + InterceptStrategy interceptStrategy = new MDCProcessorsInterceptStrategy(this); + camelContext.getCamelContextExtension().addInterceptStrategy(interceptStrategy); } @Override @@ -99,92 +102,101 @@ public class MDCService extends ServiceSupport implements CamelMDCService { LOG.info("Mapped Diagnostic Context (MDC) enabled"); } - private final class TracingLogListener implements LogListener { - - @Override - public String onLog(Exchange exchange, CamelLogger camelLogger, String message) { - try { - // Default values - prepareMDC(exchange); - if (getCustomHeaders() != null) { - if (getCustomHeaders().equals("*")){ - allHeadersMDC(exchange); - } else { - userSelectedHeadersMDC(exchange); - } + protected void setMDC(Exchange exchange) { + try { + // Default values + prepareMDC(exchange); + if (getCustomHeaders() != null) { + if (getCustomHeaders().equals("*")) { + allHeadersMDC(exchange); + } else { + userSelectedHeadersMDC(exchange); } - if (getCustomProperties() != null) { - if (getCustomProperties().equals("*")){ - allPropertiesMDC(exchange); - } else { - userSelectedPropertiesMDC(exchange); - } + } + if (getCustomProperties() != null) { + if (getCustomProperties().equals("*")) { + allPropertiesMDC(exchange); + } else { + userSelectedPropertiesMDC(exchange); } - } catch (Exception t) { - // This exception is ignored - LOG.warn("MDC: failed to store MDC data. This exception is ignored.", t); } + } catch (Exception t) { + // This exception is ignored + LOG.warn("MDC: failed to store MDC data. This exception is ignored.", t); + } + } + + public void unsetMDC() { + MDC.clear(); + } + + private final class MDCLogListener implements LogListener { + + @Override + public String onLog(Exchange exchange, CamelLogger camelLogger, String message) { + setMDC(exchange); return message; } @Override public void afterLog(Exchange exchange, CamelLogger camelLogger, String message) { - MDC.clear(); + unsetMDC(); } + } - // Default basic MDC properties to set - private void prepareMDC(Exchange exchange) { - MDC.put(MDC_EXCHANGE_ID, exchange.getExchangeId()); - MDC.put(MDC_MESSAGE_ID, exchange.getMessage().getMessageId()); - MDC.put(MDC_CAMEL_CONTEXT_ID, exchange.getContext().getName()); - // Backward compatibility: this info may not be longer widely used - String corrId = exchange.getProperty(ExchangePropertyKey.CORRELATION_ID, String.class); - if (corrId != null) { - MDC.put(MDC_CORRELATION_ID, corrId); - } - // Backward compatibility: this info may not be longer widely used - String breadcrumbId = exchange.getIn().getHeader(Exchange.BREADCRUMB_ID, String.class); - if (breadcrumbId != null) { - MDC.put(MDC_BREADCRUMB_ID, breadcrumbId); - } - String routeId = exchange.getFromRouteId(); - if (routeId != null) { - MDC.put(MDC_ROUTE_ID, routeId); - } + // Default basic MDC properties to set + private void prepareMDC(Exchange exchange) { + MDC.put(MDC_EXCHANGE_ID, exchange.getExchangeId()); + MDC.put(MDC_MESSAGE_ID, exchange.getMessage().getMessageId()); + MDC.put(MDC_CAMEL_CONTEXT_ID, exchange.getContext().getName()); + // Backward compatibility: this info may not be longer widely used + String corrId = exchange.getProperty(ExchangePropertyKey.CORRELATION_ID, String.class); + if (corrId != null) { + MDC.put(MDC_CORRELATION_ID, corrId); + } + // Backward compatibility: this info may not be longer widely used + String breadcrumbId = exchange.getIn().getHeader(Exchange.BREADCRUMB_ID, String.class); + if (breadcrumbId != null) { + MDC.put(MDC_BREADCRUMB_ID, breadcrumbId); } + String routeId = exchange.getFromRouteId(); + if (routeId != null) { + MDC.put(MDC_ROUTE_ID, routeId); + } + } - // Include those headers selected by the user - private void userSelectedHeadersMDC(Exchange exchange) { - for (String customHeader : getCustomHeaders().split(",")) { - if (exchange.getIn().getHeader(customHeader) != null) { - MDC.put(customHeader, exchange.getIn().getHeader(customHeader, String.class)); - } + // Include those headers selected by the user + private void userSelectedHeadersMDC(Exchange exchange) { + for (String customHeader : getCustomHeaders().split(",")) { + if (exchange.getIn().getHeader(customHeader) != null) { + MDC.put(customHeader, exchange.getIn().getHeader(customHeader, String.class)); } } - // Include all available headers - private void allHeadersMDC(Exchange exchange) { - for (String header : exchange.getIn().getHeaders().keySet()) { - if (exchange.getIn().getHeader(header) != null) { - MDC.put(header, exchange.getIn().getHeader(header, String.class)); - } + } + + // Include all available headers + private void allHeadersMDC(Exchange exchange) { + for (String header : exchange.getIn().getHeaders().keySet()) { + if (exchange.getIn().getHeader(header) != null) { + MDC.put(header, exchange.getIn().getHeader(header, String.class)); } } + } - // Include those properties selected by the user - private void userSelectedPropertiesMDC(Exchange exchange) { - for (String customProperty : getCustomProperties().split(",")) { - if (exchange.getProperty(customProperty) != null) { - MDC.put(customProperty, exchange.getProperty(customProperty, String.class)); - } + // Include those properties selected by the user + private void userSelectedPropertiesMDC(Exchange exchange) { + for (String customProperty : getCustomProperties().split(",")) { + if (exchange.getProperty(customProperty) != null) { + MDC.put(customProperty, exchange.getProperty(customProperty, String.class)); } } + } - // Include all available properties - private void allPropertiesMDC(Exchange exchange) { - for (String property : exchange.getAllProperties().keySet()) { - if (exchange.getProperty(property) != null) { - MDC.put(property, exchange.getProperty(property, String.class)); - } + // Include all available properties + private void allPropertiesMDC(Exchange exchange) { + for (String property : exchange.getAllProperties().keySet()) { + if (exchange.getProperty(property) != null) { + MDC.put(property, exchange.getProperty(property, String.class)); } } } diff --git a/components/camel-mdc/src/test/java/org/apache/camel/mdc/MDCAllHeadersTest.java b/components/camel-mdc/src/test/java/org/apache/camel/mdc/MDCAllHeadersTest.java new file mode 100644 index 00000000000..14ab6a56c3e --- /dev/null +++ b/components/camel-mdc/src/test/java/org/apache/camel/mdc/MDCAllHeadersTest.java @@ -0,0 +1,79 @@ +/* + * 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.mdc; + +import java.io.IOException; + +import org.apache.camel.CamelContext; +import org.apache.camel.CamelContextAware; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.test.junit5.ExchangeTestSupport; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class MDCAllHeadersTest extends ExchangeTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(MDCSelectedPropertiesTest.class); + + @Override + protected CamelContext createCamelContext() throws Exception { + MDCService mdcSvc = new MDCService(); + mdcSvc.setCustomHeaders("*"); + CamelContext context = super.createCamelContext(); + CamelContextAware.trySetCamelContext(mdcSvc, context); + mdcSvc.init(context); + return context; + } + + @Test + void testRouteSingleRequest() throws IOException { + template.request("direct:start", null); + // We should get no MDC after the route has been executed + assertEquals(0, MDC.getCopyOfContextMap().size()); + } + + @Override + protected RoutesBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:start") + .routeId("start") + .log("A message") + .setHeader("head1", simple("Header1")) + .setHeader("head2", simple("Header2")) + .process(exchange -> { + LOG.info("A process"); + assertNotNull(MDC.get(MDCService.MDC_MESSAGE_ID)); + assertNotNull(MDC.get(MDCService.MDC_EXCHANGE_ID)); + assertNotNull(MDC.get(MDCService.MDC_ROUTE_ID)); + assertNotNull(MDC.get(MDCService.MDC_CAMEL_CONTEXT_ID)); + assertEquals("Header1", MDC.get("head1")); + assertEquals("Header2", MDC.get("head2")); + }) + .to("log:info"); + } + }; + } + +} diff --git a/components/camel-mdc/src/test/java/org/apache/camel/mdc/MDCAllPropertiesTest.java b/components/camel-mdc/src/test/java/org/apache/camel/mdc/MDCAllPropertiesTest.java new file mode 100644 index 00000000000..57562b61728 --- /dev/null +++ b/components/camel-mdc/src/test/java/org/apache/camel/mdc/MDCAllPropertiesTest.java @@ -0,0 +1,79 @@ +/* + * 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.mdc; + +import java.io.IOException; + +import org.apache.camel.CamelContext; +import org.apache.camel.CamelContextAware; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.test.junit5.ExchangeTestSupport; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class MDCAllPropertiesTest extends ExchangeTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(MDCSelectedPropertiesTest.class); + + @Override + protected CamelContext createCamelContext() throws Exception { + MDCService mdcSvc = new MDCService(); + mdcSvc.setCustomProperties("*"); + CamelContext context = super.createCamelContext(); + CamelContextAware.trySetCamelContext(mdcSvc, context); + mdcSvc.init(context); + return context; + } + + @Test + void testRouteSingleRequest() throws IOException { + template.request("direct:start", null); + // We should get no MDC after the route has been executed + assertEquals(0, MDC.getCopyOfContextMap().size()); + } + + @Override + protected RoutesBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:start") + .routeId("start") + .log("A message") + .setProperty("prop1", simple("Property1")) + .setProperty("prop2", simple("Property2")) + .process(exchange -> { + LOG.info("A process"); + assertNotNull(MDC.get(MDCService.MDC_MESSAGE_ID)); + assertNotNull(MDC.get(MDCService.MDC_EXCHANGE_ID)); + assertNotNull(MDC.get(MDCService.MDC_ROUTE_ID)); + assertNotNull(MDC.get(MDCService.MDC_CAMEL_CONTEXT_ID)); + assertEquals("Property1", MDC.get("prop1")); + assertEquals("Property2", MDC.get("prop2")); + }) + .to("log:info"); + } + }; + } + +} diff --git a/components/camel-mdc/src/test/java/org/apache/camel/mdc/MDCAsyncTest.java b/components/camel-mdc/src/test/java/org/apache/camel/mdc/MDCAsyncTest.java new file mode 100644 index 00000000000..7a5c2284a1d --- /dev/null +++ b/components/camel-mdc/src/test/java/org/apache/camel/mdc/MDCAsyncTest.java @@ -0,0 +1,120 @@ +/* + * 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.mdc; + +import java.io.IOException; + +import org.apache.camel.CamelContext; +import org.apache.camel.CamelContextAware; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.test.junit5.ExchangeTestSupport; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class MDCAsyncTest extends ExchangeTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(MDCAsyncTest.class); + + @Override + protected CamelContext createCamelContext() throws Exception { + MDCService mdcSvc = new MDCService(); + mdcSvc.setCustomHeaders("*"); + mdcSvc.setCustomProperties("*"); + CamelContext context = super.createCamelContext(); + CamelContextAware.trySetCamelContext(mdcSvc, context); + mdcSvc.init(context); + return context; + } + + @Test + void testRouteSingleRequest() throws IOException, InterruptedException { + MockEndpoint mock = getMockEndpoint("mock:end"); + mock.expectedMessageCount(1); + mock.setAssertPeriod(5000); + context.createProducerTemplate().sendBody("direct:start", null); + mock.assertIsSatisfied(1000); + // We should get no MDC after the route has been executed + assertEquals(0, MDC.getCopyOfContextMap().size()); + } + + @Override + protected RoutesBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:start") + .setBody() + .simple("start") + .log("start: ${exchangeId}") + .to("direct:a") + .wireTap("direct:b"); + + from("direct:a") + .setProperty("prop1", simple("Property1")) + .setHeader("head", simple("Header1")) + .process(exchange -> { + LOG.info("Direct:a process"); + assertNotNull(MDC.get(MDCService.MDC_MESSAGE_ID)); + assertNotNull(MDC.get(MDCService.MDC_EXCHANGE_ID)); + assertNotNull(MDC.get(MDCService.MDC_ROUTE_ID)); + assertNotNull(MDC.get(MDCService.MDC_CAMEL_CONTEXT_ID)); + assertEquals("Header1", MDC.get("head")); + assertEquals("Property1", MDC.get("prop1")); + assertNull(MDC.get("prop2")); + // We store the exchange of this execution in a property + // as we will use this property to evaluate the exchange in the direct:b execution + exchange.setProperty("directa-exchange", exchange.getExchangeId()); + }) + .setBody() + .simple("Direct a") + .log("directa: ${exchangeId}"); + + from("direct:b") + .setProperty("prop2", simple("Property2")) + .setHeader("head", simple("Header2")) + .process(exchange -> { + LOG.info("Direct:b process"); + assertNotNull(MDC.get(MDCService.MDC_MESSAGE_ID)); + assertNotNull(MDC.get(MDCService.MDC_EXCHANGE_ID)); + assertNotNull(MDC.get(MDCService.MDC_ROUTE_ID)); + assertNotNull(MDC.get(MDCService.MDC_CAMEL_CONTEXT_ID)); + assertEquals("Header2", MDC.get("head")); + // NOTE: properties are shared + assertEquals("Property1", MDC.get("prop1")); + assertEquals("Property2", MDC.get("prop2")); + // We use as support storage the same properties + assertNotEquals(exchange.getProperty("directa-exchange"), MDC.get(MDCService.MDC_EXCHANGE_ID)); + }) + .delay(2000) + .setBody() + .simple("Direct b") + .log("directb: ${exchangeId}") + .to("mock:end"); + } + }; + } + +} diff --git a/components/camel-mdc/src/test/java/org/apache/camel/mdc/MDCDefaultTest.java b/components/camel-mdc/src/test/java/org/apache/camel/mdc/MDCDefaultTest.java new file mode 100644 index 00000000000..162d5ae5cb7 --- /dev/null +++ b/components/camel-mdc/src/test/java/org/apache/camel/mdc/MDCDefaultTest.java @@ -0,0 +1,74 @@ +/* + * 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.mdc; + +import java.io.IOException; + +import org.apache.camel.CamelContext; +import org.apache.camel.CamelContextAware; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.test.junit5.ExchangeTestSupport; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class MDCDefaultTest extends ExchangeTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(MDCDefaultTest.class); + + @Override + protected CamelContext createCamelContext() throws Exception { + MDCService mdcSvc = new MDCService(); + CamelContext context = super.createCamelContext(); + CamelContextAware.trySetCamelContext(mdcSvc, context); + mdcSvc.init(context); + return context; + } + + @Test + void testRouteSingleRequest() throws IOException { + template.request("direct:start", null); + // We should get no MDC after the route has been executed + assertEquals(0, MDC.getCopyOfContextMap().size()); + } + + @Override + protected RoutesBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:start") + .routeId("start") + .log("A message") + .process(exchange -> { + LOG.info("A process"); + assertNotNull(MDC.get(MDCService.MDC_MESSAGE_ID)); + assertNotNull(MDC.get(MDCService.MDC_EXCHANGE_ID)); + assertNotNull(MDC.get(MDCService.MDC_ROUTE_ID)); + assertNotNull(MDC.get(MDCService.MDC_CAMEL_CONTEXT_ID)); + }) + .to("log:info"); + } + }; + } + +} diff --git a/components/camel-mdc/src/test/java/org/apache/camel/mdc/MDCSelectedHeadersTest.java b/components/camel-mdc/src/test/java/org/apache/camel/mdc/MDCSelectedHeadersTest.java new file mode 100644 index 00000000000..3ff151b206c --- /dev/null +++ b/components/camel-mdc/src/test/java/org/apache/camel/mdc/MDCSelectedHeadersTest.java @@ -0,0 +1,84 @@ +/* + * 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.mdc; + +import java.io.IOException; + +import org.apache.camel.CamelContext; +import org.apache.camel.CamelContextAware; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.test.junit5.ExchangeTestSupport; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class MDCSelectedHeadersTest extends ExchangeTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(MDCAllPropertiesTest.class); + + @Override + protected CamelContext createCamelContext() throws Exception { + MDCService mdcSvc = new MDCService(); + mdcSvc.setCustomHeaders("head1,head2,head3"); + CamelContext context = super.createCamelContext(); + CamelContextAware.trySetCamelContext(mdcSvc, context); + mdcSvc.init(context); + return context; + } + + @Test + void testRouteSingleRequest() throws IOException { + template.request("direct:start", null); + // We should get no MDC after the route has been executed + assertEquals(0, MDC.getCopyOfContextMap().size()); + } + + @Override + protected RoutesBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:start") + .routeId("start") + .log("A message") + .setHeader("head1", simple("Header1")) + .setHeader("head2", simple("Header2")) + // head3 is missing on purpose! + .setHeader("head4", simple("Header4")) + .process(exchange -> { + LOG.info("A process"); + assertNotNull(MDC.get(MDCService.MDC_MESSAGE_ID)); + assertNotNull(MDC.get(MDCService.MDC_EXCHANGE_ID)); + assertNotNull(MDC.get(MDCService.MDC_ROUTE_ID)); + assertNotNull(MDC.get(MDCService.MDC_CAMEL_CONTEXT_ID)); + assertEquals("Header1", MDC.get("head1")); + assertEquals("Header2", MDC.get("head2")); + assertNull(MDC.get("head3")); + assertNull(MDC.get("head4")); + }) + .to("log:info"); + } + }; + } + +} diff --git a/components/camel-mdc/src/test/java/org/apache/camel/mdc/MDCSelectedPropertiesTest.java b/components/camel-mdc/src/test/java/org/apache/camel/mdc/MDCSelectedPropertiesTest.java new file mode 100644 index 00000000000..e3fa275a737 --- /dev/null +++ b/components/camel-mdc/src/test/java/org/apache/camel/mdc/MDCSelectedPropertiesTest.java @@ -0,0 +1,84 @@ +/* + * 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.mdc; + +import java.io.IOException; + +import org.apache.camel.CamelContext; +import org.apache.camel.CamelContextAware; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.test.junit5.ExchangeTestSupport; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class MDCSelectedPropertiesTest extends ExchangeTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(MDCAllPropertiesTest.class); + + @Override + protected CamelContext createCamelContext() throws Exception { + MDCService mdcSvc = new MDCService(); + mdcSvc.setCustomProperties("prop1,prop2,prop3"); + CamelContext context = super.createCamelContext(); + CamelContextAware.trySetCamelContext(mdcSvc, context); + mdcSvc.init(context); + return context; + } + + @Test + void testRouteSingleRequest() throws IOException { + template.request("direct:start", null); + // We should get no MDC after the route has been executed + assertEquals(0, MDC.getCopyOfContextMap().size()); + } + + @Override + protected RoutesBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:start") + .routeId("start") + .log("A message") + .setProperty("prop1", simple("Property1")) + .setProperty("prop2", simple("Property2")) + // prop3 is missing on purpose! + .setProperty("prop4", simple("Property4")) + .process(exchange -> { + LOG.info("A process"); + assertNotNull(MDC.get(MDCService.MDC_MESSAGE_ID)); + assertNotNull(MDC.get(MDCService.MDC_EXCHANGE_ID)); + assertNotNull(MDC.get(MDCService.MDC_ROUTE_ID)); + assertNotNull(MDC.get(MDCService.MDC_CAMEL_CONTEXT_ID)); + assertEquals("Property1", MDC.get("prop1")); + assertEquals("Property2", MDC.get("prop2")); + assertNull(MDC.get("prop3")); + assertNull(MDC.get("prop4")); + }) + .to("log:info"); + } + }; + } + +} diff --git a/components/camel-mdc/src/test/resources/log4j2.properties b/components/camel-mdc/src/test/resources/log4j2.properties index c9d7df800c7..590933e3e26 100644 --- a/components/camel-mdc/src/test/resources/log4j2.properties +++ b/components/camel-mdc/src/test/resources/log4j2.properties @@ -17,14 +17,14 @@ appender.console.type = Console appender.console.name = console appender.console.layout.type = PatternLayout -appender.console.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n +appender.console.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m [%X{camel.contextId}, %X{camel.routeId}, %X{camel.exchangeId}, %X{camel.messageId}, %X{head1}, %X{prop1}, %X{head2}, %X{prop2}]%n appender.file.type = File appender.file.name = file -appender.file.fileName = target/camel-telemetry-test.log +appender.file.fileName = target/camel-mdc-test.log appender.file.append = true appender.file.layout.type = PatternLayout -appender.file.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n +appender.file.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m [%X{camel.contextId}, %X{camel.routeId}, %X{camel.exchangeId}, %X{camel.messageId}, %X{head1}, %X{prop1}, %X{head2}, %X{prop2}]%n rootLogger.level = INFO rootLogger.appenderRef.file.ref = file
