【问题标题】:Apache Camel MDC add field from BodyApache Camel MDC 从 Body 添加字段
【发布时间】:2015-03-14 04:20:59
【问题描述】:

我正在使用 apache camel,并希望使用 MDC 将某些键添加到我的日志中。我通过了官方Camel MDC Logging documentation,这非常棒。我可以毫不费力地记录我的 routeId。我还需要从 Camel's Body 中添加一个字段。

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

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

更新:

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

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

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

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

【问题讨论】:

    标签: apache logging apache-camel


    【解决方案1】:

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

    自动注册一个简单的 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}
    

    它应该开始记录

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

      • 感谢克劳斯的快速响应。这看起来是正确的方向。我实现了我的自定义 MDCUnitOfWork。并且能够在行动中看到它。请查看我更新的相关部分。
      • 查看 MDCUnitOfWork - 覆盖当 UoW 进入离开路由时调用的推送/弹出路由上下文。
      • 感谢克劳斯,我能够覆盖方法“beforeProcess”,我相信该方法也会在执行路由之前执行。按预期工作。谢谢。
      【解决方案3】:

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

      您必须将 MDCLogging 设置为 true 并实现您自己的 UnitOfWork,就像在之前的 cmets 中显示的那样:

       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 类,您会发现代码非常相似。

      【讨论】:

        【解决方案4】:

        我们希望我们的 Camel 路由具有类似的功能 - 使用 MDC 记录特定的属性和标头。不幸的是,我们的路线已被处理,而 CustomMDCUnitOfWork 没有启动。我们最终实现了 org.apache.camel.spi.InterceptStrategy 以添加 MDC 值。如果有更好的方法来处理交易路线,我会很高兴知道..!

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-08-17
          • 1970-01-01
          • 2016-02-26
          • 2014-05-10
          • 1970-01-01
          相关资源
          最近更新 更多