[스프링 핵심원리 - 고급편 ] 로그 추적기 - 프로토타입 개발

JEONG SUJIN·2023년 2월 11일
0

스프링부트 기본

목록 보기
7/15

✔️ 로그 추적기 - 요구사항 분석

요구사항

  • 모든 PUBLIC 메서드의 호출과 응답 정보를 로그로 출력

  • 애플리케이션의 흐름을 변경하면 안됨 (로그를 남긴다고해서 비즈니스 로직의 동작에 영향을 주면 안됌)

  • 메서드 호출에서 걸린 시간

  • 정상흐름과 예외 흐름 구분 (예외발생시 예외정보가 남아야함)

  • 메서드 호출의 깊이 표현

  • HTTP 요청을 구분

    • HTTP 요청단위로 특정 ID를 남겨서 어떤 HTTP 요청에서 시작된 것인지 명확하게 구분이 가능해야함
    • 트랜잭션ID(DB트랜잭션X) 여기서는 하나의 HTTP 요청이 시작해서 끝날 때 까지를 하나의 트랜잭션이라 함.

로그 추적기 만들기

-TraceID 클래스
로그추적기는 트랜잭션 ID와 같이 표현하는 방법이 필요하다.
여기서는 트랜잭션ID와 깊이를 표현하는 level을 묶어서 TraceId 라는 개념을 만들었다.
TraceId는 단순히 id(트랜잭션ID)와 level 정보를 함께 가지고 있다.

study.advanced.trace 패키지생성

TraceId.java

package study.advanced.trace;

import java.util.UUID;

public class TraceId {

	private String id;
	private int level;
	

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

	private String createId() {
		return UUID.randomUUID().toString().substring(0,8);
	}
	
	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;
	}
	
}

TraceStatus 로그의 상태 정보를 나타내는 클래스

TraceStatus는 로그를 시작할 때의 상태정보를 가지고 있다.
상태정보는 로그를 종료할 때 사용된다.

OrderController.request() //로그시작
OrderController.request() time=1016ms //로그 종료
package study.advanced.trace;

// 로그의 상태정보
public class TraceStatus {
	
	private TraceId traceId; 
	private Long startTimeMs; 
	private String message;
	
	public TraceStatus(TraceId traceId, Long startTimeMs, String message) {
		this.traceId = traceId;
		this.startTimeMs = startTimeMs; 
		this.message = message;
	}

	public TraceId getTraceId() {
		return traceId;
	}

	public Long getStartITmeMs() {
		return startTimeMs;
	}

	public String getMessage() {
		return message;
	}


}
  • traceId : 내부에 트랜잭션ID와 level을 가지고 있다.
  • startTimeMs : 로그 시작간이다. 로그종료시 이 시작 시간을 기준으로 시작-종료까지 전체 수행 시간을 구할 수 있다.
  • message : 시작시 사용한 메시지. 이후 로그 종료시에도 이 메세지를 사용해서 출력한다.

study.advanced.trace.hellotrace 패키지생성

TraceId, TraceStatus를 사용해서 실제 로그를 생성하고, 처리하는 기능을 개발.

HelloTraceV1.java

package study.advanced.trace.hellotrace;

import org.springframework.stereotype.Component;

import lombok.extern.slf4j.Slf4j;
import study.advanced.trace.TraceId;
import study.advanced.trace.TraceStatus;

@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.getStartITmeMs();
		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());
		}
	}
	
	
	private Object 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();
	}
	
}

HelloTrace1 을 사용해서 실제 로그를 시작하고 종료할 수 있다. 그리고 로그를 출력하고 실행시간도 측정할 수 있다.
@Component: 싱글톤으로 사용하기 위해 스프링 빈으로 등록한다. 컴포넌트 스캔의 대상이 된다.

  • 공개 메서드
    로그추적기에서 사용되는 공개 메서드는 다음 3가지.

  • begin(..)

  • end(..)

  • exception(..)

하나씩 자세히 알아보기

  • TraceStatus begin(String message)
    • 로그를 시작한다.
    • 로그메세지를 파라미터로 받아서 시작 로그를 출력한다.
    • 응답 결과로 현재 로그의 상태인 TraceStatus를 반환한다.
  • void end(TraceStatus status)
    • 로그를 정상 종료한다.
    • 파라미터로 시작 로그의 상태(TraceStatus)를 전달 받는다. 이 값을 활용해서 실행시간을 계산하고, 종료시에도 시작할 때와 동일한 로그 메세지를 출력 할 수 있다.
    • 정상 흐름에서 호출한다.
  • void exception(TraceStatus status, Exception e)
    • 로그를 예외 상황으로 종료한다.
    • TraceeStatus, Exception 정보를 함께 전달받아서 실행시간, 예외 정보를 포함한 결과 로그를 출력한다.
    • 예외가 발생했을 때 호출한다.

테스트 작성

HelloTraceV1Test.java

package study.advanced.trace.hellotrace;

import org.junit.jupiter.api.Test;

import study.advanced.trace.TraceStatus;

public class HelloTraceV1Test {

	@Test
	void begin_end() {
		HelloTraceV1 trace = new HelloTraceV1();
		TraceStatus status = trace.begin("hello");
		trace.end(status); //trace 종료
	}
}

profile
기록하기

0개의 댓글