π
2024λ
01μ 29μΌ
53μΌμ°¨ : Spring (13)
Springμμ Log
logging:
file:
name: logs/app.log
level:
root: info
@Slf4j
@RestController
public class LogTestController {
@GetMapping("/log/test1")
public String testMethod1(){
log.debug("λλ²κ·Έ λ‘κ·Έμ
λλ€.");
log.info("μΈν¬ λ‘κ·Έμ
λλ€.");
log.error("μλ¬ λ‘κ·Έμ
λλ€.");
return "ok";
}
}
λͺ©μ |
μ€λͺ
|
λλ²κΉ
λ° λ¬Έμ ν΄κ²° |
μ΄ν리μΌμ΄μ
μ λ¬Έμ λ₯Ό μλ³νκ³ ν΄κ²°νκΈ° μν΄ λ‘κ·Έλ₯Ό μ¬μ©. λ³μ κ°, λ©μλ νΈμΆ, μμΈ μ€ν νΈλ μ΄μ€ λ±μ΄ κΈ°λ‘λ¨. |
μ±λ₯ λͺ¨λν°λ§ |
μ΄ν리μΌμ΄μ
μ μ±λ₯μ μΆμ νκ³ λͺ¨λν°λ§νκΈ° μν΄ λ‘κ·Έλ₯Ό μ¬μ©. λ©μλ μ€ν μκ°, λ°μ΄ν°λ² μ΄μ€ 쿼리 μμ μκ° λ±μ΄ κΈ°λ‘λ μ μμ. |
κ°μ¬ λ° λ³΄μ |
μ¬μ©μμ νλ μΆμ , 보μ μ΄λ²€νΈ λ‘κΉ
λ±μ ν΅ν΄ κ°μ¬ λ° λ³΄μ λͺ©μ μΌλ‘ μ¬μ©λ¨. |
μ΄μ λ° λͺ¨λν°λ§ |
μ΄ν리μΌμ΄μ
μ μ΄μ μνλ₯Ό μΆμ νκ³ λͺ¨λν°λ§νκΈ° μν΄ λ‘κ·Έλ₯Ό μ¬μ©. μ€μ μ§μ€μμΌλ‘ λͺ¨λν°λ§λ μ μμ. |
- log νμΌ κ΄λ¦¬(logback-spring.xml)
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name = "CONSOLE" class ="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %logger{36} - %msg%n </pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/app.log</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %logger{36} - %msg%n </pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/app.%d{yyyy-MM-dd HH:mm:ss}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
</appender>
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>error</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<file>logs/app-error.log</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %logger{36} - %msg%n </pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/app-error.%d{yyyy-MM-dd HH:mm:ss}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
</appender>
<root level = "info">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
<appender-ref ref="ERROR_FILE"/>
</root>
</configuration>
AOP (κ΄μ μ§ν₯ νλ‘κ·Έλλ°)
μ©μ΄/κ°λ
|
λ΄μ© |
Aspect (κ΄μ ) |
ν΅μ¬ λΉμ¦λμ€ λ‘μ§μμ λ°μνλ ν‘λ¨ κ΄μ¬μ¬λ₯Ό λͺ¨λνν κ²μΌλ‘, μλ₯Ό λ€μ΄ λ‘κΉ
, νΈλμμ
μ²λ¦¬, 보μ λ±μ΄ ν΄λΉλ¨. |
Advice (μ‘°μΈ) |
μ΄λ μμ μμ μ΄λμ κ΄μ μ μ μ©ν μ§λ₯Ό μ μν κ²μΌλ‘, λ©μλ νΈμΆ μ , ν, μμΈ λ°μ μ λ±κ³Ό κ°μ μ§μ μμ μ μ©λ μ μμ. |
Pointcut (ν¬μΈνΈμ»·) |
μ΄λ€ μ§μ μμ μ΄λ€ κ΄μ μ μ μ©ν μ§λ₯Ό μ μν κ²μΌλ‘, λ©μλ νΈμΆ, κ°μ²΄ μμ±, νλ μ κ·Ό λ± λ€μν μ§μ μ μ§μ ν μ μμ. |
Join Point (μ‘°μΈ ν¬μΈνΈ) |
νλ‘κ·Έλ¨ μ€ν μ€ νΉμ μμ μΌλ‘, κ΄μ μ΄ μ μ©λμ΄μΌ νλ νΉμ μ§μ μ λνλ. λ©μλ νΈμΆ, κ°μ²΄ μμ± λ±μ΄ μ‘°μΈ ν¬μΈνΈμ ν΄λΉν μ μμ. |
Weaving (μλΉ) |
κ΄μ μ ν΅μ¬ λΉμ¦λμ€ λ‘μ§μ μ μ©νλ κ³Όμ μΌλ‘, μ½λμ κ΄μ μ μ½μ
νκ±°λ μ°κ²°νμ¬ μ€νλλλ‘ λ§λλ κ²μ μλ―Έν¨. |
@Slf4j
@Aspect
@Component
public class AopLogService {
@Pointcut("within(@org.springframework.stereotype.Controller *)")
public void controllerPointCut(){
}
@Before("controllerPointCut()")
public void beforeController(JoinPoint joinPoint){
log.info("Before Controller");
HttpServletRequest httpServletRequest = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
ObjectMapper objectMapper = new ObjectMapper();
ObjectNode objectNode = objectMapper.createObjectNode();
objectNode.put("Method Name",joinPoint.getSignature().getName());
objectNode.put("CRUD Name", httpServletRequest.getMethod());
Map<String, String[]> paramMap = httpServletRequest.getParameterMap();
ObjectNode objectNodeDetail = objectMapper.valueToTree(paramMap);
objectNode.set("user inputs", objectNodeDetail);
log.info("user request info" + objectNode);
}
@After("controllerPointCut()")
public void afterController(){
log.info("end Controller");
}
@Around("controllerPointCut()")
public Object controllerLogger(ProceedingJoinPoint proceedingJoinPoint){
HttpServletRequest httpServletRequest = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
ObjectMapper objectMapper = new ObjectMapper();
ObjectNode objectNode = objectMapper.createObjectNode();
objectNode.put("Method Name",proceedingJoinPoint.getSignature().getName());
objectNode.put("CRUD Name", httpServletRequest.getMethod());
Map<String, String[]> paramMap = httpServletRequest.getParameterMap();
ObjectNode objectNodeDetail = objectMapper.valueToTree(paramMap);
objectNode.set("user inputs", objectNodeDetail);
log.info("user request info" + objectNode);
try {
return proceedingJoinPoint.proceed();
}catch (Throwable e){
log.error(e.getMessage());
throw new RuntimeException(e);
}
}
}
μ΄λ
Έν
μ΄μ
|
μ°μμΈ |
λ΄μ© |
@Pointcut |
Pointcutμ μ μνλ λ° μ¬μ© |
νΉμ μ§μ (λ©μλ νΈμΆ, κ°μ²΄ μμ± λ±)μ AOPλ₯Ό μ μ©νκΈ° μν΄ μ¬μ©λλ ννμμ μ μν©λλ€. ν΄λΉ ννμμ μ¬λ¬ μ΄λλ°μ΄μ€μμ 곡μ λ μ μμ΅λλ€. |
@Before |
λ©μλ μ€ν μ μ μ΄λλ°μ΄μ€λ₯Ό μ€ν |
μ΄λλ°μ΄μ€ λ©μλλ₯Ό νΉμ μ‘°μΈ ν¬μΈνΈ(λ©μλ νΈμΆ λ±) μ μ μ€νν©λλ€. μ£Όλ‘ μ μ²λ¦¬ λ‘μ§μ μννλ λ° μ¬μ©λ©λλ€. |
@After |
λ©μλ μ€ν νμ μ΄λλ°μ΄μ€λ₯Ό μ€ν |
μ΄λλ°μ΄μ€ λ©μλλ₯Ό νΉμ μ‘°μΈ ν¬μΈνΈ νμ μ€νν©λλ€. μ£Όλ‘ νμ²λ¦¬ λ‘μ§μ μννκ±°λ μμΈ μ²λ¦¬μ μ¬μ©λ©λλ€. |
@Around |
λ©μλ μ€ν μ νμ μ΄λλ°μ΄μ€λ₯Ό μ€ν |
μ΄λλ°μ΄μ€ λ©μλκ° μ‘°μΈ ν¬μΈνΈλ₯Ό κ°μΈμ μ€ν μ νμ λ‘μ§μ μνν μ μμ΅λλ€. κ°μ₯ μ μ°ν μ΄λλ°μ΄μ€λ‘, μ , ν μ²λ¦¬ λ° μμΈ μ²λ¦¬ λ± λͺ¨λ λ‘μ§μ ν¬ν¨ν μ μμ΅λλ€. |
@ControllerAdvice
: 컨νΈλ‘€λ¬ νΉνκΈ°λ₯ μ£Όλ‘ μμΈμ²λ¦¬
@Slf4j
@ControllerAdvice
public class CommonException {
@ExceptionHandler(EntityNotFoundException.class)
public ResponseEntity<Map<String, Object>> entityNotFoundExceptionHandler(EntityNotFoundException e){
log.error("EntityNotFoundException message : " + e.getMessage());
return this.responseErrorMassage(HttpStatus.NOT_FOUND,e.getMessage());
}
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<Map<String, Object>> IllegalArgumentExceptionHandler(IllegalArgumentException e){
log.error("IllegalArgumentException : " + e.getMessage());
return this.responseErrorMassage(HttpStatus.BAD_REQUEST,e.getMessage());
}
private ResponseEntity<Map<String, Object>> responseMassage(HttpStatus status, Object object){
Map<String, Object> map = new HashMap<>();
map.put("status", Integer.toString(status.value()));
map.put("message", object);
return new ResponseEntity<>(map, status);
}
private ResponseEntity<Map<String, Object>> responseErrorMassage(HttpStatus status, String message){
Map<String, Object> map = new HashMap<>();
map.put("status", Integer.toString(status.value()));
map.put("status message", status.getReasonPhrase());
map.put("error message", message);
return new ResponseEntity<>(map, status);
}
}
λ§μ½ 컨νΈλ‘€λ¬μμ try-catch λΈλ‘ λ΄μμ μμΈλ₯Ό μ²λ¦¬νλ©΄ ν΄λΉ λ©μλμ μμΈ μ²λ¦¬ λ‘μ§μ΄ μ°μ νΈμΆλκ³ , μ²λ¦¬νμ§ μκ±°λ μ νλλ κ²½μ°μ @ControllerAdviceμ @ExceptionHandler λ©μλκ° νΈμΆ
Spring μ€μ΅ github λ§ν¬