我的目标是在计划方法上仅使用 @Scheduled 注释,并且跟踪应该自动发生(无论是 log.info() 还是异常)。
我尝试通过创建自定义 TaskDecorator 来实现这一点,但它不起作用。
调度程序配置:
@Configuration
@RequiredArgsConstructor
@EnableScheduling
public class SchedulerConfiguration {
private final ObservationRegistry observationRegistry;
@Value("${spring.task.scheduling.pool.size}")
private Integer taskSchedulingPoolSize;
@Bean
public TaskScheduler taskScheduler() {
ConcurrentTaskScheduler scheduler = new ConcurrentTaskScheduler(new ScheduledThreadPoolExecutor(taskSchedulingPoolSize));
scheduler.setTaskDecorator(new ExecutorTaskDecorator(observationRegistry));
scheduler.setErrorHandler(new ExceptionHandler());
return scheduler;
}
}
观察配置:
@Configuration
public class ObservationConfiguration {
@Bean
ObservedAspect observedAspect(ObservationRegistry observationRegistry) {
return new ObservedAspect(observationRegistry);
}
}
异常处理程序:
@Slf4j
public class ExceptionHandler implements ErrorHandler {
@Override
public void handleError(Throwable t) {
log.error("Task threw an exception: {}", t.getMessage(), t);
}
}
@Scheduled(initialDelay = 0, fixedDelay = 1000")
public void start() {
throw new RunTimeException("test");
}
任务装饰器的第一种方法:
public class ExecutorTaskDecorator implements TaskDecorator {
private final ObservationRegistry observationRegistry;
public ExecutorTaskDecorator(ObservationRegistry observationRegistry) {
this.observationRegistry = observationRegistry;
}
@Override
public Runnable decorate(Runnable runnable) {
return Observation.createNotStarted("task.run", observationRegistry)
.observe(() -> runnable::run);
}
}
任务装饰器的第二种方法:
public class ExecutorTaskDecorator implements TaskDecorator {
@Override
public Runnable decorate(Runnable runnable) {
return runWithObserved(runnable);
}
@Observed
private Runnable runWithObserved(Runnable runnable) {
return () -> runnable.run();
}
}
这两种方法都不起作用。
TraceId 和 SpanId 仅当我将 @Observed 添加到
start()
方法并用 try catch 块包装时才会发生。
我正在使用 spring boot 3.1.3、spring-boot-starter-actuator (3.1.3) 和 micrometer-tracing-bridge-brave (1.1.4)。
我错过了什么吗? 甚至可以这样使用它吗? 对于 HTTP 请求,一切正常。
感谢 @m-deinum 的建议,我使用方面完成了这项工作。
@Aspect
@Component
@RequiredArgsConstructor
@Slf4j
public class ScheduledAspect {
private final ObservationRegistry observationRegistry;
@Pointcut("@annotation(org.springframework.scheduling.annotation.Scheduled)")
public void annotatedWithScheduled() {}
@Around("annotatedWithScheduled()")
public Object wrapScheduled(ProceedingJoinPoint pjp) {
var methodName = pjp.getSignature().getDeclaringTypeName() + "." + pjp.getSignature().getName();
return Observation.createNotStarted(methodName, observationRegistry)
.observe(() -> proceed(pjp));
}
private Object proceed(ProceedingJoinPoint pjp) {
try {
return pjp.proceed();
} catch (Throwable t) {
log.error("Task threw an exception: {}", t.getMessage(), t);
}
return null;
}
}