Search code examples
springspring-bootaopspring-aop

Log ApplicationEventPublisher.publishEvent() calls


I've got an Spring Boot 2.2 Application which publishes and consumes spring application events in different packages. Now I want to log every time an event has been published by ApplicationEventPublisher.publishEvent().

One solution could be to write my own event publisher like:

public class LoggableApplicationEventPublisher implements ApplicationEventPublisher {

    private final ApplicationEventPublisher eventPublisher;
    private final Logger logger;

    public ApplicationEventLogger(ApplicationEventPublisher eventPublisher, Logger logger) {

        this.eventPublisher = eventPublisher;
        this.logger = logger;
    }


    @Override
    public void publishEvent(ApplicationEvent event) {

        eventPublisher.publishEvent(event);
        logger.info("--> Emitting {}", event);
    }
}

Another solution could be to use aspect oriented programming and write an Aspect which is triggered everytime publishEvent() has been triggered:

@Aspect
@Component
public class EventPublishAspect {

    private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

    @Pointcut("execution(* org.springframework.context.ApplicationEventPublisher.*(..))")
    public void logPublishEvent() {
    }


    @After("logPublishEvent()")
    public void log(JoinPoint point) {

        Object[] lArgs = point.getArgs();
        LOG.info("Triggered", lArgs[0]);
    }
}

I've set up all correctly (dependencies aswell) and this example is working for other pointcuts (like for a call of specific method of my services).

However, this aspect is not working with the declared pointcut for the ApplicationEventPublisher-Interface. Do you know why not? It seems like spring boot injects AbstractApplicationContext on runtime, which is actually implementing this interface.


Solution

  • Solution that does not require aspects (and has faster startup time?)

        @Primary
        @Bean
        DelegatingApplicationEventPublisher applicationEventPublisher(ApplicationContext applicationContext) {
            new DelegatingApplicationEventPublisher(applicationContext)
        }
    
    @Slf4j
    @RequiredArgsConstructor
    public class DelegatingApplicationEventPublisher implements ApplicationEventPublisher {
    
        private final ApplicationContext context;
    
        @Override
        public void publishEvent(ApplicationEvent event) {
            logEvent(event);
            context.publishEvent(event);
        }
    
        @Override
        public void publishEvent(Object event) {
            logEvent(event);
            context.publishEvent(event);
        }
    
        private void logEvent(Object event) {
            if (event instanceof PayloadApplicationEvent payloadApplicationEvent) {
                log.debug(markers("eventName", payloadApplicationEvent.getPayload().getClass(), "event", payloadApplicationEvent.getPayload()), "publishing...");
            } else {
                log.debug(markers("eventName", event.getClass(), "event", event), "publishing ...");
            }
        }
    
    }