스프링/스프링 핵심 원리 - 고급편

4. 로그추적기 V1 프로토타입

sdafdq 2024. 1. 5. 14:19

이런 식으로 나오게 할 생각 인 듯

 

@Slf4j
public class TraceId {
    private String id;
    private int level;
    public TraceId(){
        this.id = createId();
        this.level = 0;
    }

    private String createId(){
        return UUID.randomUUID().toString().substring(0,8);
    }

    private TraceId(String id, int level){
        this.id = id;
        this.level = level;
    }

    public TraceId createNextId(){
        return new TraceId(id, level + 1);
    }

    public TraceId createPreviousId(){
        return new TraceId(id, level - 1);
    }

    public boolean isFirstLevel(){
        return level == 0;
    }

    public String getId() {
        return id;
    }

    public int getLevel() {
        return level;
    }
}

정보를 담고 있는.

고유의 ID와 level

빈 생성자는 레벨 0에 시작

createId는 UUID 앞쪽 몇자만 자르는데, 물론 중복확률이 더 올라가겠지만, 이거는 그냥 log용이라 괜찮음. 

새 객체를 생성하는 것이 내 입장에서는 조금 그렇긴 했음. 아 고유성 살리려고 했구나 ok.

하긴 레벨마다 고유의 Trace 객체를 가지고 있는 편이 훨 관리하기 좋음.

시작인지 확인하는 건 아직 왜 만든 지 잘 모르겠고.

 

@Getter
public class TraceStatus {
    private TraceId traceId;
    private Long startTimeMs;
    String message;
    public TraceStatus(TraceId traceId, Long startTimeMs, String message) {
        this.traceId = traceId;
        this.startTimeMs = startTimeMs;
        this.message = message;
    }
}

정보를 포함하는..

얘는 상태, 즉 시간 정보를 포함하는..

 

@Slf4j
@Component
public class HelloTraceV1 {
    private static final String START_PREFIX = "-->";
    private static final String COMPLETE_PREFIX = "<--";
    private static final String EX_PREFIX = "<X-";
    public TraceStatus begin(String message){
        TraceId traceId = new TraceId();
        Long startTimeMs = System.currentTimeMillis();
        log.info("[{}] {}{}", traceId.getId(), addSpace(START_PREFIX, traceId.getLevel()), message);

        return new TraceStatus(traceId, startTimeMs, message);
    }

    public void end(TraceStatus status){
        complete(status, null);
    }

    public void exception(TraceStatus status, Exception e){
        complete(status, e);
    }

    private void complete(TraceStatus status, Exception e){
        Long stopTimeMs = System.currentTimeMillis();
        long resultTimeMs = stopTimeMs - status.getStartTimeMs();
        TraceId traceId = status.getTraceId();

        if(e == null){
            log.info("[{}] {}{} time={}ms", traceId.getId(), addSpace(COMPLETE_PREFIX, traceId.getLevel()), status.getMessage(), resultTimeMs);
        }else{
            log.info("[{}] {}{} time={}ms ex={}", traceId.getId(), addSpace(COMPLETE_PREFIX, traceId.getLevel()), status.getMessage(), resultTimeMs, e.toString());
        }
    }

    private static String addSpace(String prefix, int level){
        StringBuilder sb = new StringBuilder();
        for(int i = 0; i< level; i++){
            sb.append((i==level - 1) ? "|" + prefix : "|   ");
        }
        return sb.toString();
    }
}

begin 하면 

TraceId 새롭게 생성하면서, 현재 시간 넣어주고, 

새 TraceStatus를 생성.

이 클래스가 Handler 역할일 듯. @Component 등록해서 하나로 쓸 거임.

 

TraceStatus는 호출한 곳에서 쓸 예정일 듯.

 

end, exception 메소드는 메소드 마지막 부분에 public이므로 호출해서 쓸 것 같은데,

각자 complete를 호출하는데 exception이 null이냐 아니냐의 차이.

에러가 났든, end든 여튼 호출한 쪽의 부모 메소드는 마지막 부분일 것이기 때문에 끝 로그를 남김. 결과적으로 로그를 남기는 그것 뿐인 듯.

 

exception도 public인데 try catch해서 잡아서 그 Exception을 쓸 듯.

 

complete에서는 이제 status가 가지고 있던 시간을 현재 시스템 시간에서 빼서 총 걸린 시간을 로그로 남김.

 

addSpace는 직역하면 공백추가인데, 

레벨만큼 공백을 추가시키는 거.

스트링 빌더를 쓰는데, 

level - 1까지 0부터 반복문 돌면서 

뭔가 레벨이 추가적으로 있으면 공백을 추가 시킴

 

 

class HelloTraceV1Test {
    @Test
    void begin_end(){
        HelloTraceV1 trace = new HelloTraceV1();
        TraceStatus status = trace.begin("hello");

        trace.end(status);
    }

    @Test
    void begin_exception(){
        HelloTraceV1 trace = new HelloTraceV1();
        TraceStatus status = trace.begin("hello");
        trace.exception(status, new IllegalStateException());
    }
}

 

테스트.

그냥 간단하게,

begin하면 

log.info("[{}] {}{}", traceId.getId(), addSpace(START_PREFIX, traceId.getLevel()), message);

이 로그가 나오고,

 

반환된 trace에서 end하면

log.info("[{}] {}{} time={}ms", traceId.getId(), addSpace(COMPLETE_PREFIX, traceId.getLevel()), status.getMessage(), resultTimeMs);

이 로그가 나옴.

 

 

 

 

지금 이건 완벽하지 않음. 하나씩 추가할 예정.

 

테스트 또한 사실 저렇게 콘솔로 확인하는게 아니라 특정 값이 옳은지 확인한다던지 그렇게 해야 함.

'스프링 > 스프링 핵심 원리 - 고급편' 카테고리의 다른 글

6. V2 파라미터로 동기화  (0) 2024.01.14
5. 로그 추적기 적용  (0) 2024.01.14
3. 요구사항 분석  (0) 2024.01.05
2. 예제 만들기  (0) 2024.01.05
1. 강의 소개  (0) 2023.12.25