삽질 피하기
[삽질 피하기] 로그 - 히스토리 기능 (AOP)
ozofweird
2021. 4. 21. 16:27
1. 로그 (AOP)
1) MainApplication
package com.example.jpa.sample;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.scheduling.annotation.EnableScheduling;
@EnableScheduling // 스케쥴러 설정
@EnableAspectJAutoProxy // aop 동작 설정
@SpringBootApplication
public class SampleApplication {
public static void main(String[] args) {
SpringApplication.run(SampleApplication.class, args);
}
}
2) Logs
히스토리를 저장할 Entity, Repository, Service를 구현해준다.
...
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.time.LocalDateTime;
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Data
@Entity
public class Logs {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column
private String text;
@Column
private LocalDateTime regDate;
}
...
import org.springframework.data.jpa.repository.JpaRepository;
public interface LogsRepository extends JpaRepository<Logs, Long> {
}
...
public interface LogService {
void add(String text);
void deleteLog();
}
...
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
@RequiredArgsConstructor
@Service
public class LogServiceImpl implements LogService {
private final LogsRepository logsRepository;
@Override
public void add(String text) {
logsRepository.save(Logs.builder()
.text(text)
.regDate(LocalDateTime.now())
.build());
}
@Override
public void deleteLog() {
logsRepository.deleteAll();
}
}
3) Logger
로그-히스토리 기능은 주로 AOP 기술을 활용한다.
...
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Slf4j // 로그 찍어보는 용도로 사용
@RequiredArgsConstructor
@Aspect
@Component
public class LoginLogger {
private final LogService logService;
@Around("execution(* com.example.jpa.sample..*.*Service*.*(..))")
public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("#################################");
log.info("서비스 호출 전");
Object result = joinPoint.proceed();
// joinPoint.getArgs() : 서비스 호출시 넘기는 파라미터
// joinPoint.getSignature() : 메시지 정보 (ex. 메서드의 경우 getDeclaringTypeName(), getName() 사용)
if("login".equals(joinPoint.getSignature().getName())) {
StringBuilder sb = new StringBuilder();
sb.append("\n");
sb.append("함수명: " + joinPoint.getSignature().getDeclaringTypeName() + ", " + joinPoint.getSignature().getName());
sb.append("\n");
sb.append("매개변수: ");
Object[] args = joinPoint.getArgs();
if(args != null && args.length > 0) {
for(Object o : args) {
if(o instanceof UserLogin) {
// String email = ((UserLogin)o).getEmail();
// String password = ((UserLogin)o).getPassword();
sb.append(((UserLogin)o).toString()); // @ToString
sb.append("리턴값: " + ((User)result).toString());
}
}
logService.add(sb.toString());
log.info(sb.toString());
}
}
log.info("#################################");
log.info("서비스 호출 후");
return result;
}
}
...
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Slf4j // 로그 찍어보는 용도로 사용
@RequiredArgsConstructor
@Aspect
@Component
public class BoardLogger {
private final LogService logService;
@Around("execution(* com.example.jpa.sample..*.*Controller.detail(..))")
public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("#################################");
log.info("컨트롤러 Detail 서비스 호출 전");
Object result = joinPoint.proceed();
if(joinPoint.getSignature().getDeclaringTypeName().contains("ApiBoardController")
&& "detail".equals(joinPoint.getSignature().getName())) {
StringBuilder sb = new StringBuilder();
sb.append("파라미터: ");
Object[] args = joinPoint.getArgs();
for(Object o : args) {
sb.append(o.toString());
}
sb.append("결과: ");
sb.append(result.toString());
log.info(sb.toString());
logService.add(sb.toString());
}
log.info("#################################");
log.info("컨트롤러 Detail 호출 후");
return result;
}
}
4) application.yml
별도로 로그를 저장을 할 수 있다.
logging:
level:
org.hibernate.SQL: trace
org.hibernate.type: trace
file:
name: ./logs/spring-jpa.log
728x90