일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 클론코딩
- 개발
- 프론트엔드
- react native
- react-native
- 코딩
- Spring
- Java
- spring boot
- 스타트업
- expo
- 인스타그램
- 국비지원
- 리엑트 네이티브
- 스프링
- 풀스택
- 프론트 엔드
- 백엔드
- 개발자
- 스프링 부트
- 비전공자
- 풀스택 개발자
- 자바
- 국비 지원
- 비전공
- Redux
- react
- 상태관리
- ffmpeg
- 리엑트
- Today
- Total
오티스의개발일기
[SPRING BOOT] aop 를 활용하여 request요청 log찍기 본문
# 0 . AOP란?
aop란 애스팩트라고 부르는 별도의 클래스에 캡슐화하는 접근 방식 이다
더쉽게 풀어서 이야기하자면
각 비지니스 코드파일 혹은 컨트롤러 등등 여러가지 파일에대한 어떠한 이벤트를 받고
로그같은 것들을 수행하고싶은데
각자 하나하나 만들기에는 중복되는 코드와 관리가 힘들기때문에
하나 혹은 정리해놓은 클래스 내부에서 자신이 관심이있는 클래스를 등록해두고
그 클래스가 동작할때
aop가 가지고있는 생명주기를 가지고
동작 전 그리고 동작시 그리고 후 에대한 어떠한 로직을 처리할때 사용한다.
오늘은 aop를 사용해볼것이고 너무 깊게 사용하지않을것이다.
그이유는 이 프로잭트에서는 불필요하기때문에
이것을 사용하여 매 request에 대한 요청 로그를 찍어볼것이다.
사용할 어노테이션에대해 간략하게 설명하겠다.
@Aspect = 관심사를 등록한다는이야기다 한마디로 이파일 aop에 사용하겠음~ 하고 말하는것과 같다.
곧 LogAdvice 라는 파일을 만들건데 그곳 상단에 적어줄것이다.
@JoinPoint = 어드바이스가 실행하는 동작을 끼워 넣을 수 있는 때를 말한다 우리는 이걸 사용하지 않을것이다.
@Advice = @JoinPoint 에서 실행되는 코드를 말한다.
@PointCut = 어드바이스가 실행되는 하나 이상의 조인 포인트를 선택하는 표현식 이건 한마디로 이벤트를 등록하는것과 마찬가지이다.
저곳에 파라미터로 어떤 위치를 적는데 그 위치에서 발생하는 모든 이벤트를 받겠다~ 이런말이다.
@Around = @JoinPoint 이전과 이후에 호출되는 어드바이스이다. 우리는 이것을 메인으로 사용해 로그처리를 할것이다.
자 시작해보겠다.
우리가 만들것은
1. logback-spring.xml
2. LogAdvice.java
2. UserController
이다 한번 만들어보자
일단 파일 구조는 이러하다
#1. aop dependencies 추가
implementation 'org.springframework.boot:spring-boot-starter-aop'
# 2. logback-spring.xml 생성
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 콘솔(STDOUT)에 log 기록 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>[%d{yyyy-MM-dd HH:mm:ss}:%-3relative] %-5level ${PID:-} --- [%15.15thread] %-40.40logger{36} : %msg%n</Pattern>
</layout>
</appender>
<!-- log root 레벨 설정 (logging.level.root=info)-->
<root level="info">
<!-- 참조할 appender 설정 - STDOUT -->
<appender-ref ref="STDOUT" />
</root>
</configuration>
# 3. LogAdvice.java 생성
package com.example.backend.common.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.RequestContextListener;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
@Component
@Aspect
public class LogAdvice {
private static final Logger logger = LoggerFactory.getLogger(LogAdvice.class);
@Bean
public RequestContextListener requestContextListener(){ return new RequestContextListener();}
// 어디에 관심이 있는지 등록
@Pointcut("within(com.example.backend.controller..*)")
public void onRequest() {
}
// 위에 만든 onRequest가 동작할시 requestLogging 동작함
@Around("com.example.backend.common.aop.LogAdvice.onRequest()")
public Object requestLogging(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
HttpServletRequest request = null;
try {
request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
} catch (IllegalStateException e) {
return proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());
}
long start = System.currentTimeMillis();
try {
return proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());
} finally {
long end = System.currentTimeMillis();
logger.info("Request: {} {}: ({}ms)", request.getMethod(), request.getRequestURL(), end - start);
}
}
}
이제 컨트롤러를 만들고 postman으로 확인해보자
package com.example.backend.controller;
import com.example.backend.common.exception.CustomApiException;
import com.example.backend.dto.CMRespDto;
import com.example.backend.dto.user.request.RequestUserRegisterDto;
import com.example.backend.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
@RestController
@RequiredArgsConstructor
@CrossOrigin(origins = {"*"})
@RequestMapping("/api/user")
public class UserController {
private final UserService userService;
@PostMapping("/register")
public CMRespDto<?> register (@Valid @RequestBody RequestUserRegisterDto requestUserRegisterDto) {
System.out.println("123");
return new CMRespDto<>(200, "정상처리", null);
}
@GetMapping("/hi")
public CMRespDto<?> hi (){
userService.register();
return new CMRespDto<>(200, "정상처리", null);
}
}
정상 post man 으로 요청했을때 정상처리가 되는걸 볼수있다
로그도 정상 출력되는걸 확인할수있다.
이것으로 spring boot aop를 활용한 로그출력을 마치도록하겠다.