Notice
Recent Posts
Recent Comments
Link
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

개발자되기 프로젝트

필드 동기화 - 개발 본문

인프런/[인프런] 스프링 핵심 원리 - 고급

필드 동기화 - 개발

Seung__ 2021. 11. 20. 13:02
  • 앞서 로그 추적기를 만들면서 다음 로그를 출력할 때 트랜잭션ID 와 level 을 동기화 하는 문제가 있었다.
  • 이 문제를 해결하기 위해 TraceId 를 파라미터로 넘기도록 구현했다.
  • 이렇게 해서 동기화는 성공했지만, 
  • 로그를 출력하는 모든 메서드에 TraceId 파라미터를 추가해야 하는 문제가 발생했다.
  • TraceId 를 파라미터로 넘기지 않고 이 문제를 해결할 수 있는 방법은 없을까?

 

 

1. LogTrace Interface


public interface LogTrace {

    TraceStatus begin(String message);

    void end(TraceStatus status);

    void exception(TraceStatus status, Exception e);
}

 

2.  FieldLogTrace


  • FieldLogTrace 는 기존에 만들었던 HelloTraceV2 와 거의 같은 기능을 한다.
  • TraceId 를 동기화 하는 부분을 TraceId traceIdHolder 필드를 사용하도록 변경
  • 로그 시작시 생성된 traceID는 Trace에 TraceHolder 필드에 보관이 된다.
  • syncTraceId()
    • 로그 시작시 호출
    • TraceId 를 새로 만들거나 앞선 로그의 TraceId 를 참고해서 동기화하고, level 도 증가한다.
    • 최초 호출이면 TraceId 를 새로 만든다.
    • 직전 로그가 있으면 해당 로그의 TraceId 를 참고해서 동기화하고, level 도 하나 증가한다.
      결과를 traceIdHolder 에 보관한다.
  • releaseTraceId()
    • 로그 종료시 호출
    • 메서드를 추가로 호출할 때는 level 이 하나 증가해야 하지만, 
    • 메서드 호출이 끝나면 level 이 하나 감소해야 한다.
    • releaseTraceId() 는 level 을 하나 감소한다.
    • 만약 최초 호출( level==0 )이면 내부에서 관리하는 traceId 를 제거한다.
@Slf4j
public class FieldLogTrace implements LogTrace{

    private static final String START_PREFIX = "-->";
    private static final String COMPLETE_PREFIX = "<--";
    private static final String EX_PREFIX = "<X-";

    private TraceId traceIdHolder; //traceId 동기화, 동시성 이슈 발생.

    @Override
    public TraceStatus begin(String message) {
        syncTraceId();
        TraceId traceId = traceIdHolder;
        Long startTimeMs = System.currentTimeMillis();
        log.info("[{}] {}{}", traceId.getId(), addSpace(START_PREFIX, traceId.getLevel()), message);
        return new TraceStatus(traceId, startTimeMs, message);
    }

    private void syncTraceId(){
        if (traceIdHolder == null){
            traceIdHolder = new TraceId();
        } else {
            traceIdHolder = traceIdHolder.creatNextId();
        }
    }

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

    @Override
    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(EX_PREFIX, traceId.getLevel()), status.getMessage(), resultTimeMs, e.toString());
        }

        releaseTraceId();
    }

    private void releaseTraceId() {
        if (traceIdHolder.isFirstLevel()){
            traceIdHolder = null;
        }else {
            traceIdHolder.creatPreviousId();
        }
    }

    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();
    }
}

 

 

3. Test


class FieldLogTraceTest {

    FieldLogTrace trace = new FieldLogTrace();

    @Test
    void begin_end_level2(){
        //trace에 traceId holder가 있음. 처음의 traceID를 가지고 있음.
        TraceStatus status1 = trace.begin("hello1");
        TraceStatus status2 = trace.begin("hello2");
        trace.end(status2);
        trace.end(status1);

    }

    @Test
    void begin_exception_level2(){
        //trace에 traceId holder가 있음. 처음의 traceID를 가지고 있음.
        TraceStatus status1 = trace.begin("hello1");
        TraceStatus status2 = trace.begin("hello2");
        trace.exception(status2, new IllegalStateException());
        trace.exception(status1, new IllegalStateException());

    }

}
[908f527a] hello1
[908f527a] |-->hello2
[908f527a] |<--hello2 time=3ms
[908f527a] hello1 time=11ms
[cf33e392] hello1
[cf33e392] |-->hello2
[cf33e392] |<X-hello2 time=0ms ex=java.lang.IllegalStateException
[cf33e392] hello1 time=1ms ex=java.lang.IllegalStateException

 

 

4. GitHub : 211120 Filed Synchronization


 

GitHub - bsh6463/Spring_Advanced: initial

initial. Contribute to bsh6463/Spring_Advanced development by creating an account on GitHub.

github.com

 

Comments