Apache Camel MDC从Body添加字段

时间:2015-03-14 04:20:59

标签: apache logging apache-camel

我正在使用apache camel并希望使用MDC将某些密钥添加到我的日志中。我经历了官方Camel MDC Logging documentation,这非常棒。我能够毫不费力地记录我的routeId。我还需要添加Camel's Body的字段。

最糟糕的情况我可以在所有路由中手动添加它,但我想知道是否可以更容易地从body添加字段到MDC?

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

更新

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

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

在我的用例中,我正在将Amazon SQS作为我的第一条路线。我这里没有所需的信息。在第一个路径中,我构建了我的Context并将其设置为Camel body,这是我需要在MDC中设置的信息所在的位置。

是否可以在第二条路线之前创建UnitOfWork?

4 个答案:

答案 0 :(得分:8)

这是一个完整的实现,其代码基于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}

它应该开始记录

答案 1 :(得分:4)

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

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

答案 2 :(得分:1)

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

您必须将MDCLogging设置为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类,您会发现代码非常相似。

答案 3 :(得分:0)

我们希望Camel路由中有类似的东西 - 使用MDC记录特定属性和标题。不幸的是我们的路由被处理了,而且CustomMDCUnitOfWork没有开始。我们最终实现了一个org.apache.camel.spi.InterceptStrategy以便添加MDC值。如果通过交易路线有更好的方法,我很乐意知道..!