@Aspect
@Component
@Slf4j
public class LogAspect {
private final AccountRepo accountRepo;
private final OperatorLogHistoryRepository operatorLogHistoryRepository;
public LogAspect(AccountRepo accountRepo, OperatorLogHistoryRepository operatorLogHistoryRepository) {
this.accountRepo = accountRepo;
this.operatorLogHistoryRepository = operatorLogHistoryRepository;
}
@Pointcut("execution(* kr.co.concepters.operation.controller.*.*(..))" +
"&& !@annotation(kr.co.concepters.operation.annotation.NoLogging)")
private void pointCut() {
}
@Around("pointCut()")
public Object onAfterHandler(ProceedingJoinPoint joinPoint) throws Throwable {
List<Object> args = Arrays.asList(joinPoint.getArgs());
Object result = joinPoint.proceed();
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null) return result;
Object tempUserDetail = authentication.getPrincipal();
if (!(tempUserDetail instanceof UserDetails)) return result;
UserDetails userDetails = (UserDetails) tempUserDetail;
LocalDateTime connectionDate = LocalDateTime.now();
String connectionDateTime = connectionDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss"));
Account account = accountRepo.findById(userDetails.getAccountIdx()).orElse(null);
String ip = getClientIP(request);
// 사설 아이피 체크.
if (isPrivateNetwork(ip)) return result;
String path = request.getServletPath();
String method = request.getMethod();
boolean isDownload = path.contains("download"); // download check.
if (account != null) {
log.info("{} [{}] {} ({}) [{} : {}]", connectionDateTime, ip, account.getIdentifier(), account.getName(), method, path);
// 비밀번호 로그 제외 로직 추가.
args = args.stream()
.filter(arg -> !(arg instanceof HttpServletResponse) && !(arg instanceof HttpServletRequest))
.map(arg -> {
if (arg instanceof Map) {
Map<Object, Object> temp = (Map) arg;
if (temp.containsKey("pw")) {
temp.remove("pw");
} else if (temp.containsKey("password")) {
temp.remove("password");
}
return temp;
} else {
try {
if (arg != null && arg.getClass().getMethod("toString").getDeclaringClass() == Object.class) {
return "[Object] " + arg.getClass().getSimpleName();
} else {
return arg;
}
} catch (NoSuchMethodException e) {
return arg;
}
}
}).collect(Collectors.toList());
log.info("args {}", args);
operatorLogHistoryRepository.save(OperatorLogHistory.builder()
.accountIdx(account.getIdx())
.ipAddress(ip)
.identifier(account.getIdentifier())
.name(account.getName())
.email(account.getEmail())
.phone(account.getPhone())
.isMaster(account.getIsMaster())
.isDownload(isDownload)
.method(method)
.path(path)
.arguments(args.toString())
.connectionDate(connectionDate)
.build());
}
return result;
}
private boolean isPrivateNetwork(String ip) throws UnknownHostException {
InetAddress inetAddress = InetAddress.getByName(ip);
return inetAddress.isSiteLocalAddress();
}
}
해당부분에서 pointcut 메소드에서 !@annotation(kr.co.concepters.operation.annotation.NoLogging)" 부분이 있다.
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface NoLogging {
}
인터페이스 앞에 @를 붙여서 어노테이션을 커스텀 합니다.
@Target, @Retention은 어노테이션을 정의할 때 사용하는 메타 어노테이션입니다.
- @Target은 어노테이션이 적용될 수 있는 대상을 지정합니다. 위의 예시에서는 메소드에만 적용할 수 있도록 ElementType.METHOD로 설정되어 있습니다.
- @Retention은 어노테이션이 유지되는 기간을 지정합니다. 위의 예시에서는 런타임까지 유지되도록 RetentionPolicy.RUNTIME으로 설정되어 있습니다.
@NoLogging은 사용자가 직접 만든 어노테이션으로, 메소드에 적용되면 해당 메소드의 로그를 출력하지 않도록 하는 기능을 할 수 있습니다.
@NoLogging
@GetMapping({"/", ""})
public ResponseEntity<?> root(@RequestHeader(value = "X-Path", required = false) String xPath) {
해당 부분에 @NoLogging 을 선언함으로써, 로그 출력을 하지않도록 설정 가능
728x90
'Programming > Web-Spring' 카테고리의 다른 글
[intellij] 인텔리j spring boot 실행 시 , finished with non-zero exit value 1 해결 (0) | 2024.09.05 |
---|---|
[Spring] vault 개념과 활용 (0) | 2024.06.25 |
[jwt] refreshToken을 db에서 유지하는 이유 (0) | 2024.06.07 |
[Spring] 필터(Filter) vs 인터셉터(Interceptor) 차이 (0) | 2024.06.03 |
[Spring] QueryDsl의 Q클래스 빨간줄 에러 뜨는현상 방지 (0) | 2024.01.30 |