728x90
1. POM 의존성설정
<!-- log-->
<dependency>
<groupId>io.sentry</groupId>
<artifactId>sentry-spring-boot-starter</artifactId>
<version>6.14.0</version>
</dependency>
2. YML파일 설정
sentry:
dsn: Sentry.io에서 발급받은 DSN키값
일단은 전처리 과정에서 받은 오류를 받아서 Type 값과 method를 입력시켜주었습니다.
package com.cos.photogramstart.handler.aop;
import com.cos.photogramstart.handler.ex.CustomVaildationApiException;
import com.cos.photogramstart.handler.ex.CustomVaildationException;
import io.sentry.Sentry;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
@Component //RestController Service 든 Component 구현체들이다. Compoenet 를 상속해서 만들어져있음
@Aspect //aop 처리를 할수있는 핸들러
public class ValidationAdvice {
private static final Logger log= LoggerFactory.getLogger(ValidationAdvice.class);
//
// @Before("execution(* com.cos.photogramstart.web.api.*Controller.*(..))")
// public void testCheck(){
// // 어디서든지 요청을 받아올수있음
// HttpServletRequest request= ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
//
//
// }
// web 패키지에서 Controller로 끝나는 모든클래스에서 모든 메서드의 파라미터가 뭐든상관없는거를 호출
@Around("execution(* com.cos.photogramstart.web.api.*Controller.*(..))")
public Object apiAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("web api 컨틀롤러==============");
String type=proceedingJoinPoint.getSignature().getDeclaringTypeName();
String method=proceedingJoinPoint.getSignature().getName();
Object [] args=proceedingJoinPoint.getArgs();
for (Object arg:args){
if (arg instanceof BindingResult){
System.out.println("유효성 검사를 하는 함수입니다");
BindingResult bindingResult=(BindingResult) arg;
if(bindingResult.hasErrors()){
Map<String,String> errorMap=new HashMap<>();
for(FieldError error:bindingResult.getFieldErrors()){
errorMap.put(error.getField(), error.getDefaultMessage());
log.warn(type+"."+method+"() => 필드:"+error.getField()+"메세지"+error.getDefaultMessage());
Sentry.captureMessage(type+"."+method+"() => 필드:"+error.getField()+"메세지"+error.getDefaultMessage());
}
throw new CustomVaildationApiException("유효성검사 실패함",errorMap);
}
}
}
// ProceedingJoinPoint 함수의 모든곳에 접근할수있는 변수
// 호출한 함수보다 먼저 실행이됨
return proceedingJoinPoint.proceed(); //호출한 함수가 실행됨
}
@Around("execution(* com.cos.photogramstart.web.*Controller.*(..))")
public Object advice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
// ProceedingJoinPoint 는 컨트롤러 메소드안에 접근할수있는 권한을 만듬
System.out.println("web 컨틀롤러==============");
String type=proceedingJoinPoint.getSignature().getDeclaringTypeName();
String method=proceedingJoinPoint.getSignature().getName();
Object [] args=proceedingJoinPoint.getArgs();
for (Object arg:args){
if (arg instanceof BindingResult){
BindingResult bindingResult=(BindingResult) arg;
if(bindingResult.hasErrors()){
Map<String,String> errorMap=new HashMap<>();
for(FieldError error:bindingResult.getFieldErrors()){
errorMap.put(error.getField(),error.getDefaultMessage());
log.warn(type+"."+method+"() => 필드:"+error.getField()+"메세지"+error.getDefaultMessage());
Sentry.captureMessage(type+"."+method+"() => 필드:"+error.getField()+"메세지"+error.getDefaultMessage());
}
throw new CustomVaildationException("유효성검사 실패함",errorMap);
}
}
}
return proceedingJoinPoint.proceed();
}
}
3. Sentry.Capture(String) 을 통해서 Sentry.io에 메세지를 날립니다.
다음과 같이 어떤 HTTP메서드를 날렸을 때 어떠한 오류가 떳는지 필드오류가 나타나게 됩니다.
번외
5. logback-spring.xml 을 만들어서 파일안에 로그찍기
src->main->resources 안에 logback-spring.xml 파일만들기
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<property name="LOGS_ABSOLUTE_PATH" value="./logs" />
<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][%thread] %-5level %logger{36} - %msg%n</Pattern>
</layout>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOGS_ABSOLUTE_PATH}/logback.log</file>
<encoder>
<pattern>[%d{yyyy-MM-dd HH:mm:ss}:%-3relative][%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOGS_ABSOLUTE_PATH}/logback.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>5MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>30</maxHistory>
</rollingPolicy>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
<logger name="com.cos.photogramstart.handler" level="WARN">
<appender-ref ref="FILE" />
</logger>
</configuration>
여기서 중요한점은 root-level입니다. 해당하는 STDOUT 표준입출력창을 통해 띄울 레벨을 정하는것입니다.
File 쪽은 loggername="로깅 처리할 패키지를 써주시면됩니다"
다음과 같이 logs파일안에 logback.log 가 생성되고 로그가 기록되게됩니다.
저는 파일안에 찍히는 로그 레벨을 WARN 부터 했으므로 WARN 및 ERROR 가 찍히게 될 것 입니다.
728x90
'aop' 카테고리의 다른 글
Spring Filter,Interceptor,AOP 차이 (0) | 2023.02.19 |
---|---|
AOP 전처리와 후처리 공통로직,핵심로직을 분리. (0) | 2023.02.13 |
AOP란 무엇인가 (0) | 2022.08.17 |