Implementing Request Logging with Spring AOP: A Practical Guide

This article demonstrates how to use Spring AOP to create a request‑logging aspect that captures request parameters, response data, execution time, and error information, while also addressing high‑concurrency logging issues and integrating trace‑ID tracking for easier debugging.

Top Architect
Top Architect
Top Architect
Implementing Request Logging with Spring AOP: A Practical Guide

When a project reaches the integration testing phase, mismatched request parameters often cause interface failures; a request‑logging aspect can record the full call chain, providing evidence for troubleshooting.

Aspect‑Oriented Programming Overview

AOP separates core business logic from cross‑cutting concerns such as transaction management, security, caching, and logging, improving code readability and maintainability.

Define the Pointcut

@Pointcut("execution(* your_package.controller..*(..))")
public void requestServer() {}

The pointcut targets all methods in the controller package.

Before Advice – Log Request Metadata

@Before("requestServer()")
public void doBefore(JoinPoint joinPoint) {
    ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
    HttpServletRequest request = attributes.getRequest();
    LOGGER.info("===============================Start========================");
    LOGGER.info("IP : {}", request.getRemoteAddr());
    LOGGER.info("URL : {}", request.getRequestURL().toString());
    LOGGER.info("HTTP Method : {}", request.getMethod());
    LOGGER.info("Class Method : {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
}

Logs IP, URL, HTTP method and the invoked controller method before execution.

Around Advice – Capture Parameters, Result and Duration

@Around("requestServer()")
public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
    long start = System.currentTimeMillis();
    Object result = proceedingJoinPoint.proceed();
    LOGGER.info("Request Params : {}", getRequestParams(proceedingJoinPoint));
    LOGGER.info("Result : {}", result);
    LOGGER.info("Time Cost : {} ms", System.currentTimeMillis() - start);
    return result;
}

The around advice records input parameters, the method’s return value, and execution time.

After Advice – Mark End of Request

@After("requestServer()")
public void doAfter(JoinPoint joinPoint) {
    LOGGER.info("===============================End========================");
}

Simply logs a separator indicating the request has finished.

High‑Concurrency Optimization

To avoid interleaved log lines under heavy load, the article introduces a RequestInfo DTO that aggregates all data and logs it as a single JSON string.

@Data
public class RequestInfo {
    private String ip;
    private String url;
    private String httpMethod;
    private String classMethod;
    private Object requestParams;
    private Object result;
    private Long timeCost;
}

The around advice now populates this object and logs JSON.toJSONString(requestInfo), producing a compact, parseable line.

Error Logging with @AfterThrowing

@AfterThrowing(pointcut = "requestServer()", throwing = "e")
public void doAfterThrow(JoinPoint joinPoint, RuntimeException e) {
    HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    RequestErrorInfo errorInfo = new RequestErrorInfo();
    errorInfo.setIp(request.getRemoteAddr());
    errorInfo.setUrl(request.getRequestURL().toString());
    errorInfo.setHttpMethod(request.getMethod());
    errorInfo.setClassMethod(String.format("%s.%s", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName()));
    errorInfo.setRequestParams(getRequestParamsByJoinPoint(joinPoint));
    errorInfo.setException(e);
    LOGGER.info("Error Request Info : {}", JSON.toJSONString(errorInfo));
}

Logs request details together with the thrown exception without recording duration.

Trace‑ID Integration for Distributed Tracing

An interceptor adds a unique traceId to the logging context before each request and removes it after completion.

public class LogInterceptor implements HandlerInterceptor {
    private static final String TRACE_ID = "traceId";
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        String traceId = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
        ThreadContext.put("traceId", traceId);
        return true;
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        ThreadContext.remove(TRACE_ID);
    }
}

The logging pattern is updated to include %X{traceId}, enabling end‑to‑end request tracing.

Complete Aspect Code

The article concludes with the full source of RequestLogAspect, which combines pointcut definition, before, around, after, and after‑throwing advices, as well as helper methods for extracting parameters.

@Component
@Aspect
public class RequestLogAspect {
    private static final Logger LOGGER = LoggerFactory.getLogger(RequestLogAspect.class);
    @Pointcut("execution(* your_package.controller..*(..))")
    public void requestServer() {}
    // ... (advices and helper methods as shown above)
}

Developers are encouraged to integrate this aspect into their Spring applications to obtain comprehensive request logs, simplify debugging, and improve observability.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Javaaopspringloggingaspectj
Top Architect
Written by

Top Architect

Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.