spring core advanced : log trace v3 - FieldLogTrace
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
package com.example.advanced;
|
||||
|
||||
import com.example.advanced.trace.logtrace.FieldLogTrace;
|
||||
import com.example.advanced.trace.logtrace.LogTrace;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class LogTraceConfig {
|
||||
|
||||
@Bean
|
||||
public LogTrace logTrace() {
|
||||
return new FieldLogTrace();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.example.advanced.app.v3;
|
||||
|
||||
import com.example.advanced.trace.TraceStatus;
|
||||
import com.example.advanced.trace.logtrace.LogTrace;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
public class OrderControllerV3 {
|
||||
|
||||
private final OrderServiceV3 orderService;
|
||||
private final LogTrace trace;
|
||||
|
||||
@GetMapping("/v3/request")
|
||||
public String request(String itemId) {
|
||||
|
||||
TraceStatus status = null;
|
||||
try {
|
||||
status = trace.begin("OrderController.request()");
|
||||
orderService.orderItem(itemId);
|
||||
trace.end(status);
|
||||
return "ok";
|
||||
} catch (Exception e) {
|
||||
trace.exception(status, e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.example.advanced.app.v3;
|
||||
|
||||
import com.example.advanced.trace.TraceStatus;
|
||||
import com.example.advanced.trace.logtrace.LogTrace;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
@RequiredArgsConstructor
|
||||
public class OrderRepositoryV3 {
|
||||
|
||||
private final LogTrace trace;
|
||||
|
||||
public void save(String itemId) {
|
||||
|
||||
TraceStatus status = null;
|
||||
try {
|
||||
status = trace.begin("OrderRepository.save()");
|
||||
// 저장 로직
|
||||
if (itemId.equals("ex")) {
|
||||
throw new IllegalStateException("예외 발생!");
|
||||
}
|
||||
sleep(1000);
|
||||
trace.end(status);
|
||||
} catch (Exception e) {
|
||||
trace.exception(status, e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private void sleep(int millis) {
|
||||
try {
|
||||
Thread.sleep(millis);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.example.advanced.app.v3;
|
||||
|
||||
import com.example.advanced.trace.TraceStatus;
|
||||
import com.example.advanced.trace.logtrace.LogTrace;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class OrderServiceV3 {
|
||||
|
||||
private final OrderRepositoryV3 orderRepository;
|
||||
private final LogTrace trace;
|
||||
|
||||
public void orderItem(String itemId) {
|
||||
TraceStatus status = null;
|
||||
try {
|
||||
status = trace.begin("OrderService.orderItem()");
|
||||
orderRepository.save(itemId);
|
||||
trace.end(status);
|
||||
} catch (Exception e) {
|
||||
trace.exception(status, e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package com.example.advanced.trace.logtrace;
|
||||
|
||||
import com.example.advanced.trace.TraceId;
|
||||
import com.example.advanced.trace.TraceStatus;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@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.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.getClass());
|
||||
}
|
||||
|
||||
releaseTraceId();
|
||||
}
|
||||
|
||||
private void releaseTraceId() {
|
||||
if (traceIdHolder.isFirstLevel()) {
|
||||
traceIdHolder = null; // destroy
|
||||
} else {
|
||||
traceIdHolder = traceIdHolder.createPreviousId();
|
||||
}
|
||||
}
|
||||
|
||||
private 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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.example.advanced.trace.logtrace;
|
||||
|
||||
import com.example.advanced.trace.TraceStatus;
|
||||
|
||||
public interface LogTrace {
|
||||
|
||||
TraceStatus begin(String message);
|
||||
void end(TraceStatus status);
|
||||
void exception(TraceStatus status, Exception e);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.example.advanced.trace.logtrace;
|
||||
|
||||
import com.example.advanced.trace.TraceStatus;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class FieldLogTraceTest {
|
||||
|
||||
FieldLogTrace trace = new FieldLogTrace();
|
||||
|
||||
@Test
|
||||
void begin_end_level2() {
|
||||
TraceStatus status1 = trace.begin("hello1");
|
||||
TraceStatus status2 = trace.begin("hello2");
|
||||
trace.end(status2);
|
||||
trace.end(status1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void begin_exception_level2() {
|
||||
TraceStatus status1 = trace.begin("hello1");
|
||||
TraceStatus status2 = trace.begin("hello2");
|
||||
trace.exception(status2, new IllegalStateException());
|
||||
trace.exception(status1, new IllegalStateException());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user