You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2019/08/05 16:01:25 UTC

[camel] branch master updated: CAMEL-7444: MDC logging now supports setting a pattern to allow to propagte custom keys that matches the pattern.

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 92ef961  CAMEL-7444: MDC logging now supports setting a pattern to allow to propagte custom keys that matches the pattern.
92ef961 is described below

commit 92ef9616a95a52e198cf959a7fe3d7ad9ca4b521
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Mon Aug 5 17:31:03 2019 +0200

    CAMEL-7444: MDC logging now supports setting a pattern to allow to propagte custom keys that matches the pattern.
---
 .../camel/blueprint/CamelContextFactoryBean.java   | 11 +++++
 .../src/main/docs/spring-boot.adoc                 |  3 +-
 .../spring/boot/CamelConfigurationProperties.java  | 16 +++++++
 .../camel/spring/CamelContextFactoryBean.java      | 24 +++++++++++
 .../main/java/org/apache/camel/CamelContext.java   | 36 ++++++++++++++++
 .../camel/impl/engine/AbstractCamelContext.java    | 18 +++++++-
 .../impl/engine/DefaultUnitOfWorkFactory.java      |  2 +-
 .../apache/camel/impl/engine/MDCUnitOfWork.java    | 49 +++++++++++++++++++---
 .../core/xml/AbstractCamelContextFactoryBean.java  |  5 +++
 .../org/apache/camel/processor/MDCAsyncTest.java   | 21 ++++++++++
 .../camel/main/DefaultConfigurationConfigurer.java |  1 +
 .../camel/main/DefaultConfigurationProperties.java | 23 ++++++++++
 .../camel-main-configuration-metadata.json         |  6 +++
 13 files changed, 206 insertions(+), 9 deletions(-)

diff --git a/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelContextFactoryBean.java b/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelContextFactoryBean.java
index f63f212..553cca0 100644
--- a/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelContextFactoryBean.java
+++ b/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelContextFactoryBean.java
@@ -110,6 +110,8 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Blu
     @XmlAttribute
     private String useMDCLogging;
     @XmlAttribute
+    private String mdcLoggingKeysPattern;
+    @XmlAttribute
     private String useDataType;
     @XmlAttribute
     private String useBreadcrumb;
@@ -401,6 +403,15 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Blu
     }
 
     @Override
+    public String getMDCLoggingKeysPattern() {
+        return mdcLoggingKeysPattern;
+    }
+
+    public void setMDCLoggingKeysPattern(String mdcLoggingKeysPattern) {
+        this.mdcLoggingKeysPattern = mdcLoggingKeysPattern;
+    }
+
+    @Override
     public String getUseDataType() {
         return useDataType;
     }
diff --git a/components/camel-spring-boot/src/main/docs/spring-boot.adoc b/components/camel-spring-boot/src/main/docs/spring-boot.adoc
index fa08bbd..ddbd8df 100644
--- a/components/camel-spring-boot/src/main/docs/spring-boot.adoc
+++ b/components/camel-spring-boot/src/main/docs/spring-boot.adoc
@@ -89,7 +89,7 @@ When using Spring Boot make sure to use the following Maven dependency to have s
 ----
 
 
-The component supports 126 options, which are listed below.
+The component supports 127 options, which are listed below.
 
 
 
@@ -164,6 +164,7 @@ The component supports 126 options, which are listed below.
 | *camel.springboot.log-exhausted-message-body* | Sets whether to log exhausted message body with message history. Default is false. | false | Boolean
 | *camel.springboot.log-mask* | Sets whether log mask is enabled or not. Default is false. | false | Boolean
 | *camel.springboot.main-run-controller* | Whether to use the main run controller to ensure the Spring-Boot application keeps running until being stopped or the JVM terminated. You typically only need this if you run Spring-Boot standalone. If you run Spring-Boot with spring-boot-starter-web then the web container keeps the JVM running. | false | Boolean
+| *camel.springboot.mdc-logging-keys-pattern* | Sets the pattern used for determine which custom MDC keys to propagate during message routing when the routing engine continues routing asynchronously for the given message. Setting this pattern to * will propagate all custom keys. Or setting the pattern to foo*,bar* will propagate any keys starting with either foo or bar. Notice that a set of standard Camel MDC keys are always propagated which starts with camel. as key name. The match rule [...]
 | *camel.springboot.message-history* | Sets whether message history is enabled or not. Default is true. | true | Boolean
 | *camel.springboot.name* | Sets the name of the CamelContext. |  | String
 | *camel.springboot.producer-template-cache-size* | Producer template endpoints cache size. | 1000 | Integer
diff --git a/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelConfigurationProperties.java b/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelConfigurationProperties.java
index 9adbbcf..8e884a6 100644
--- a/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelConfigurationProperties.java
+++ b/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelConfigurationProperties.java
@@ -416,6 +416,22 @@ public class CamelConfigurationProperties extends DefaultConfigurationProperties
     private boolean useMdcLogging;
 
     /**
+     * Sets the pattern used for determine which custom MDC keys to propagate during message routing when
+     * the routing engine continues routing asynchronously for the given message. Setting this pattern to * will
+     * propagate all custom keys. Or setting the pattern to foo*,bar* will propagate any keys starting with
+     * either foo or bar.
+     * Notice that a set of standard Camel MDC keys are always propagated which starts with camel. as key name.
+     *
+     * The match rules are applied in this order (case insensitive):
+     *
+     * 1. exact match, returns true
+     * 2. wildcard match (pattern ends with a * and the name starts with the pattern), returns true
+     * 3. regular expression match, returns true
+     * 4. otherwise returns false
+     */
+    private String mdcLoggingKeysPattern;
+
+    /**
      * Sets the thread name pattern used for creating the full thread name.
      *
      * The default pattern is: Camel (#camelId#) thread ##counter# - #name#
diff --git a/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java b/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java
index d5097b9..cc155fb 100644
--- a/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java
+++ b/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java
@@ -125,6 +125,8 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Spr
     @XmlAttribute
     private String useMDCLogging;
     @XmlAttribute
+    private String mdcLoggingKeysPattern;
+    @XmlAttribute
     private String useDataType;
     @XmlAttribute
     private String useBreadcrumb;
@@ -804,6 +806,28 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Spr
         this.useMDCLogging = useMDCLogging;
     }
 
+    public String getMDCLoggingKeysPattern() {
+        return mdcLoggingKeysPattern;
+    }
+
+    /**
+     * Sets the pattern used for determine which custom MDC keys to propagate during message routing when
+     * the routing engine continues routing asynchronously for the given message. Setting this pattern to * will
+     * propagate all custom keys. Or setting the pattern to foo*,bar* will propagate any keys starting with
+     * either foo or bar.
+     * Notice that a set of standard Camel MDC keys are always propagated which starts with camel. as key name.
+     *
+     * The match rules are applied in this order (case insensitive):
+     *
+     * 1. exact match, returns true
+     * 2. wildcard match (pattern ends with a * and the name starts with the pattern), returns true
+     * 3. regular expression match, returns true
+     * 4. otherwise returns false
+     */
+    public void setMDCLoggingKeysPattern(String mdcLoggingKeysPattern) {
+        this.mdcLoggingKeysPattern = mdcLoggingKeysPattern;
+    }
+
     @Override
     public String getUseDataType() {
         return useDataType;
diff --git a/core/camel-api/src/main/java/org/apache/camel/CamelContext.java b/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
index e981250..8e501f6 100644
--- a/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
+++ b/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
@@ -1162,6 +1162,42 @@ public interface CamelContext extends StatefulService, RuntimeConfiguration {
     void setUseMDCLogging(Boolean useMDCLogging);
 
     /**
+     * Gets the pattern used for determine which custom MDC keys to propagate during message routing when
+     * the routing engine continues routing asynchronously for the given message. Setting this pattern to <tt>*</tt> will
+     * propagate all custom keys. Or setting the pattern to <tt>foo*,bar*</tt> will propagate any keys starting with
+     * either foo or bar.
+     * Notice that a set of standard Camel MDC keys are always propagated which starts with <tt>camel.</tt> as key name.
+     * <p/>
+     * The match rules are applied in this order (case insensitive):
+     * <ul>
+     *   <li>exact match, returns true</li>
+     *   <li>wildcard match (pattern ends with a * and the name starts with the pattern), returns true</li>
+     *   <li>regular expression match, returns true</li>
+     *   <li>otherwise returns false</li>
+     * </ul>
+     */
+    String getMDCLoggingKeysPattern();
+
+    /**
+     * Sets the pattern used for determine which custom MDC keys to propagate during message routing when
+     * the routing engine continues routing asynchronously for the given message. Setting this pattern to <tt>*</tt> will
+     * propagate all custom keys. Or setting the pattern to <tt>foo*,bar*</tt> will propagate any keys starting with
+     * either foo or bar.
+     * Notice that a set of standard Camel MDC keys are always propagated which starts with <tt>camel.</tt> as key name.
+     * <p/>
+     * The match rules are applied in this order (case insensitive):
+     * <ul>
+     *   <li>exact match, returns true</li>
+     *   <li>wildcard match (pattern ends with a * and the name starts with the pattern), returns true</li>
+     *   <li>regular expression match, returns true</li>
+     *   <li>otherwise returns false</li>
+     * </ul>
+     *
+     * @param pattern  the pattern
+     */
+    void setMDCLoggingKeysPattern(String pattern);
+
+    /**
      * Whether to enable using data type on Camel messages.
      * <p/>
      * Data type are automatic turned on if one ore more routes has been explicit configured with input and output types.
diff --git a/core/camel-base/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java b/core/camel-base/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
index 85330c5..4aba49c 100644
--- a/core/camel-base/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
+++ b/core/camel-base/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
@@ -204,6 +204,7 @@ public abstract class AbstractCamelContext extends ServiceSupport implements Ext
     private Boolean loadTypeConverters = Boolean.TRUE;
     private Boolean typeConverterStatisticsEnabled = Boolean.FALSE;
     private Boolean useMDCLogging = Boolean.FALSE;
+    private String mdcLoggingKeysPattern;
     private Boolean useDataType = Boolean.FALSE;
     private Boolean useBreadcrumb = Boolean.FALSE;
     private Boolean allowUseOriginalMessage = Boolean.FALSE;
@@ -2534,7 +2535,12 @@ public abstract class AbstractCamelContext extends ServiceSupport implements Ext
 
         if (isUseMDCLogging()) {
             // log if MDC has been enabled
-            log.info("MDC logging is enabled on CamelContext: {}", getName());
+            String pattern = getMDCLoggingKeysPattern();
+            if (pattern != null) {
+                log.info("MDC logging (keys-pattern: {}) is enabled on CamelContext: {}", pattern, getName());
+            } else {
+                log.info("MDC logging is enabled on CamelContext: {}", getName());
+            }
         }
 
         if (getDelayer() != null && getDelayer() > 0) {
@@ -3726,6 +3732,16 @@ public abstract class AbstractCamelContext extends ServiceSupport implements Ext
     }
 
     @Override
+    public String getMDCLoggingKeysPattern() {
+        return mdcLoggingKeysPattern;
+    }
+
+    @Override
+    public void setMDCLoggingKeysPattern(String pattern) {
+        this.mdcLoggingKeysPattern = pattern;
+    }
+
+    @Override
     public Boolean isUseDataType() {
         return useDataType;
     }
diff --git a/core/camel-base/src/main/java/org/apache/camel/impl/engine/DefaultUnitOfWorkFactory.java b/core/camel-base/src/main/java/org/apache/camel/impl/engine/DefaultUnitOfWorkFactory.java
index 06ea3cd..a2af28e 100644
--- a/core/camel-base/src/main/java/org/apache/camel/impl/engine/DefaultUnitOfWorkFactory.java
+++ b/core/camel-base/src/main/java/org/apache/camel/impl/engine/DefaultUnitOfWorkFactory.java
@@ -29,7 +29,7 @@ public class DefaultUnitOfWorkFactory implements UnitOfWorkFactory {
     public UnitOfWork createUnitOfWork(Exchange exchange) {
         UnitOfWork answer;
         if (exchange.getContext().isUseMDCLogging()) {
-            answer = new MDCUnitOfWork(exchange);
+            answer = new MDCUnitOfWork(exchange, exchange.getContext().getMDCLoggingKeysPattern());
         } else {
             answer = new DefaultUnitOfWork(exchange);
         }
diff --git a/core/camel-base/src/main/java/org/apache/camel/impl/engine/MDCUnitOfWork.java b/core/camel-base/src/main/java/org/apache/camel/impl/engine/MDCUnitOfWork.java
index 360fb99..30812db 100644
--- a/core/camel-base/src/main/java/org/apache/camel/impl/engine/MDCUnitOfWork.java
+++ b/core/camel-base/src/main/java/org/apache/camel/impl/engine/MDCUnitOfWork.java
@@ -16,11 +16,15 @@
  */
 package org.apache.camel.impl.engine;
 
+import java.util.HashMap;
+import java.util.Map;
+
 import org.apache.camel.AsyncCallback;
 import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
 import org.apache.camel.spi.RouteContext;
 import org.apache.camel.spi.UnitOfWork;
+import org.apache.camel.support.PatternHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.MDC;
@@ -32,6 +36,8 @@ public class MDCUnitOfWork extends DefaultUnitOfWork {
 
     private static final Logger LOG = LoggerFactory.getLogger(MDCUnitOfWork.class);
 
+    private final String pattern;
+
     private final String originalBreadcrumbId;
     private final String originalExchangeId;
     private final String originalMessageId;
@@ -41,8 +47,9 @@ public class MDCUnitOfWork extends DefaultUnitOfWork {
     private final String originalCamelContextId;
     private final String originalTransactionKey;
 
-    public MDCUnitOfWork(Exchange exchange) {
+    public MDCUnitOfWork(Exchange exchange, String pattern) {
         super(exchange, LOG);
+        this.pattern = pattern;
 
         // remember existing values
         this.originalExchangeId = MDC.get(MDC_EXCHANGE_ID);
@@ -74,7 +81,7 @@ public class MDCUnitOfWork extends DefaultUnitOfWork {
 
     @Override
     public UnitOfWork newInstance(Exchange exchange) {
-        return new MDCUnitOfWork(exchange);
+        return new MDCUnitOfWork(exchange, pattern);
     }
 
     @Override
@@ -126,7 +133,7 @@ public class MDCUnitOfWork extends DefaultUnitOfWork {
         if (stepId != null) {
             MDC.put(MDC_STEP_ID, stepId);
         }
-        return new MDCCallback(callback);
+        return new MDCCallback(callback, pattern);
     }
 
     @Override
@@ -189,6 +196,15 @@ public class MDCUnitOfWork extends DefaultUnitOfWork {
         return "MDCUnitOfWork";
     }
 
+    private static boolean matchPatterns(String value, String[] patterns) {
+        for (String pattern : patterns) {
+            if (PatternHelper.matchPattern(value, pattern)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * {@link AsyncCallback} which preserves {@link org.slf4j.MDC} when
      * the asynchronous routing engine is being used.
@@ -201,10 +217,10 @@ public class MDCUnitOfWork extends DefaultUnitOfWork {
         private final String messageId;
         private final String correlationId;
         private final String routeId;
-        private final String stepId;
         private final String camelContextId;
+        private final Map<String, String> custom;
 
-        private MDCCallback(AsyncCallback delegate) {
+        private MDCCallback(AsyncCallback delegate, String pattern) {
             this.delegate = delegate;
             this.exchangeId = MDC.get(MDC_EXCHANGE_ID);
             this.messageId = MDC.get(MDC_MESSAGE_ID);
@@ -212,7 +228,25 @@ public class MDCUnitOfWork extends DefaultUnitOfWork {
             this.correlationId = MDC.get(MDC_CORRELATION_ID);
             this.camelContextId = MDC.get(MDC_CAMEL_CONTEXT_ID);
             this.routeId = MDC.get(MDC_ROUTE_ID);
-            this.stepId = MDC.get(MDC_STEP_ID);
+
+            if (pattern != null) {
+                custom = new HashMap<>();
+                Map<String, String> mdc = MDC.getCopyOfContextMap();
+                if (mdc != null) {
+                    if ("*".equals(pattern)) {
+                        custom.putAll(mdc);
+                    } else {
+                        final String[] patterns = pattern.split(",");
+                        mdc.forEach((k, v) -> {
+                            if (matchPatterns(k, patterns)) {
+                                custom.put(k, v);
+                            }
+                        });
+                    }
+                }
+            } else {
+                custom = null;
+            }
         }
 
         @Override
@@ -235,6 +269,9 @@ public class MDCUnitOfWork extends DefaultUnitOfWork {
                     if (camelContextId != null) {
                         MDC.put(MDC_CAMEL_CONTEXT_ID, camelContextId);
                     }
+                    if (custom != null) {
+                        custom.forEach(MDC::put);
+                    }
                 }
                 // need to setup the routeId finally
                 if (routeId != null) {
diff --git a/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java b/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java
index 4c1e0c7..a1e4b3b 100644
--- a/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java
+++ b/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java
@@ -750,6 +750,8 @@ public abstract class AbstractCamelContextFactoryBean<T extends ModelCamelContex
 
     public abstract String getUseMDCLogging();
 
+    public abstract String getMDCLoggingKeysPattern();
+
     public abstract String getUseDataType();
 
     public abstract String getUseBreadcrumb();
@@ -852,6 +854,9 @@ public abstract class AbstractCamelContextFactoryBean<T extends ModelCamelContex
         if (getUseMDCLogging() != null) {
             context.setUseMDCLogging(CamelContextHelper.parseBoolean(context, getUseMDCLogging()));
         }
+        if (getMDCLoggingKeysPattern() != null) {
+            context.setMDCLoggingKeysPattern(CamelContextHelper.parseText(context, getMDCLoggingKeysPattern()));
+        }
         if (getUseDataType() != null) {
             context.setUseDataType(CamelContextHelper.parseBoolean(context, getUseDataType()));
         }
diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/MDCAsyncTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/MDCAsyncTest.java
index edbc4d5..261a080 100644
--- a/core/camel-core/src/test/java/org/apache/camel/processor/MDCAsyncTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/MDCAsyncTest.java
@@ -52,10 +52,19 @@ public class MDCAsyncTest extends ContextTestSupport {
                 // enable MDC and breadcrumb
                 context.setUseMDCLogging(true);
                 context.setUseBreadcrumb(true);
+                context.setMDCLoggingKeysPattern("custom*,my*");
 
                 MdcCheckerProcessor checker = new MdcCheckerProcessor();
                 
                 from("direct:a").routeId("route-async")
+                    .process(e -> {
+                        // custom is propagated
+                        MDC.put("custom.hello", "World");
+                        // foo is not propagated
+                        MDC.put("foo", "Bar");
+                        // myKey is propagated
+                        MDC.put("myKey", "Baz");
+                    })
                     .process(checker)
                     .to("log:foo")
                     .process(new MyAsyncProcessor())
@@ -110,9 +119,21 @@ public class MDCAsyncTest extends ContextTestSupport {
         private String breadcrumbId;
         private String contextId;
         private Long threadId;
+        private String foo;
 
         @Override
         public void process(Exchange exchange) throws Exception {
+            // custom is propagated as its pattern matches
+            assertEquals("World", MDC.get("custom.hello"));
+            assertEquals("Baz", MDC.get("myKey"));
+
+            if (foo != null) {
+                // foo is not propagated
+                assertNotEquals(foo, MDC.get("foo"));
+            } else {
+                foo = MDC.get("foo");
+            }
+
             if (threadId != null) {
                 Long currId = Thread.currentThread().getId();
                 assertNotEquals(threadId, currId);
diff --git a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java
index b8fdc6a..6dbaf1e 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java
@@ -140,6 +140,7 @@ public final class DefaultConfigurationConfigurer {
         camelContext.setUseBreadcrumb(config.isUseBreadcrumb());
         camelContext.setUseDataType(config.isUseDataType());
         camelContext.setUseMDCLogging(config.isUseMdcLogging());
+        camelContext.setMDCLoggingKeysPattern(config.getMdcLoggingKeysPattern());
         camelContext.setLoadTypeConverters(config.isLoadTypeConverters());
 
         if (camelContext.getManagementStrategy().getManagementAgent() != null) {
diff --git a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java
index e4ce762..25c0548 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java
@@ -64,6 +64,7 @@ public abstract class DefaultConfigurationProperties<T> {
     private String jmxManagementNamePattern = "#name#";
     private boolean jmxCreateConnector;
     private boolean useMdcLogging;
+    private String mdcLoggingKeysPattern;
     private String threadNamePattern;
     private String routeFilterIncludePattern;
     private String routeFilterExcludePattern;
@@ -589,6 +590,28 @@ public abstract class DefaultConfigurationProperties<T> {
         this.useMdcLogging = useMdcLogging;
     }
 
+    public String getMdcLoggingKeysPattern() {
+        return mdcLoggingKeysPattern;
+    }
+
+    /**
+     * Sets the pattern used for determine which custom MDC keys to propagate during message routing when
+     * the routing engine continues routing asynchronously for the given message. Setting this pattern to * will
+     * propagate all custom keys. Or setting the pattern to foo*,bar* will propagate any keys starting with
+     * either foo or bar.
+     * Notice that a set of standard Camel MDC keys are always propagated which starts with camel. as key name.
+     *
+     * The match rules are applied in this order (case insensitive):
+     *
+     * 1. exact match, returns true
+     * 2. wildcard match (pattern ends with a * and the name starts with the pattern), returns true
+     * 3. regular expression match, returns true
+     * 4. otherwise returns false
+     */
+    public void setMdcLoggingKeysPattern(String mdcLoggingKeysPattern) {
+        this.mdcLoggingKeysPattern = mdcLoggingKeysPattern;
+    }
+
     public String getThreadNamePattern() {
         return threadNamePattern;
     }
diff --git a/core/camel-main/src/main/resources/META-INF/camel-main-configuration-metadata.json b/core/camel-main/src/main/resources/META-INF/camel-main-configuration-metadata.json
index 2f7a884..dbc5104 100644
--- a/core/camel-main/src/main/resources/META-INF/camel-main-configuration-metadata.json
+++ b/core/camel-main/src/main/resources/META-INF/camel-main-configuration-metadata.json
@@ -187,6 +187,12 @@
 			"description":"Sets whether log mask is enabled or not. Default is false."
 		},
 		{
+			"name":"camel.main.mdc-logging-keys-pattern",
+			"type":"java.lang.String",
+			"sourceType":"org.apache.camel.main.DefaultConfigurationProperties",
+			"description":"Sets the pattern used for determine which custom MDC keys to propagate during message routing when the routing engine continues routing asynchronously for the given message. Setting this pattern to will propagate all custom keys. Or setting the pattern to foo,bar will propagate any keys starting with either foo or bar. Notice that a set of standard Camel MDC keys are always propagated which starts with camel. as key name. The match rules are applied in this order (case  [...]
+		},
+		{
 			"name":"camel.main.message-history",
 			"type":"boolean",
 			"sourceType":"org.apache.camel.main.DefaultConfigurationProperties",