Apache camel 卷下的Camel MDC Logback过时信息

Apache camel 卷下的Camel MDC Logback过时信息,apache-camel,logback,mdc,Apache Camel,Logback,Mdc,我们有一个高负载的apachecamel应用程序,它利用logback/MDC记录信息。正如logback文档中预先警告的那样,我们发现一些MDC信息在线程上是过时的。我发现这个问题解决了这个问题: 我们应该如何将其应用于camel应用程序以避免过时的信息?是否有一个简单的方法可以将默认ThreadPoolExecutor全局更改为链接问题中建议的自定义变体?我看到你可以为池自己做,但没有看到任何执行者的例子。请记住,我们的应用程序相当大,每天都有大量的订单,我希望对现有应用程序的影响尽可能小

我们有一个高负载的apachecamel应用程序,它利用logback/MDC记录信息。正如logback文档中预先警告的那样,我们发现一些MDC信息在线程上是过时的。我发现这个问题解决了这个问题:


我们应该如何将其应用于camel应用程序以避免过时的信息?是否有一个简单的方法可以将默认ThreadPoolExecutor全局更改为链接问题中建议的自定义变体?我看到你可以为池自己做,但没有看到任何执行者的例子。请记住,我们的应用程序相当大,每天都有大量的订单,我希望对现有应用程序的影响尽可能小。

我找到了答案,并想发布我所做的事情,以防它对其他人有利。请注意,我使用的是JDK 6/camel2.13.2

  • Camel有一个使用
    DefaultThreadPoolFactory的
    DefaultExecutorServiceManager
    。我将默认工厂扩展为
    MdcThreadPoolFactory

  • DefaultThreadPoolFactory
    具有生成
    RejectableThreadPoolExecutor
    s和
    RejectableScheduledThreadPoolExecutor
    s的方法。我将这两种方法扩展到Mdc*版本中,覆盖
    execute()
    方法来包装Runnable并在线程之间传递Mdc信息(如我原始问题中的链接所指定的)

  • 我在我的应用程序配置中创建了一个
    MdcThreadPoolFactory
    的bean实例,该实例由Camel自动获取,并在
    ExecutorServiceManager

MDCThread池执行器:

package com.mypackage.concurrent

import org.apache.camel.util.concurrent.RejectableThreadPoolExecutor
import org.slf4j.MDC;

import java.util.Map;
import java.util.concurrent.*;

/**
 * A SLF4J MDC-compatible {@link ThreadPoolExecutor}.
 * <p/>
 * In general, MDC is used to store diagnostic information (e.g. a user's session id) in per-thread variables, to facilitate
 * logging. However, although MDC data is passed to thread children, this doesn't work when threads are reused in a
 * thread pool. This is a drop-in replacement for {@link ThreadPoolExecutor} sets MDC data before each task appropriately.
 * <p/>
 * Created by broda20.
 * Date: 10/29/15
 */
public class MdcThreadPoolExecutor extends RejectableThreadPoolExecutor {

    @SuppressWarnings("unchecked")
    private Map<String, Object> getContextForTask() {
        return MDC.getCopyOfContextMap();
    }

    public MdcThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
                                        BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }

    public MdcThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
                                        BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
    }

    public MdcThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
                                        BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
    }

    public MdcThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
                                        BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
    }

    /**
     * All executions will have MDC injected. {@code ThreadPoolExecutor}'s submission methods ({@code submit()} etc.)
     * all delegate to this.
     */
    @Override
    public void execute(Runnable command) {
        super.execute(wrap(command, getContextForTask()));
    }

    public static Runnable wrap(final Runnable runnable, final Map<String, Object> context) {
        return new Runnable() {
            @Override
            public void run() {
                Map previous = MDC.getCopyOfContextMap();
                if (context == null) {
                    MDC.clear();
                } else {
                    MDC.setContextMap(context);
                }
                try {
                    runnable.run();
                } finally {
                    if (previous == null) {
                        MDC.clear();
                    } else {
                        MDC.setContextMap(previous);
                    }
                }
            }
        };
    }
}
package com.mypackage.concurrent

import org.apache.camel.util.concurrent.RejectableScheduledThreadPoolExecutor
import org.slf4j.MDC;

import java.util.Map;
import java.util.concurrent.*;

/**
 * A SLF4J MDC-compatible {@link ThreadPoolExecutor}.
 * <p/>
 * In general, MDC is used to store diagnostic information (e.g. a user's session id) in per-thread variables, to facilitate
 * logging. However, although MDC data is passed to thread children, this doesn't work when threads are reused in a
 * thread pool. This is a drop-in replacement for {@link ThreadPoolExecutor} sets MDC data before each task appropriately.
 * <p/>
 * Created by broda20.
 * Date: 10/29/15
 */
public class MdcScheduledThreadPoolExecutor extends RejectableScheduledThreadPoolExecutor {

    @SuppressWarnings("unchecked")
    private Map<String, Object> getContextForTask() {
        return MDC.getCopyOfContextMap();
    }

    public MdcScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize);
    }

    public MdcScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory) {
        super(corePoolSize, threadFactory);
    }

    public MdcScheduledThreadPoolExecutor(int corePoolSize, RejectedExecutionHandler handler) {
        super(corePoolSize, handler);
    }

    public MdcScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
        super(corePoolSize, threadFactory, handler);
    }

    /**
     * All executions will have MDC injected. {@code ThreadPoolExecutor}'s submission methods ({@code submit()} etc.)
     * all delegate to this.
     */
    @Override
    public void execute(Runnable command) {
        super.execute(wrap(command, getContextForTask()));
    }

    public static Runnable wrap(final Runnable runnable, final Map<String, Object> context) {
        return new Runnable() {
            @Override
            public void run() {
                Map previous = MDC.getCopyOfContextMap();
                if (context == null) {
                    MDC.clear();
                } else {
                    MDC.setContextMap(context);
                }
                try {
                    runnable.run();
                } finally {
                    if (previous == null) {
                        MDC.clear();
                    } else {
                        MDC.setContextMap(previous);
                    }
                }
            }
        };
    }
}
package com.mypackage.concurrent
导入org.apache.camel.util.concurrent.RejectableThreadPoolExecutor
导入org.slf4j.MDC;
导入java.util.Map;
导入java.util.concurrent.*;
/**
*与SLF4J MDC兼容的{@link ThreadPoolExecutor}。
*

*通常,MDC用于在每个线程变量中存储诊断信息(例如用户的会话id),以便于 *日志记录。然而,尽管MDC数据被传递给线程子级,但当线程在系统中被重用时,这不起作用 *线程池。这是{@link ThreadPoolExecutor}在每个任务之前适当设置MDC数据的替换。 *

*由broda20创建。 *日期:2015年10月29日 */ 公共类MdcThreadPoolExecutor扩展了RejectableThreadPoolExecutor{ @抑制警告(“未选中”) 私有映射getContextFortTask(){ 返回MDC.getCopyOfContextMap(); } 公共MdcThreadPoolExecutor(int-corePoolSize、int-maximumPoolSize、long-keepAliveTime、TimeUnit、, 阻塞队列(工作队列){ super(corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue); } 公共MdcThreadPoolExecutor(int-corePoolSize、int-maximumPoolSize、long-keepAliveTime、TimeUnit、, BlockingQueue工作队列,ThreadFactory ThreadFactory){ 超级(corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue、threadFactory); } 公共MdcThreadPoolExecutor(int-corePoolSize、int-maximumPoolSize、long-keepAliveTime、TimeUnit、, BlockingQueue工作队列,RejectedExecutionHandler){ super(corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue、handler); } 公共MdcThreadPoolExecutor(int-corePoolSize、int-maximumPoolSize、long-keepAliveTime、TimeUnit、, BlockingQueue工作队列、ThreadFactory ThreadFactory、RejectedExecutionHandler){ super(corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue、threadFactory、handler); } /** *所有执行都将注入MDC。{@code ThreadPoolExecutor}的提交方法({@code submit()}等) *所有人都同意这一点。 */ @凌驾 public void execute(Runnable命令){ execute(wrap(命令,getContextForTask()); } 公共静态可运行包装(最终可运行,最终映射上下文){ 返回新的Runnable(){ @凌驾 公开募捐{ Map previous=MDC.getCopyOfContextMap(); if(上下文==null){ MDC.clear(); }否则{ setContextMap(上下文); } 试一试{ runnable.run(); }最后{ 如果(上一个==null){ MDC.clear(); }否则{ MDC.setContextMap(先前版本); } } } }; } }

MDCSScheduledThreadPoolExecutor:

package com.mypackage.concurrent

import org.apache.camel.util.concurrent.RejectableThreadPoolExecutor
import org.slf4j.MDC;

import java.util.Map;
import java.util.concurrent.*;

/**
 * A SLF4J MDC-compatible {@link ThreadPoolExecutor}.
 * <p/>
 * In general, MDC is used to store diagnostic information (e.g. a user's session id) in per-thread variables, to facilitate
 * logging. However, although MDC data is passed to thread children, this doesn't work when threads are reused in a
 * thread pool. This is a drop-in replacement for {@link ThreadPoolExecutor} sets MDC data before each task appropriately.
 * <p/>
 * Created by broda20.
 * Date: 10/29/15
 */
public class MdcThreadPoolExecutor extends RejectableThreadPoolExecutor {

    @SuppressWarnings("unchecked")
    private Map<String, Object> getContextForTask() {
        return MDC.getCopyOfContextMap();
    }

    public MdcThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
                                        BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }

    public MdcThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
                                        BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
    }

    public MdcThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
                                        BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
    }

    public MdcThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
                                        BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
    }

    /**
     * All executions will have MDC injected. {@code ThreadPoolExecutor}'s submission methods ({@code submit()} etc.)
     * all delegate to this.
     */
    @Override
    public void execute(Runnable command) {
        super.execute(wrap(command, getContextForTask()));
    }

    public static Runnable wrap(final Runnable runnable, final Map<String, Object> context) {
        return new Runnable() {
            @Override
            public void run() {
                Map previous = MDC.getCopyOfContextMap();
                if (context == null) {
                    MDC.clear();
                } else {
                    MDC.setContextMap(context);
                }
                try {
                    runnable.run();
                } finally {
                    if (previous == null) {
                        MDC.clear();
                    } else {
                        MDC.setContextMap(previous);
                    }
                }
            }
        };
    }
}
package com.mypackage.concurrent

import org.apache.camel.util.concurrent.RejectableScheduledThreadPoolExecutor
import org.slf4j.MDC;

import java.util.Map;
import java.util.concurrent.*;

/**
 * A SLF4J MDC-compatible {@link ThreadPoolExecutor}.
 * <p/>
 * In general, MDC is used to store diagnostic information (e.g. a user's session id) in per-thread variables, to facilitate
 * logging. However, although MDC data is passed to thread children, this doesn't work when threads are reused in a
 * thread pool. This is a drop-in replacement for {@link ThreadPoolExecutor} sets MDC data before each task appropriately.
 * <p/>
 * Created by broda20.
 * Date: 10/29/15
 */
public class MdcScheduledThreadPoolExecutor extends RejectableScheduledThreadPoolExecutor {

    @SuppressWarnings("unchecked")
    private Map<String, Object> getContextForTask() {
        return MDC.getCopyOfContextMap();
    }

    public MdcScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize);
    }

    public MdcScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory) {
        super(corePoolSize, threadFactory);
    }

    public MdcScheduledThreadPoolExecutor(int corePoolSize, RejectedExecutionHandler handler) {
        super(corePoolSize, handler);
    }

    public MdcScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
        super(corePoolSize, threadFactory, handler);
    }

    /**
     * All executions will have MDC injected. {@code ThreadPoolExecutor}'s submission methods ({@code submit()} etc.)
     * all delegate to this.
     */
    @Override
    public void execute(Runnable command) {
        super.execute(wrap(command, getContextForTask()));
    }

    public static Runnable wrap(final Runnable runnable, final Map<String, Object> context) {
        return new Runnable() {
            @Override
            public void run() {
                Map previous = MDC.getCopyOfContextMap();
                if (context == null) {
                    MDC.clear();
                } else {
                    MDC.setContextMap(context);
                }
                try {
                    runnable.run();
                } finally {
                    if (previous == null) {
                        MDC.clear();
                    } else {
                        MDC.setContextMap(previous);
                    }
                }
            }
        };
    }
}
package com.mypackage.concurrent
导入org.apache.camel.util.concurrent.RejectableScheduledThreadPoolExecutor
导入org.slf4j.MDC;
导入java.util.Map;
导入java.util.concurrent.*;
/**
*与SLF4J MDC兼容的{@link ThreadPoolExecutor}。
*

*通常,MDC用于在每个线程变量中存储诊断信息(例如用户的会话id),以便于 *日志记录。然而,尽管MDC数据被传递给线程子级,但当线程在系统中被重用时,这不起作用 *线程池。这是{@link ThreadPoolExecutor}在每个任务之前适当设置MDC数据的替换。 *

*由broda20创建。 *日期:2015年10月29日 */ 公共类MDCSScheduledThreadPoolExecutor扩展了RejectableScheduledThreadPoolExecutor{ @抑制警告(“未选中”) 私有映射getContextFortTask(){ 返回MDC.getCopyOfContextMap(); } 公共MdcScheduledThreadPoolExecutor(int corePoolSize){ 超级(核心池大小); } 公共MDCSScheduledThreadPoolExecutor(int corePoolSize,ThreadFactory ThreadFactory){ 超级(corePoolSize,threadFactory); } 公共MdcScheduledThread