简体   繁体   English

Apache Camel MDC 从 Body 添加字段

[英]Apache Camel MDC add field from Body

I am working with apache camel and would like to add certain keys to my logs using MDC.我正在使用 apache camel,并想使用 MDC 将某些键添加到我的日志中。 I went through the official Camel MDC Logging documentation which is pretty great.我浏览了官方的Camel MDC Logging 文档,非常棒。 I am able to log my routeId's without much effort.我可以毫不费力地记录我的 routeId。 I also need to add a field from Camel's Body.我还需要从 Camel's Body 添加一个字段。

Worst case scenario I can add this manually in all routes, but I was wondering if its possible to add fields from body to MDC in a easier fashion?最坏的情况我可以在所有路由中手动添加它,但我想知道是否可以以更简单的方式将字段从 body 添加到 MDC?

Any ideas are appreciated.任何想法表示赞赏。 I would really like to be able to do this without having to go into every route and adding a one liner.我真的很想能够做到这一点,而不必进入每条路线并添加一个班轮。

Update:更新:

Implemented a custom MDCUnitOfWork and Factory in my project.在我的项目中实现了自定义 MDCUnitOfWork 和 Factory。 I am able to see the CustomUnitOfWorkFactory creating my CustomUnitOfWork which is then setting the MDC values.我能够看到 CustomUnitOfWorkFactory 创建我的 CustomUnitOfWork 然后设置 MDC 值。

However I noticed this only happens in the beginning of the route.但是我注意到这只发生在路线的开头。

In my use case, I am Polling an Amazon SQS as my first route.在我的用例中,我将轮询 Amazon SQS 作为我的第一条路线。 I do not have the required information here.我这里没有所需的信息。 In the first route I build my Context and set that to Camel body which is where my information that I need to set in MDC resides.在第一条路线中,我构建了我的 Context 并将其设置为 Camel body,这是我需要在 MDC 中设置的信息所在的位置。

Is it possible to create UnitOfWork before second route as well?是否也可以在第二条路线之前创建 UnitOfWork?

Here is a full implementation with code based on Claus's recommendation.这是基于 Claus 建议的代码的完整实现。 We are using spring boot, but adjust according to your needs我们使用的是弹簧靴,但根据您的需要进行调整

Auto register a simple bean自动注册一个简单的 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) {
        }
    };
}

Then, create your custom unit of work class然后,创建您的自定义工作单元单元

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

In your logback/log4j configuration use the value myProp like so:在您的 logback/log4j 配置中,使用 myProp 值,如下所示:

%X{myProp}

It should start logging它应该开始记录

You can configure a custom UnitOfWorkFactory to create a custom UnitOfWork that extends the MDCUnitOfWork , where you can add custom information to MDC.您可以配置自定义UnitOfWorkFactory以创建扩展MDCUnitOfWork的自定义UnitOfWork ,您可以在其中向 MDC 添加自定义信息。

You can configure the UnitOfWorkFactory on CamelContext from Java or in XML just add a <bean> and Camel detects and uses it您可以从 Java 或在 XML 中配置 CamelContext 上的 UnitOfWorkFactory 只需添加一个<bean>和 Camel 检测并使用它

I had an issue with missing headers in MDC and the solutions provided here in earlier comments didn't work.我遇到了 MDC 中缺少标头的问题,之前评论中提供的解决方案不起作用。 Here's a working solution to my case: all headers except default headers are being lost between threads (MDC is thread local).这是针对我的情况的有效解决方案:除默认标头之外的所有标头都在线程之间丢失(MDC 是线程本地的)。 Because of Camel MDCUnitOfWork default flawed implementation the only headers passed to an MDC in another thread are default Camel headers.由于 Camel MDCUnitOfWork 默认有缺陷的实现,在另一个线程中传递给 MDC 的唯一标头是默认的 Camel 标头。

You have to setMDCLogging to true and implement your own UnitOfWork like it was shown in previous comments:您必须将 MDCLogging 设置为 true 并实现您自己的 UnitOfWork,就像之前的评论中所示:

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

The implementation of the CustomUnitOfWork is a lot more complicated, because we need to override a lot of deafult MDCUnitOfWork behavior (make sure to import org.slf4j.MDC): 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);
        }
    }
}
}

If you take a look at Camel MDCUnitOfWork class you will see that the code is very similar.如果您查看 Camel MDCUnitOfWork 类,您会发现代码非常相似。

we wanted a similar thing from our Camel routes - to log particular properties and headers using MDC.我们想从我们的 Camel 路由中得到类似的东西 - 使用 MDC 记录特定的属性和标头。 Unfortunately our routes were transacted and the CustomMDCUnitOfWork was not kicking in. We ended up implementing an org.apache.camel.spi.InterceptStrategy in order to add the MDC values.不幸的是,我们的路由被处理了,CustomMDCUnitOfWork 没有启动。我们最终实现了一个 org.apache.camel.spi.InterceptStrategy 以添加 MDC 值。 If there is a better way of doing this with transacted routes I would be happy to know..!如果有更好的方法来处理交易路线,我很高兴知道..!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM