feat(components): MDC Intercept strategy and UT
* Required to wrap any Camel processor
* Unit test to cover main use cases
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 0000000..3306a40
--- /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 bd38d6a..5ac3a42 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.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 @@
@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 @@
@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 @@
LOG.info("Mapped Diagnostic Context (MDC) enabled");
}
- private final class TracingLogListener implements LogListener {
+ 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);
+ }
+ }
+ } 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) {
- 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);
- }
- }
- } catch (Exception t) {
- // This exception is ignored
- LOG.warn("MDC: failed to store MDC data. This exception is ignored.", t);
- }
+ 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 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 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 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 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));
}
}
}
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 0000000..14ab6a5
--- /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 0000000..57562b6
--- /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 0000000..7a5c228
--- /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 0000000..162d5ae
--- /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 0000000..3ff151b
--- /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 0000000..e3fa275
--- /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 c9d7df8..590933e 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