Apache Camel调用pollEnrich后如何打印correlationId(exchangeId)
问题描述
Apache Camel路由处理邮件内容场景下,已通过getContext().setUseMDCLogging(true);开启MDC日志功能,在logback.xml中通过%X{camel.exchangeId}配置打印关联ID(即exchangeId)。但调用pollEnrich()方法后,原exchangeId 95C1D8CE0CF95D7-0000000000000001 无法在后续日志中输出,对应日志位置的%X{camel.exchangeId}取值为空。
现有配置
路由代码
@Override public void configure() throws Exception { getContext().setUseMDCLogging(true); from("direct:process_polling_email") .log("Hello World") .routeId("routeId_123456789") .doTry() .log("doTry: exchangeProperty.subject - ${exchangeProperty.subject}") .pollEnrich().simple("...." + "?username={{imap.username}}&" + "password={{imap.password}}&" +"folderName={{imap.fetch.folder}}&" +"copyTo={{imap.tocopy.folder}}&" +"searchTerm.subject=${exchangeProperty.subject}&" +"fetchSize=1&" +"searchTerm.unseen=true&" + "closeFolder=false&" + "disconnect=false&" +"sendEmptyMessageWhenIdle=true&" +"bridgeErrorHandler=true") .endDoTry() .log("After pollEnrich "); }
logback.xml配置
<encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} %X{camel.exchangeId} - %msg%n</pattern> </encoder>
实际日志输出
2022-06-03 13:39:00 [Camel (camel-1) thread #6 - INFO routeId_123456789 95C1D8CE0CF95D7-0000000000000001 - doTry: exchangeProperty.subject - Hello World 2022-06-03 13:39:01 [Camel (camel-1) thread #6 - INFO routeId_123456789 - After pollEnrich
问题原因
pollEnrich是Camel的内容增强EIP,默认行为是用拉取到的新Exchange直接替换原路由中的Exchange实例。Camel的MDC日志上下文是和当前Exchange绑定的,默认聚合策略不会自动把原Exchange的MDC属性、exchangeId传递给新Exchange,同时部分旧版本Camel存在pollEnrich执行后MDC上下文未正确回填的已知问题,最终导致后续日志无法获取到camel.exchangeId的值。
解决方案
可根据实际场景选择以下任意一种方案修复:
- 方案1:显式指定聚合策略,手动传递上下文
给pollEnrich添加自定义聚合策略,在合并新旧Exchange时手动保留原exchangeId并回填MDC,适配所有Camel版本,示例代码:.pollEnrich() .simple("你的IMAP端点完整URI") .aggregateStrategy((oldExchange, newExchange) -> { // 适配sendEmptyMessageWhenIdle=true返回空的场景 if (newExchange == null) { return oldExchange; } // 保留原Exchange的ID String originalExchangeId = oldExchange.getExchangeId(); // 复制原Exchange的全部属性到新Exchange newExchange.getProperties().putAll(oldExchange.getProperties()); // 手动回填MDC中的exchangeId MDC.put("camel.exchangeId", originalExchangeId); return newExchange; }) - 方案2:升级Camel版本
Camel 3.14及以上LTS版本已修复pollEnrich类EIP执行后MDC上下文丢失的问题,升级后无需额外编码即可自动传递camel.exchangeId到后续日志。 - 方案3:pollEnrich执行后手动恢复MDC值
如果不需要修改聚合逻辑,可以在pollEnrich前后加简单处理,手动把exchangeId写回MDC:// 先把原exchangeId存为Exchange属性 .setProperty("originalExchangeId", exchangeProperty("CamelExchangeId")) .pollEnrich().simple("你的IMAP端点完整URI") // 执行后手动回填MDC .process(exchange -> { String originalId = exchange.getProperty("originalExchangeId", String.class); MDC.put("camel.exchangeId", originalId); }) - 方案4:配置MDC键传递规则
除了开启MDC日志外,额外配置MDC键的传递匹配规则,让Camel自动传递所有camel开头的上下文属性:
该方案在Camel 3.x以上部分版本可直接解决问题,不需要修改路由逻辑。getContext().setUseMDCLogging(true); // 新增配置,匹配所有camel开头的MDC键做跨节点传递 getContext().setMDCLoggingKeysPattern("camel.*");
内容的提问来源于stack exchange,提问作者benz
相关产品推荐
相关产品推荐

