Apache Camel MDC 从 Body 添加字段
Apache Camel MDC add field from Body
我正在使用 apache camel 并希望使用 MDC 将某些键添加到我的日志中。我浏览了官方 Camel MDC Logging documentation 非常棒。我可以毫不费力地记录我的 routeId。我还需要从 Camel's Body 添加一个字段。
最坏的情况我可以在所有路由中手动添加它,但我想知道是否有可能以更简单的方式将字段从正文添加到 MDC?
欢迎任何想法。我真的很希望能够做到这一点,而不必进入每条路线并添加一个班轮。
更新:
在我的项目中实现了自定义 MDCUnitOfWork 和工厂。我能够看到 CustomUnitOfWorkFactory 创建我的 CustomUnitOfWork,然后设置 MDC 值。
但是我注意到这只发生在路线的开头。
在我的用例中,我轮询 Amazon SQS 作为我的第一条路线。我这里没有所需的信息。在第一条路线中,我构建了我的 Context 并将其设置为 Camel body,这是我需要在 MDC 中设置的信息所在的位置。
是否也可以在第二条路线之前创建 UnitOfWork?
您可以配置自定义 UnitOfWorkFactory
以创建扩展 MDCUnitOfWork
的自定义 UnitOfWork
,您可以在其中向 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 会检测并使用它
我们想从我们的 Camel 路由中获得类似的东西 - 记录特定属性并 headers 使用 MDC。不幸的是,我们的路由被处理了,CustomMDCUnitOfWork 没有启动。我们最终实现了一个 org.apache.camel.spi.InterceptStrategy 来添加 MDC 值。如果有更好的方法来处理交易路线,我很乐意知道..!
这是基于克劳斯推荐的代码的完整实现。我们使用的是spring开机,不过根据你的需要调整
自动注册一个简单的 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) {
}
};
}
然后,创建您的自定义工作单元class
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 中缺少 headers 的问题,之前评论中提供的解决方案无效。这是针对我的情况的有效解决方案:除默认 headers 之外的所有 headers 都在线程之间丢失(MDC 是线程本地的)。由于 Camel MDCUnitOfWork 默认实现有缺陷,在另一个线程中传递给 MDC 的唯一 headers 是默认的 Camel headers.
您必须将 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 class,您会发现代码非常相似。
我正在使用 apache camel 并希望使用 MDC 将某些键添加到我的日志中。我浏览了官方 Camel MDC Logging documentation 非常棒。我可以毫不费力地记录我的 routeId。我还需要从 Camel's Body 添加一个字段。
最坏的情况我可以在所有路由中手动添加它,但我想知道是否有可能以更简单的方式将字段从正文添加到 MDC?
欢迎任何想法。我真的很希望能够做到这一点,而不必进入每条路线并添加一个班轮。
更新:
在我的项目中实现了自定义 MDCUnitOfWork 和工厂。我能够看到 CustomUnitOfWorkFactory 创建我的 CustomUnitOfWork,然后设置 MDC 值。
但是我注意到这只发生在路线的开头。
在我的用例中,我轮询 Amazon SQS 作为我的第一条路线。我这里没有所需的信息。在第一条路线中,我构建了我的 Context 并将其设置为 Camel body,这是我需要在 MDC 中设置的信息所在的位置。
是否也可以在第二条路线之前创建 UnitOfWork?
您可以配置自定义 UnitOfWorkFactory
以创建扩展 MDCUnitOfWork
的自定义 UnitOfWork
,您可以在其中向 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 会检测并使用它
我们想从我们的 Camel 路由中获得类似的东西 - 记录特定属性并 headers 使用 MDC。不幸的是,我们的路由被处理了,CustomMDCUnitOfWork 没有启动。我们最终实现了一个 org.apache.camel.spi.InterceptStrategy 来添加 MDC 值。如果有更好的方法来处理交易路线,我很乐意知道..!
这是基于克劳斯推荐的代码的完整实现。我们使用的是spring开机,不过根据你的需要调整
自动注册一个简单的 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) {
}
};
}
然后,创建您的自定义工作单元class
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 中缺少 headers 的问题,之前评论中提供的解决方案无效。这是针对我的情况的有效解决方案:除默认 headers 之外的所有 headers 都在线程之间丢失(MDC 是线程本地的)。由于 Camel MDCUnitOfWork 默认实现有缺陷,在另一个线程中传递给 MDC 的唯一 headers 是默认的 Camel headers.
您必须将 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 class,您会发现代码非常相似。