diff --git a/runtime/model/src/main/java/com/alipay/muagent/model/trace/TraceContext.java b/runtime/model/src/main/java/com/alipay/muagent/model/trace/TraceContext.java new file mode 100644 index 0000000..92973d6 --- /dev/null +++ b/runtime/model/src/main/java/com/alipay/muagent/model/trace/TraceContext.java @@ -0,0 +1,14 @@ +package com.alipay.muagent.model.trace; + +import lombok.Data; + +/** + * @author Joshua + * @version TraceContext.java v1.0 2024-11-20 20:21 + **/ +@Data +public class TraceContext { + + private String traceId; + +} diff --git a/runtime/model/src/main/java/com/alipay/muagent/model/trace/TraceThreadLocalContext.java b/runtime/model/src/main/java/com/alipay/muagent/model/trace/TraceThreadLocalContext.java new file mode 100644 index 0000000..3acb92e --- /dev/null +++ b/runtime/model/src/main/java/com/alipay/muagent/model/trace/TraceThreadLocalContext.java @@ -0,0 +1,44 @@ +package com.alipay.muagent.model.trace; + +import java.util.EmptyStackException; + +/** + * @author Joshua + * @version TraceThreadLocalContext.java v1.0 2024-11-20 20:24 + **/ +public class TraceThreadLocalContext { + + private final ThreadLocal traceContextThreadLocal = new ThreadLocal<>(); + + public void push(TraceContext traceContext) { + if (traceContext == null) { + return; + } + traceContextThreadLocal.set(traceContext); + } + + public TraceContext pop() throws EmptyStackException { + if (this.isEmpty()) { + return null; + } + TraceContext traceContext = traceContextThreadLocal.get(); + this.clear(); + return traceContext; + } + + public TraceContext getCurrentTraceContext() throws EmptyStackException { + if (this.isEmpty()) { + return null; + } + return traceContextThreadLocal.get(); + } + + public boolean isEmpty() { + TraceContext traceContext = traceContextThreadLocal.get(); + return traceContext == null; + } + + public void clear() { + traceContextThreadLocal.remove(); + } +} diff --git a/runtime/model/src/main/java/com/alipay/muagent/model/trace/TraceThreadLocalContextHolder.java b/runtime/model/src/main/java/com/alipay/muagent/model/trace/TraceThreadLocalContextHolder.java new file mode 100644 index 0000000..8028b3b --- /dev/null +++ b/runtime/model/src/main/java/com/alipay/muagent/model/trace/TraceThreadLocalContextHolder.java @@ -0,0 +1,23 @@ +package com.alipay.muagent.model.trace; + +/** + * @author Joshua + * @version TraceThreadLocalContextHolder.java v1.0 2024-11-20 20:28 + **/ +public class TraceThreadLocalContextHolder { + + /** + * singleton SofaTraceContext + */ + private static final TraceThreadLocalContext SINGLE_TRACE_CONTEXT = new TraceThreadLocalContext(); + + /** + * Get threadlocal trace context + * + * @return TraceThreadLocalContext + */ + public static TraceThreadLocalContext getTraceThreadLocalContext() { + return SINGLE_TRACE_CONTEXT; + } + +} diff --git a/runtime/util/pom.xml b/runtime/util/pom.xml index 7787170..281efad 100644 --- a/runtime/util/pom.xml +++ b/runtime/util/pom.xml @@ -18,6 +18,12 @@ + + com.alipay.muagent + model + 0.0.1-SNAPSHOT + + com.google.code.gson gson diff --git a/runtime/util/src/main/java/com/alipay/muagent/util/LoggerUtil.java b/runtime/util/src/main/java/com/alipay/muagent/util/LoggerUtil.java index 0e5e0f1..8c4a9d8 100644 --- a/runtime/util/src/main/java/com/alipay/muagent/util/LoggerUtil.java +++ b/runtime/util/src/main/java/com/alipay/muagent/util/LoggerUtil.java @@ -4,6 +4,8 @@ */ package com.alipay.muagent.util; +import com.alipay.muagent.model.trace.TraceThreadLocalContext; +import com.alipay.muagent.model.trace.TraceThreadLocalContextHolder; import org.slf4j.Logger; import org.slf4j.helpers.MessageFormatter; @@ -13,10 +15,16 @@ */ public class LoggerUtil { + /** + * 获取当前请求上下文的traceId + * @return traceId + */ private static String getTraceId() { - // todo - return ""; - + TraceThreadLocalContext traceThreadLocalContext = TraceThreadLocalContextHolder.getTraceThreadLocalContext(); + if (!traceThreadLocalContext.isEmpty()) { + return traceThreadLocalContext.getCurrentTraceContext().getTraceId(); + } + return null; } /** diff --git a/runtime/util/src/main/java/com/alipay/muagent/util/TraceUtil.java b/runtime/util/src/main/java/com/alipay/muagent/util/TraceUtil.java new file mode 100644 index 0000000..3001305 --- /dev/null +++ b/runtime/util/src/main/java/com/alipay/muagent/util/TraceUtil.java @@ -0,0 +1,101 @@ +package com.alipay.muagent.util; + +import java.net.InetAddress; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * @author Joshua + * @version TraceUtil.java v1.0 2024-11-20 20:34 + **/ +public class TraceUtil { + + private static final String EMPTY_STRING = ""; + + private static final AtomicInteger COUNT = new AtomicInteger(1000); + + private static String processId = null; + + private static String hexIpAddress = "ffffffff"; + + static { + try { + String ipAddressStr = getInetAddress(); + if (null != ipAddressStr) { + hexIpAddress = getHexAddress(ipAddressStr); + } + } catch (Exception e) { + /* + * empty catch + */ + } + } + + public static String generateTraceId() { + return getTraceId(hexIpAddress, System.currentTimeMillis(), getNextId()); + } + + private static String getTraceId(String ip, long timeStamp, int nextId) { + return ip + timeStamp + nextId + getProcessId(); + } + + private static String getProcessId() { + if (StringUtils.isNotBlank(processId)) { + return processId; + } + + String processName = java.lang.management.ManagementFactory.getRuntimeMXBean().getName(); + + if (StringUtils.isBlank(processName)) { + return EMPTY_STRING; + } + + String[] processSplitName = processName.split("@"); + + if (processSplitName.length == 0) { + return EMPTY_STRING; + } + + String pid = processSplitName[0]; + + if (StringUtils.isBlank(pid)) { + return EMPTY_STRING; + } + + processId = pid; + return pid; + } + + private static String getHexAddress(String ipAddressStr) { + final String[] ips = ipAddressStr.split("\\."); + StringBuilder stringBuilder = new StringBuilder(); + for (String partOfAddress : ips) { + String hex = Integer.toHexString(Integer.parseInt(partOfAddress)); + if (hex.length() == 1) { + stringBuilder.append('0').append(hex); + } else { + stringBuilder.append(hex); + } + } + return stringBuilder.toString(); + } + + private static String getInetAddress() { + try { + return InetAddress.getLocalHost().getHostAddress(); + } catch (Exception e) { + return null; + } + } + + private static int getNextId() { + while (true) { + int current = COUNT.get(); + int next = (current > 9000) ? 1000 : current + 1; + if (COUNT.compareAndSet(current, next)) { + return next; + } + } + } + + +} diff --git a/runtime/web/pom.xml b/runtime/web/pom.xml index b9d244f..89825bf 100644 --- a/runtime/web/pom.xml +++ b/runtime/web/pom.xml @@ -40,6 +40,11 @@ model 0.0.1-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-aop + \ No newline at end of file diff --git a/runtime/web/src/main/java/com/alipay/muagent/web/interceptor/RequestInterceptorAspect.java b/runtime/web/src/main/java/com/alipay/muagent/web/interceptor/RequestInterceptorAspect.java new file mode 100644 index 0000000..6d27bc6 --- /dev/null +++ b/runtime/web/src/main/java/com/alipay/muagent/web/interceptor/RequestInterceptorAspect.java @@ -0,0 +1,56 @@ +package com.alipay.muagent.web.interceptor; + +import com.alipay.muagent.model.trace.TraceContext; +import com.alipay.muagent.model.trace.TraceThreadLocalContext; +import com.alipay.muagent.model.trace.TraceThreadLocalContextHolder; +import com.alipay.muagent.util.TraceUtil; +import com.alipay.muagent.web.model.Result; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.*; +import org.springframework.stereotype.Component; + +/** + * @author Joshua + * @version RequestInterceptorAspect.java v1.0 2024-11-20 20:52 + **/ +@Aspect +@Component +public class RequestInterceptorAspect { + + @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping) || " + + "@annotation(org.springframework.web.bind.annotation.GetMapping) || " + + "@annotation(org.springframework.web.bind.annotation.PostMapping) || " + + "@annotation(org.springframework.web.bind.annotation.PutMapping) || " + + "@annotation(org.springframework.web.bind.annotation.DeleteMapping)") + public void requestMappingMethods() { + } + + @Before("requestMappingMethods()") + public void doBeforeRequestHandle() { + TraceContext traceContext = new TraceContext(); + traceContext.setTraceId(TraceUtil.generateTraceId()); + TraceThreadLocalContext traceThreadLocalContext = TraceThreadLocalContextHolder.getTraceThreadLocalContext(); + traceThreadLocalContext.push(traceContext); + } + + @AfterReturning(pointcut = "requestMappingMethods()", returning = "result") + public void handleAfterReturning(JoinPoint joinPoint, Object result) { + try { + TraceContext traceContext = TraceThreadLocalContextHolder.getTraceThreadLocalContext().getCurrentTraceContext(); + ((Result) result).setTraceId(traceContext.getTraceId()); + } catch (Exception e) { + /* + * empty catch + */ + } finally { + TraceThreadLocalContextHolder.getTraceThreadLocalContext().clear(); + } + } + + @AfterThrowing(pointcut = "requestMappingMethods()", throwing = "error") + public void handleAfterThrowing(JoinPoint joinPoint, Throwable error) { + TraceThreadLocalContextHolder.getTraceThreadLocalContext().clear(); + } + + +} diff --git a/runtime/web/src/main/java/com/alipay/muagent/web/model/Result.java b/runtime/web/src/main/java/com/alipay/muagent/web/model/Result.java index 8b4cb9e..6a92cb6 100644 --- a/runtime/web/src/main/java/com/alipay/muagent/web/model/Result.java +++ b/runtime/web/src/main/java/com/alipay/muagent/web/model/Result.java @@ -27,6 +27,8 @@ public class Result { private String host = getLocalHost(); + private String traceId; + /** * 创建一个方法执行成功的Result对象 *