빈쿵바라기
좌충우돌 개발자의 기록
빈쿵바라기
전체 방문자
오늘
어제
  • 분류 전체보기 (53)
    • Programming (25)
      • JAVA (12)
      • Spring Boot (6)
      • JPA (7)
      • Python (0)
    • Database (12)
      • RDBMS (4)
      • NoSQL (7)
    • Server (11)
    • Elasticsearch (3)
    • ETC (2)

블로그 메뉴

    공지사항

    인기 글

    최근 댓글

    최근 글

    티스토리

    hELLO · Designed By 정상우.
    빈쿵바라기

    좌충우돌 개발자의 기록

    Programming/Spring Boot

    Spring AOP를 활용한 모든 Request에 Log 남기기

    2023. 3. 29. 19:00

    Controller에서 RequestMapping된 모든 요청에 로그를 남기고 싶은데, 메소드 하나하나에 로그를 찍는 것은 너무 생산성이 떨어지기에 Spring AOP를 활용하여 로그를 남겼던 방법을 기록합니다.

     

    1. Dependency 추가

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>

     

    2. @Aspect 클래스 작성

    import java.util.HashMap;
    import java.util.Map;
    import javax.servlet.http.HttpServletRequest;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.AfterReturning;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    import org.aspectj.lang.reflect.CodeSignature;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    
    @Aspect
    @Component
    public class LoggingAspect {
    
    	// om.ocko.myproject.controller 이하 패키지의 모든 클래스 이하 모든 메서드에 적용
    	@Pointcut("execution(* com.ocko.myproject.controller..*.*(..))")
    	private void onRequest() {
    	}
    
    	// Pointcut에 의해 필터링된 경로로 들어오는 경우 메서드 호출 전에 적용
    	@Before("onRequest()")
    	public void beforeParameterLog(JoinPoint joinPoint) {
    		Class clazz = joinPoint.getTarget().getClass();
    		Logger logger = LoggerFactory.getLogger(clazz);
    		
    		HttpServletRequest request = 
    		        ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
    
    		logger.info("Request : {} {} {}", request.getMethod(), request.getRequestURI(), params(joinPoint).toString());
    	}
    
    	// Poincut에 의해 필터링된 경로로 들어오는 경우 메서드 리턴 후에 적용
    	@AfterReturning(value = "onRequest()", returning = "returnObj")
    	public void afterReturnLog(JoinPoint joinPoint, Object returnObj) {
    		Class clazz = joinPoint.getTarget().getClass();
    		Logger logger = LoggerFactory.getLogger(clazz);
    		
    		HttpServletRequest request = 
    		        ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
    
    		logger.info("Response {} : {}", request.getRequestURI(), returnObj);
    	}
    
    
    	/* printing request parameter or request body */
    	private Map params(JoinPoint joinPoint) {
    		CodeSignature codeSignature = (CodeSignature) joinPoint.getSignature();
    		String[] parameterNames = codeSignature.getParameterNames();
    		Object[] args = joinPoint.getArgs();
    		Map<String, Object> params = new HashMap<>();
    		for (int i = 0; i < parameterNames.length; i++) {
    			params.put(parameterNames[i], args[i]);
    		}
    		return params;
    	}
    }

     

    AOP 주요 개념

    • Aspect : 흩어진 관심사를 모듈화 한 것
    • Advice : 실질적인 부가기능을 담은 구현체 (@Before, @After, @AfterReturning, @AfterThrowing, @Around)
    • JointPoint : Advice가 적용될 위치, 끼어들 수 있는 지점.
    • PointCut : JointPoint의 상세한 스펙을 정의한 것.

     

    3. 실행결과

    2023-03-29 18:58:02.491  INFO 162004 --- [nio-8081-exec-3] i.s.k.p.controller.AdminApiController    : Request : GET /api/a/board {id=165}
    2023-03-29 18:58:02.521  INFO 162004 --- [nio-8081-exec-3] i.s.k.p.controller.AdminApiController    : Response /api/a/board : {id=165, title=hello, content=hello world}

     

    Rererence

    https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/EnableAspectJAutoProxy.html

    저작자표시

    'Programming > Spring Boot' 카테고리의 다른 글

    [Spring Security] 수동 인증(강제 로그인)  (0) 2023.05.16
    [Jasypt] Spring Boot 애플리케이션의 프로퍼티 암호화  (0) 2023.03.24
    [Maven] 라이브러리 Dependency 충돌 해결하기(Maven Tree)  (0) 2023.03.02
    [Mybatis] PostgreSQL ilike 구현하기(feat. Criteria 커스텀하기)  (0) 2022.08.20
    [Spring Security] 두개의 로그인 페이지(Multiple Login Pages)  (0) 2022.08.10
      'Programming/Spring Boot' 카테고리의 다른 글
      • [Spring Security] 수동 인증(강제 로그인)
      • [Jasypt] Spring Boot 애플리케이션의 프로퍼티 암호화
      • [Maven] 라이브러리 Dependency 충돌 해결하기(Maven Tree)
      • [Mybatis] PostgreSQL ilike 구현하기(feat. Criteria 커스텀하기)
      빈쿵바라기
      빈쿵바라기
      삽질하는 개발자의 좌충우돌 개발기

      티스토리툴바