java - Spring Sleuth - JMS ErrorHandler 上的跟踪中断
问题描述
我有一个使用 Spring Sleuth 和 JMS的简单示例https://github.com/gtiwari333/sleuth-jms-broken-tracing/tree/master 。
在这里,对/jms
端点的调用将消息排入队列,并且在onMessage
方法处收到消息后,我们正在对 GET 调用/test
并抛出MyException
. 我们希望跟踪 id 传递给 ,ErrorHandler
以便我们在 、 、 和端点之间的日志中看到/jms
相同onMessage()
的handleError()
traceId /test
。
我现在得到什么/如何得到错误:
我运行了应用程序并点击了localhost:8080/jms
端点。在下面的日志中,TraceId 没有在JmsListenerErrorHandler
类中传播,并且为 GET 调用创建了一个新的 TraceId/test
2020-08-04 17:55:24.212 INFO [,225c47fb814f6584,225c47fb814f6584,true] 16956 --- [nio-8080-exec-1] sleuth.SleuthApplication : Queuing message ...
2020-08-04 17:55:24.282 INFO [,225c47fb814f6584,eac851f1650ae8a6,true] 16956 --- [enerContainer-1] sleuth.SleuthApplication : JMS message received SOME MESSAGE !!!
2020-08-04 17:55:24.321 INFO [,225c47fb814f6584,612a7956f6b29a01,true] 16956 --- [nio-8080-exec-3] sleuth.SleuthApplication : test1 called
<<<<<<<<< FINE UPTO HERE
2020-08-04 17:55:24.332 INFO [,,,] 16956 --- [enerContainer-1] sleuth.SleuthApplication : handling error by calling another endpoint ..
<<<<<<<<< new thread started and lost tracing
2020-08-04 17:55:24.336 INFO [,4c163d0997076729,4c163d0997076729,true] 16956 --- [nio-8080-exec-2] sleuth.SleuthApplication : test1 called
<<<<<<<<< new trace id received
它看起来 JMS 在新线程中处理新消息的接收/处理。Sleuth 具有必要的“仪器”逻辑来拦截 Trace/Span id 并将其传播到@JmsListener
代码,但它不会传播到org.springframework.util.ErrorHandler
.
- org.springframework.jms.listener.DefaultMessageListenerContainer.AsyncMessageListenerInvoker
- org.springframework.jms.listener.AbstractPollingMessageListenerContainer#doReceiveAndExecute
编码:
@RestController 和 @JmsListener:
@RestController
static class Ctrl {
@Autowired RestTemplate restTemplate;
@Autowired JmsTemplate jmsTemplate;
@GetMapping("/test")
void test() {
log.info("test1 called");
}
@GetMapping("/jms")
void jms() {
log.info("Queuing message ...");
jmsTemplate.convertAndSend("test-queue", "SOME MESSAGE !!!");
}
@JmsListener(destination = "test-queue", concurrency = "5")
void onMessage(TextMessage message) throws JMSException {
log.info("JMS message received {}", message.getText());
restTemplate.getForEntity("http://localhost:8080/test", Void.class); //-->it works
throw new MyException("Some Error"); //-->it doesn't
}
static class MyException extends RuntimeException {
public MyException(String msg) { super(msg); }
}
}
错误处理程序:
@Component
static class JmsListenerErrorHandler implements ErrorHandler {
@Autowired RestTemplate restTemplate;
@Override
public void handleError(Throwable t) {
log.info("handling error by calling another endpoint .."); //1....tracing is lost here
restTemplate.getForEntity("http://localhost:8080/test", Void.class);
}
}
JMS 配置:
@Configuration
@EnableJms
static class ActiveMqConfig implements JmsListenerConfigurer {
@Autowired ErrorHandler jmsListenerErrorHandler;
@Autowired ConnectionFactory connectionFactory;
@Override
public void configureJmsListeners(JmsListenerEndpointRegistrar registrar) {
registrar.setContainerFactory(containerFactory());
}
@Bean
JmsListenerContainerFactory<?> containerFactory() {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
factory.setErrorHandler(jmsListenerErrorHandler);
return factory;
}
}
我尝试了什么:(使它成为一个完整的问题)
它在 PR 中:https ://github.com/gtiwari333/sleuth-jms-broken-tracing/pull/1/files
在这里,我尝试使用创建一个自定义的 Executor bean 包装LazyTraceThreadPoolTaskExecutor
并尝试将其传递给JmsListenerContainerFactory
它适用于正常的线程执行,但不适用于 JMS 的东西。
executor.execute(() -> log.info("Im inside thread 2")); //it works
有人已经想出如何拦截 ErrorHandler 来传递 TraceId 了吗?
解决方案
关于. _ _ @JmsListener
所以我猜目前不支持。
一个可能的解决方案是传递Span
异常:
@RestController
static class Ctrl {
@Autowired
private Tracer tracer;
// ...
@JmsListener(destination = "test-queue", concurrency = "5")
void onMessage(TextMessage message) throws JMSException{
//..
throw new MyException("Some Error",tracer.currentSpan()); // <-- pass current span
}
}
所以你可以得到它JmsListenerErrorHandler
:
@Override
public void handleError(Throwable t) {
if(t.getCause() instanceof MyException){
MyException mEx = (MyException) t.getCause();
log.info("Failing span: {}",mEx.getSpan());
}
//...
}
MyException
班级:
class MyException extends RuntimeException {
private final Span span;
public MyException(String msg, Span span) {
super(msg);
this.span=span;
}
// Getter for the Span
}
推荐阅读
- r - 如何从字符串中提取时间?
- javascript - 为什么 localStorage 返回一个字符串值,其大小写为 null 且未定义
- angular - 使用 async/await 时返回默认值的错误处理程序
- java - 我认为我的 BFS 将所有有效坐标添加到列表中,而不仅仅是最短路径
- angular - 带有innerHTML的Angular 7反应式表单
- java - 如何将程序的输出写入excel表格
- sap-business-bydesign - SAP ByD in code Customer Invoice Request to Customer Invoice
- firebase - 当只有经过身份验证的用户可以阅读文档时,如何检查文档是否作为未经身份验证的用户存在于集合中
- java - GUAVA CACHE - 动态计算权重
- java - 无法从请求正文中读取