그냥 빈으로 (즉 디폴트는 싱글톤으로) 등록하고, 필드에 가지고 있게끔 해서 동기화 시키는 거다.
근데 이건 동시성 이슈가 있다.
싱글톤이기에 공유가 된다.
public interface LogTrace {
TraceStatus begin(String message);
void end(TraceStatus status);
void exception(TraceStatus status, Exception e);
}
일단 인터페이스로 만든다. 갈아끼울 것이다.
@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;
@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.createNextId();
}
}
@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 = traceIdHolder.createPreviousId();
}
}
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();
}
}
기존이랑 거의 똑같다. 달라진 점은,
@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);
}
여기서 syncTraceId()를 쓴다는 점.
private void syncTraceId(){
if(traceIdHolder == null){
traceIdHolder = new TraceId();
}else{
traceIdHolder = traceIdHolder.createNextId();
}
}
필드에 traceIdHolder라는 곳에 기억해 놓는 것이다.
만약 필드가 null이면 새로 만들고, 만약 있는데 syncTraceId를 다시 호출했다?
그러면 레벨을 하나 올리는 것 이다.
또 complete 부분도 바뀌었다.
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();
}
releaseTraceId() 하면
private void releaseTraceId() {
if(traceIdHolder.isFirstLevel()){
traceIdHolder = null;
}else{
traceIdHolder = traceIdHolder.createPreviousId();
}
}
레벨이 first레벨인데 release 시키는 거면 끝이니 그냥 null로, 즉 없에주는 거고,
first가 아니면 이전 레벨로 변화 시킨다.
@Test
void begin_end_level2(){
TraceStatus status1 = trace.begin("hello1");
TraceStatus status2 = trace.begin("hello2");
trace.end(status2);
trace.end(status1);
}
테스트 잘 된다.
begin일 때 syncTraceId라서 필드 보고 판단하는 거라서 알아서 잘 된다.
하지만, 동시성 문제가 있다.
'스프링 > 스프링 핵심 원리 - 고급편' 카테고리의 다른 글
11. 동시성 문제 (0) | 2024.01.14 |
---|---|
10. 필드 동기화 적용 (0) | 2024.01.14 |
8. V2 정리 (0) | 2024.01.14 |
7. V2 적용 (0) | 2024.01.14 |
6. V2 파라미터로 동기화 (0) | 2024.01.14 |