Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- http
- JPQL
- db
- 스프링
- Proxy
- 알고리즘
- Thymeleaf
- jpa
- SpringBoot
- 스프링 핵심 원리
- spring
- 인프런
- springdatajpa
- 백준
- AOP
- Android
- Spring Boot
- 그리디
- 스프링 핵심 기능
- transaction
- pointcut
- 김영한
- Exception
- Servlet
- QueryDSL
- Greedy
- kotlin
- JDBC
- java
- 자바
Archives
- Today
- Total
개발자되기 프로젝트
필드 동기화 - 개발 본문
- 앞서 로그 추적기를 만들면서 다음 로그를 출력할 때 트랜잭션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
'인프런 > [인프런] 스프링 핵심 원리 - 고급' 카테고리의 다른 글
필드 동기화 - 동시성 문제 (0) | 2021.11.20 |
---|---|
필드 동기화 - 적용 (0) | 2021.11.20 |
로그 추적기 V2 - 적용 (0) | 2021.11.20 |
로그 추적기 V2 - 파라미터로 동기화 개발 (0) | 2021.11.20 |
로그 추적기 V1 - 적용 (0) | 2021.11.19 |
Comments