Centralize the AOP logging for my microservices

I have multiple microservices and have establish AOP logging to log my controller, service, and repository layers. Currently, the same AppAspect class is redundant over all my microservice. Is there a way to centralize this?

A thought : have the AOP class as jar, upload it to some repository (or even AWS S3) and have my microservices depend on those.

Why? : Whenever I want to make a small change on my AOP logs, I have to do it repeatadely accross all microservice.

Any leads would help. Following is my AOP AppAspect class

@Aspect
@Component
@Slf4j
public class AppAspect {
    private String ipAddress = "[NO-IP]";

    @Before("execution(* np.com.oskarshrestha.bookstorebackend.controller..*(..)) " +
            "|| execution(* np.com.oskarshrestha.bookstorebackend.service..*(..)) " +
            "|| execution(* np.com.oskarshrestha.bookstorebackend.repository..*(..))")
    public void logBeforeMethodExecution(JoinPoint joinPoint) {
        try {
            // get ip address
            ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (requestAttributes != null) {
                HttpServletRequest request = requestAttributes.getRequest();
                ipAddress = request.getRemoteAddr();
            }
            // get method name
            String methodName = joinPoint.getSignature().getDeclaringType().getPackage().getName() + "." + joinPoint.getSignature().getName();
            log.info("[{}] Started method execution {}", ipAddress, methodName);
        } catch (Exception e) {
            log.error("{} Error in AppAspect {}", ipAddress, e.getMessage());
        }
    }

    @AfterReturning("execution(* np.com.oskarshrestha.bookstorebackend.controller..*(..)) " +
            "|| execution(* np.com.oskarshrestha.bookstorebackend.service..*(..)) " +
            "|| execution(* np.com.oskarshrestha.bookstorebackend.repository..*(..))")
    public void logAfterMethodExecution(JoinPoint joinPoint) {
        try {
            // get method name
            String methodName = joinPoint.getSignature().getDeclaringType().getPackage().getName() + "." + joinPoint.getSignature().getName();
            log.info("[{}] Completed method execution {}", ipAddress, methodName);
        } catch (Exception e) {
            log.error("{} Error in AppAspect {}", ipAddress, e.getMessage());
        }
    }

    @AfterThrowing(value = "execution(* np.com.oskarshrestha.bookstorebackend.controller..*(..)) " +
            "|| execution(* np.com.oskarshrestha.bookstorebackend.service..*(..)) " +
            "|| execution(* np.com.oskarshrestha.bookstorebackend.repository..*(..))", throwing = "exception")
    public void logAfterMethodExecutionThrows(JoinPoint joinPoint, Exception exception) {
        try {
            // get method name
            String methodName = joinPoint.getSignature().getDeclaringType().getPackage().getName() + "." + joinPoint.getSignature().getName();
            log.info("[{}] Exception thrown by method execution {} {}", ipAddress, methodName, exception.getMessage());
        } catch (Exception e) {
            log.error("{} Error in AppAspect {}", ipAddress, e.getMessage());
        }
    }
}

I tried to look for references or resources but didn’t find much lead. Is this even possible?

  • The simple answer is: Yes, you can do that. Why are you asking about it here? Did you even try? Were there any problems? I would expect it to just work. Besides, Stack Overflow is not a place to ask for references or resources, but about programming problems.

    – 

  • Your aspect is flawed to start with, it will fail to log correctly in a multi threaded environment. If you want to log additional information put that in the MDC (through a servlet filter, to extract the IP address for instance) then use a regular logging facility (apparently ou want to trace logging) like the one shipped with Spring, the CustomizableTraceInterceptor. Combine that with additional information in the MDC and you can do anything you like.

    – 

It is not the way to centralize logs. You can add some extra logic using AOP, but it’s not your case. Typical microservices architecture includes external tracing and logging solutions:

  1. Tracing is used to trace execution path from start to finish across related microservices for each request. Can be archived with Jaeger + Opentracing spec (for spring boot v2) or Opentelemetry spec (for spring boot v3)
  2. Logging solutions typically use log storage and ui server for browsing logs. Can be archived with ELK stack + Grafana (instead of Kibana).

So, if you want to archive good observability of your microservice system, you should try these solutions. Google random Kibana screenshot:
Kibana logs example

Extra tip: Try to replace @Before and @After annotations with @Around (and remove hardcoded package names)

Leave a Comment