Apache Camel MDC 从 Body 添加字段



我正在使用 apache camel,并希望使用 MDC 将某些键添加到我的日志中。我浏览了官方的骆驼MDC日志记录文档,这非常棒。我可以毫不费力地记录我的路由 ID。我还需要从骆驼的身体添加一个字段。

最坏的情况 我可以在所有路由中手动添加它,但我想知道是否可以以更简单的方式将字段从正文添加到 MDC?

任何想法都值得赞赏。我真的希望能够做到这一点,而不必进入每条路线并添加一条班轮。

更新:

在我的项目中实现了自定义MDCUnitOfWork和工厂。我能够看到CustomUnitOfWorkFactory正在创建我的CustomUnitOfWork,然后设置MDC值。

但是我注意到这只发生在路线的开头。

在我的使用案例中,我将轮询 Amazon SQS 作为我的第一个路由。我这里没有所需的信息。在第一条路线中,我构建我的上下文并将其设置为骆驼体,这是我需要在 MDC 中设置的信息所在的位置。

是否可以在第二条路线之前创建工作单元?

这是一个完整的实现,其中包含基于 Claus 建议的代码。我们使用的是弹簧靴,但根据您的需要进行调整

自动注册一个简单的 bean

@Bean
public CamelContextConfiguration contextConfiguration() {
    return new CamelContextConfiguration() {
        @Override
        public void beforeApplicationStart(CamelContext context) {
            context.setUseMDCLogging(true);
            context.setUnitOfWorkFactory(MyUnitOfWork::new);
        }
        @Override
        public void afterApplicationStart(CamelContext camelContext) {
        }
    };
}

然后,创建自定义工作单元类

public class MyUnitOfWork extends MDCUnitOfWork {
    public MyUnitOfWork(Exchange exchange) {
        super(exchange);
        if( exchange.getProperty("myProp") != null){
            MDC.put("myProp", (String) exchange.getProperty("myProp"));
        }
    }
}

在您的 logback/log4j 配置中使用值 myProp,如下所示:

%X{myProp}

它应该开始日志记录

我在 MDC 中缺少标题时遇到了问题,并且之前评论中提供的解决方案不起作用。这是我的情况的一个有效解决方案:除默认标头外的所有标头都在线程之间丢失(MDC 是线程本地)。由于 Camel MDCUnitOfWork 默认的实现存在缺陷,因此传递给另一个线程中的 MDC 的唯一标头是默认的 Camel 标头。

您必须将MDCLoging设置为true并实现自己的UnitOfWork,就像前面的评论所示:

 camelContext.setUseMDCLogging(true);
 camelContext.setUnitOfWorkFactory(CustomUnitOfWork::new);

CustomUnitOfWork 的实现要复杂得多,因为我们需要覆盖很多 MDCUnitOfWork 行为(确保导入 org.slf4j.MDC):

class CustomUnitOfWork extends MDCUnitOfWork {
static final String CUSTOM_FIELD_NAME = "customField";
private String customField;
CustomUnitOfWork(Exchange exchange) {
    super(exchange);
    customField = (String) exchange.getIn().getHeader("customFieldPath123");
    MDC.put(CUSTOM_FIELD_NAME, customField);
}
@Override
public UnitOfWork newInstance(Exchange exchange) {
    return new CustomUnitOfWork(exchange);
}
@Override
public void clear() {
    super.clear();
    if (customField != null) {
        MDC.put(CUSTOM_FIELD_NAME, customField);
    } else {
        MDC.remove(CUSTOM_FIELD_NAME);
    }
}
@Override
public void stop() throws Exception {
    super.stop();
    clear();
}
@Override
public AsyncCallback beforeProcess(Processor processor, Exchange exchange, AsyncCallback callback) {
    return new CustomMDCCallback(callback);
}
private class CustomMDCCallback implements AsyncCallback {
    private final AsyncCallback delegate;
    private final String breadcrumbId;
    private final String exchangeId;
    private final String messageId;
    private final String correlationId;
    private final String routeId;
    private final String camelContextId;
    private final String customField;

    private CustomMDCCallback(AsyncCallback delegate) {
        this.delegate = delegate;
        this.exchangeId = MDC.get(MDC_EXCHANGE_ID);
        this.messageId = MDC.get(MDC_MESSAGE_ID);
        this.breadcrumbId = MDC.get(MDC_BREADCRUMB_ID);
        this.correlationId = MDC.get(MDC_CORRELATION_ID);
        this.camelContextId = MDC.get(MDC_CAMEL_CONTEXT_ID);
        this.routeId = MDC.get(MDC_ROUTE_ID);
        this.customField = MDC.get(CUSTOM_FIELD_NAME);
    }
    @Override
    public void done(boolean doneSync) {
        try {
            if (!doneSync) {
                checkAndPut(breadcrumbId, MDC_BREADCRUMB_ID);
                checkAndPut(exchangeId, MDC_EXCHANGE_ID);
                checkAndPut(messageId, MDC_MESSAGE_ID);
                checkAndPut(correlationId, MDC_CORRELATION_ID);
                checkAndPut(camelContextId, MDC_CAMEL_CONTEXT_ID);
                checkAndPut(customField, CUSTOM_FIELD_NAME);
            }
            checkAndPut(routeId, MDC_ROUTE_ID);
        } finally {
            delegate.done(doneSync);
        }
    }
    private void checkAndPut(String value, String fieldName) {
        if (value != null) {
            MDC.put(fieldName, value);
        }
    }
}
}

如果你看一下Camel MDCUnitOfWork类,你会发现代码非常相似。

您可以配置自定义UnitOfWorkFactory以创建自定义UnitOfWork以扩展MDCUnitOfWork,您可以在其中将自定义信息添加到 MDC。

  • http://camel.apache.org/maven/current/camel-core/apidocs/org/apache/camel/impl/MDCUnitOfWork.html
  • http://camel.apache.org/maven/current/camel-core/apidocs/org/apache/camel/spi/UnitOfWorkFactory.html

您可以从Java或在XML中在CamelContext上配置UnitOfWorkFactory,只需添加一个<bean>,Camel就会检测并使用它

  • http://camel.apache.org/advanced-configuration-of-camelcontext-using-spring.html

我们希望从我们的骆驼路线中得到类似的东西 - 使用 MDC 记录特定的属性和标头。 不幸的是,我们的路线被交易了,CustomMDCUnitOfWork没有启动。 我们最终实现了一个org.apache.camel.spi.InterceptStrategy,以添加MDC值。 如果有更好的方法可以通过交易路线做到这一点,我将很高兴知道..!

最新更新