Search code examples
spring-bootlogbackspring-aop

Is it possible to "impersonate" a class in logging via aspect?


I developed an aspect that will log when I enter and exit from a class with the standard format that also logs the class, so something like:

2020-03-20 20:05:30.280  INFO 3336 --- [nio-8080-exec-2] c.a.common.aop.LoggingAspect        : Entering method

Please notice that the logging class appears to be "LoggingAspect". Would it be possible, instead, to log the proxied class name? At the moment I get:

2020-03-20 20:05:30.280  INFO 3336 --- [nio-8080-exec-2] c.a.common.aop.LoggingAspect        : Entering method 
2020-03-20 20:06:30.280  INFO 3336 --- [nio-8080-exec-2] c.a.my.proxied.Class        : Doing stuff
2020-03-20 20:05:30.280  INFO 3336 --- [nio-8080-exec-2] c.a.common.aop.LoggingAspect        : Exiting method 

I would like to always have c.a.my.proxied.Class for each line. Here's my aspect:

@Aspect
@Order(1)
@Component
@Slf4j
public class LoggingAspect {

  @Pointcut("@within(org.springframework.web.bind.annotation.RestController)")
  private void controllerInvocation() {}

  @Around("controllerInvocation()")
  public Object logEntering(ProceedingJoinPoint joinPoint) throws Throwable{
     log.info("Entering method");
     Object res = joinPoint.proceed();
     log.info("Exiting method");
     return res;
  }
}

Solution

  • From the documentation for annotation @Slf4j

    @Slf4j
    public class LogExample {}
    

    will generate:

    public class LogExample {
        private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExample.class);
    }
    

    which means that by using the log reference , it would always be for LoggingAspect in the code shared.

    A workaround could be as follows

    import org.slf4j.Logger;
    import static org.slf4j.LoggerFactory.getLogger;
    
    // ...
    
    @Around("controllerInvocation()")
    public Object logEntering(ProceedingJoinPoint joinPoint) throws Throwable {
        // Get the logger for the class of intercepted method
        Logger logz = getLogger(joinPoint.getTarget().getClass());
        logz.info("Entering method");
        Object res = joinPoint.proceed();
        logz.info("Exiting method");
        return res;
    }
    

    Hope this helps


    Edit : OP requested @kriegaex for an example of his suggestion. I take the liberty to illustrate his suggestions.

    Please refer the aop example section in documentation for more details

    import org.slf4j.Logger;
    import static org.slf4j.LoggerFactory.getLogger;
    
    // ...
    
    @Around("controllerInvocation() && target(myTarget)")
    public Object logEntering(ProceedingJoinPoint joinPoint,Object myTarget) throws Throwable {
        // Get the logger for the class of intercepted method
        Logger logz = getLogger(myTarget.getClass());
        logz.info("Entering method");
        try{
            Object res = joinPoint.proceed();
        }finally{
            logz.info("Exiting method");
        }
        return res;
    }