diff --git a/src/main/java/com/profiler/context/CallStack.java b/src/main/java/com/profiler/context/CallStack.java index 83c29f5c5..b33ab065d 100644 --- a/src/main/java/com/profiler/context/CallStack.java +++ b/src/main/java/com/profiler/context/CallStack.java @@ -8,14 +8,23 @@ import java.util.logging.Logger; */ public class CallStack { + private Span span; // CallStack을 동시성 환경에서 복사해서 볼수 있는 방법이 필요함. private StackFrame[] stack = new StackFrame[4]; // 추적 depth크기 제한을 위해서 필요. 해당 사이즈를 넘어갈경우 부드럽게 트레이스를 무시하는 로직이 필요함. - private final int TRACE_STACK_MAX_SIZE = 64; + private final int TRACE_STACK_MAX_SIZE = 32; private int index = -1; + public CallStack(TraceID traceId) { + this.span = new Span(traceId); + } + + public Span getSpan() { + return span; + } + // copy시의 락 생각할 경우 좀더 정교하게 잡을수 있을듯. // push, pop, copy만 락을 잡아도 될거 같은 생각이 듬. public synchronized StackFrame getCurrentStackFrame() { @@ -38,7 +47,7 @@ public class CallStack { index++; if (index > stack.length - 1) { StackFrame[] old = stack; - stack = new StackFrame[index + 4]; + stack = new RootStackFrame[index + 4]; System.arraycopy(old, 0, stack, 0, old.length); } } diff --git a/src/main/java/com/profiler/context/StackFrame.java b/src/main/java/com/profiler/context/RootStackFrame.java similarity index 77% rename from src/main/java/com/profiler/context/StackFrame.java rename to src/main/java/com/profiler/context/RootStackFrame.java index eca6e4e5d..2ed348bc0 100644 --- a/src/main/java/com/profiler/context/StackFrame.java +++ b/src/main/java/com/profiler/context/RootStackFrame.java @@ -3,40 +3,43 @@ package com.profiler.context; /** * */ -public class StackFrame { +public class RootStackFrame implements StackFrame { private int stackId; private Span span; - public StackFrame(Span span) { + + public RootStackFrame(Span span) { this.span = span; } - public TraceID getTraceID() { - return span.getTraceID(); - } - + @Override public int getStackFrameId() { return stackId; } + @Override public void setStackFrameId(int stackId) { this.stackId = stackId; } + @Override public void markBeforeTime() { this.span.setStartTime(System.currentTimeMillis()); } + @Override public long getBeforeTime() { return this.span.getStartTime(); } + @Override public void markAfterTime() { this.span.setEndTime(System.currentTimeMillis()); } + @Override public long getAfterTime() { return this.span.getEndTime(); } @@ -50,13 +53,16 @@ public class StackFrame { return span; } + @Override public void attachObject(Object object) { } + @Override public Object getAttachObject(Object object) { return null; } + @Override public Object detachObject() { return null; } diff --git a/src/main/java/com/profiler/context/SubSpan.java b/src/main/java/com/profiler/context/SubSpan.java new file mode 100644 index 000000000..aea4ea958 --- /dev/null +++ b/src/main/java/com/profiler/context/SubSpan.java @@ -0,0 +1,153 @@ +package com.profiler.context; + +import com.profiler.Agent; +import com.profiler.common.ServiceType; + +import java.util.ArrayList; +import java.util.List; + +/** + * Span represent RPC + * + * @author netspider + */ +public class SubSpan implements Thriftable { + + private final Span parentSpan; + + private short sequence; + + private long startTime; + private long endTime; + private String serviceName; + private String rpc; + private ServiceType serviceType; + private String endPoint; + + private final List annotations = new ArrayList(5); + + public SubSpan(Span parentSpan) { + this.parentSpan = parentSpan; + } + + public Span getParentSpan() { + return parentSpan; + } + + public int getSequence() { + return sequence; + } + + public void setSequence(short sequence) { + this.sequence = sequence; + } + + public boolean addAnnotation(HippoAnnotation annotation) { + return annotations.add(annotation); + } + + public int getAnnotationSize() { + return annotations.size(); + } + + public String getEndPoint() { + return this.endPoint; + } + + public String getServiceName() { + return serviceName; + } + + public void setServiceName(String serviceName) { + this.serviceName = serviceName; + } + + public String getRpc() { + return rpc; + } + + public void setRpc(String rpc) { + this.rpc = rpc; + } + + public void setEndPoint(String endPoint) { + this.endPoint = endPoint; + } + + public void setStartTime(long startTime) { + this.startTime = startTime; + } + + public long getStartTime() { + return startTime; + } + + public void setEndTime(long endTime) { + this.endTime = endTime; + } + + public long getEndTime() { + return endTime; + } + + public ServiceType getServiceType() { + return serviceType; + } + + public void setServiceType(ServiceType serviceType) { + this.serviceType = serviceType; + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + + sb.append("{"); + sb.append("\n\t ParentTraceID=").append(parentSpan.getTraceID()); + sb.append("\n\t sequence=").append(sequence); + sb.append(",\n\t StartTime=").append(startTime); + sb.append(", EndTime=").append(endTime); + sb.append(",\n\t Name=").append(rpc); + sb.append(", ServiceName=").append(serviceName); + sb.append(", ServiceType=").append(serviceType); + sb.append(", EndPoint=").append(endPoint); + sb.append(", Seq=").append(sequence); + sb.append(",\n\t Annotations = {"); + for (HippoAnnotation a : annotations) { + sb.append("\n\t\t").append(a); + } + sb.append("\n\t}"); + + sb.append("}"); + + return sb.toString(); + } + + public com.profiler.common.dto.thrift.SubSpan toThrift() { + com.profiler.common.dto.thrift.SubSpan span = new com.profiler.common.dto.thrift.SubSpan(); + + span.setAgentId(Agent.getInstance().getAgentId()); + long parentSpanStartTime = parentSpan.getStartTime(); + span.setStartElapsed((int) (startTime - parentSpanStartTime)); + span.setEndElapsed((int) (endTime - startTime)); + TraceID parentSpanTraceID = parentSpan.getTraceID(); + span.setMostTraceId(parentSpanTraceID.getId().getMostSignificantBits()); + span.setLeastTraceId(parentSpanTraceID.getId().getLeastSignificantBits()); + span.setRpc(rpc); + span.setServiceName(serviceName); + span.setServiceType(serviceType.getCode()); + + span.setSpanId(parentSpanTraceID.getSpanId()); + span.setSequence(sequence); + + span.setEndPoint(endPoint); + + // 여기서 데이터 인코딩을 하자. + List annotationList = new ArrayList(annotations.size()); + for (HippoAnnotation a : annotations) { + annotationList.add(a.toThrift()); + } + span.setAnnotations(annotationList); + + return span; + } +} diff --git a/src/main/java/com/profiler/context/SubStackFrame.java b/src/main/java/com/profiler/context/SubStackFrame.java new file mode 100644 index 000000000..27cc06abb --- /dev/null +++ b/src/main/java/com/profiler/context/SubStackFrame.java @@ -0,0 +1,68 @@ +package com.profiler.context; + +/** + * + */ +public class SubStackFrame implements StackFrame { + private SubSpan subSpan; + private int stackId; + + public SubStackFrame(SubSpan subSpan) { + this.subSpan = subSpan; + } + + @Override + public int getStackFrameId() { + return stackId; + } + + @Override + public void setStackFrameId(int stackId) { + this.stackId = stackId; + } + + @Override + public void markBeforeTime() { + subSpan.setStartTime(System.currentTimeMillis()); + } + + @Override + public long getBeforeTime() { + return subSpan.getStartTime(); + } + + @Override + public void markAfterTime() { + subSpan.setEndTime(System.currentTimeMillis()); + } + + @Override + public long getAfterTime() { + return subSpan.getEndTime(); + } + + public void setSequence(short sequence) { + subSpan.setSequence(sequence); + } + + public SubSpan getSubSpan() { + return subSpan; + } + + @Override + public void attachObject(Object object) { + //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public Object getAttachObject(Object object) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public Object detachObject() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + +} diff --git a/src/main/java/com/profiler/context/Trace.java b/src/main/java/com/profiler/context/Trace.java index 1192b9117..97e878091 100644 --- a/src/main/java/com/profiler/context/Trace.java +++ b/src/main/java/com/profiler/context/Trace.java @@ -21,30 +21,37 @@ public final class Trace { public static final int NOCHECK_STACKID = -1; public static final int ROOT_STACKID = 0; + private short sequence; + private boolean tracingEnabled = true; - private TraceID root; + // private TraceID root; private CallStack callStack; private DataSender dataSender = DEFULT_DATA_SENDER; public Trace() { // traceObject에서 spanid의 유효성을 히스토리를 관리한다면 같은 thread에서는 span랜덤생성아이디의 충돌을 방지할수 있기는 함. - this.root = TraceID.newTraceId(); - this.callStack = new CallStack(); + TraceID traceId = TraceID.newTraceId(); + this.callStack = new CallStack(traceId); this.callStack.push(); - StackFrame stackFrame = createStackFrame(root, ROOT_STACKID); + StackFrame stackFrame = createRootStackFrame(ROOT_STACKID, callStack.getSpan()); this.callStack.setStackFrame(stackFrame); } public Trace(TraceID continueRoot) { - this.root = continueRoot; - this.callStack = new CallStack(); +// this.root = continueRoot; + this.callStack = new CallStack(continueRoot); this.callStack.push(); - StackFrame stackFrame = createStackFrame(continueRoot, ROOT_STACKID); +// StackFrame stackFrame = createStackFrame(ROOT_STACKID); + StackFrame stackFrame = createRootStackFrame(ROOT_STACKID, callStack.getSpan()); this.callStack.setStackFrame(stackFrame); } + public CallStack getCallStack() { + return callStack; + } + public DataSender getDataSender() { return dataSender; } @@ -53,18 +60,18 @@ public final class Trace { this.dataSender = dataSender; } - public void handle(TraceHandler handler) { - try { - TraceID nextId = getNextTraceId(); - callStack.push(); - StackFrame stackFrame = createStackFrame(nextId, HANDLER_STACKID); - callStack.setStackFrame(stackFrame); - handler.handle(nextId); - } finally { - // stackID check하면 좋을듯. - callStack.pop(); - } - } +// public void handle(TraceHandler handler) { +// try { +//// TraceID nextId = getNextTraceId(); +// callStack.push(); +// StackFrame stackFrame = createStackFrame(nextId, HANDLER_STACKID); +// callStack.setStackFrame(stackFrame); +// handler.handle(nextId); +// } finally { +// // stackID check하면 좋을듯. +// callStack.pop(); +// } +// } public AsyncTrace createAsyncTrace() { // 경우에 따라 별도 timeout 처리가 있어야 될수도 있음. @@ -75,10 +82,18 @@ public final class Trace { return asyncTrace; } - private StackFrame createStackFrame(TraceID nextId, int stackId) { - Span span = new Span(nextId); - StackFrame stackFrame = new StackFrame(span); + private StackFrame createSubStackFrame(int stackId) { + SubSpan subSpan = new SubSpan(callStack.getSpan()); + SubStackFrame stackFrame = new SubStackFrame(subSpan); stackFrame.setStackFrameId(stackId); + stackFrame.setSequence(sequence++); + return stackFrame; + } + + private StackFrame createRootStackFrame(int stackId, Span span) { + RootStackFrame stackFrame = new RootStackFrame(span); + stackFrame.setStackFrameId(stackId); + stackFrame.setSpan(span); return stackFrame; } @@ -86,6 +101,7 @@ public final class Trace { traceBlockBegin(NOCHECK_STACKID); } + public void markBeforeTime() { StackFrame stackFrame = getCurrentStackFrame(); stackFrame.markBeforeTime(); @@ -113,9 +129,9 @@ public final class Trace { public void traceBlockBegin(int stackId) { - TraceID nextId = getNextTraceId(); +// TraceID nextId = getNextTraceId(); callStack.push(); - StackFrame stackFrame = createStackFrame(nextId, stackId); + StackFrame stackFrame = createSubStackFrame(stackId); callStack.setStackFrame(stackFrame); } @@ -138,10 +154,18 @@ public final class Trace { // 자체 stack dump를 하면 오류발견이 쉬울것으로 생각됨. logger.warning("Corrupted CallStack found. StackId not matched"); } - logSpan(currentStackFrame); + if (currentStackFrame instanceof RootStackFrame) { + logSpan(((RootStackFrame) currentStackFrame).getSpan()); + } else { + logSpan(((SubStackFrame) currentStackFrame).getSubSpan()); + } callStack.pop(); } + private void logEvent() { + + } + public StackFrame getCurrentStackFrame() { return callStack.getCurrentStackFrame(); } @@ -162,8 +186,8 @@ public final class Trace { * * @return */ - public TraceID getCurrentTraceId() { - return callStack.getCurrentStackFrame().getTraceID(); + public TraceID getTraceId() { + return callStack.getSpan().getTraceID(); } public void enable() { @@ -174,14 +198,34 @@ public final class Trace { tracingEnabled = false; } + @Deprecated public TraceID getNextTraceId() { - TraceID current = getCurrentTraceId(); + TraceID current = getTraceId(); return current.getNextTraceId(); } + void logSpan(SubSpan span) { + try { + if (logger.isLoggable(Level.INFO)) { + logger.info("[WRITE SubSPAN]" + span + " CurrentThreadID=" + Thread.currentThread().getId() + ",\n\t CurrentThreadName=" + Thread.currentThread().getName() + "\n\n"); + } - void logSpan(StackFrame stackFrame) { - Span span = stackFrame.getSpan(); + // TODO: remove this, just for debugging + // if (spanMap.size() > 0) { + // System.out.println("##################################################################"); + // System.out.println("# [DEBUG MSG] WARNING SpanMap size > 0 check spanMap. #"); + // System.out.println("##################################################################"); + // System.out.println("current spamMap=" + spanMap); + // } + + dataSender.send(span); +// span.cancelTimer(); + } catch (Exception e) { + logger.log(Level.SEVERE, e.getMessage(), e); + } + } + + void logSpan(Span span) { try { if (logger.isLoggable(Level.INFO)) { logger.info("[WRITE SPAN]" + span + " CurrentThreadID=" + Thread.currentThread().getId() + ",\n\t CurrentThreadName=" + Thread.currentThread().getName() + "\n\n"); @@ -265,8 +309,15 @@ public final class Trace { return; try { - Span span = getCurrentStackFrame().getSpan(); - span.addAnnotation(new HippoAnnotation(System.currentTimeMillis(), key, value)); + // TODO API 단일화 필요. + StackFrame currentStackFrame = getCurrentStackFrame(); + if (currentStackFrame instanceof RootStackFrame) { + Span span = ((RootStackFrame) currentStackFrame).getSpan(); + span.addAnnotation(new HippoAnnotation(System.currentTimeMillis(), key, value)); + } else { + SubSpan span = ((SubStackFrame) currentStackFrame).getSubSpan(); + span.addAnnotation(new HippoAnnotation(System.currentTimeMillis(), key, value)); + } } catch (Exception e) { logger.log(Level.SEVERE, e.getMessage(), e); } @@ -284,10 +335,19 @@ public final class Trace { return; try { - Span span = getCurrentStackFrame().getSpan(); - span.setServiceType(serviceType); - span.setServiceName(serviceName); - span.setRpc(rpc); + // TODO API 단일화 필요. + StackFrame currentStackFrame = getCurrentStackFrame(); + if (currentStackFrame instanceof RootStackFrame) { + Span span = ((RootStackFrame) currentStackFrame).getSpan(); + span.setServiceType(serviceType); + span.setServiceName(serviceName); + span.setRpc(rpc); + } else { + SubSpan span = ((SubStackFrame) currentStackFrame).getSubSpan(); + span.setServiceType(serviceType); + span.setServiceName(serviceName); + span.setRpc(rpc); + } } catch (Exception e) { logger.log(Level.SEVERE, e.getMessage(), e); } @@ -297,10 +357,16 @@ public final class Trace { public void recordEndPoint(final String endPoint) { if (!tracingEnabled) return; - + // TODO API 단일화 필요. try { - Span span = getCurrentStackFrame().getSpan(); - span.setEndPoint(endPoint); + StackFrame currentStackFrame = getCurrentStackFrame(); + if (currentStackFrame instanceof RootStackFrame) { + Span span = ((RootStackFrame) currentStackFrame).getSpan(); + span.setEndPoint(endPoint); + } else { + SubSpan span = ((SubStackFrame) currentStackFrame).getSubSpan(); + span.setEndPoint(endPoint); + } } catch (Exception e) { logger.log(Level.SEVERE, e.getMessage(), e); } @@ -311,8 +377,14 @@ public final class Trace { return; try { - Span span = getCurrentStackFrame().getSpan(); - span.addAnnotation(new HippoAnnotation(System.currentTimeMillis(), key)); + StackFrame currentStackFrame = getCurrentStackFrame(); + if (currentStackFrame instanceof RootStackFrame) { + Span span = ((RootStackFrame) currentStackFrame).getSpan(); + span.addAnnotation(new HippoAnnotation(System.currentTimeMillis(), key)); + } else { + SubSpan span = ((SubStackFrame) currentStackFrame).getSubSpan(); + span.addAnnotation(new HippoAnnotation(System.currentTimeMillis(), key)); + } } catch (Exception e) { logger.log(Level.SEVERE, e.getMessage(), e); diff --git a/src/main/java/com/profiler/modifier/DefaultModifierRegistry.java b/src/main/java/com/profiler/modifier/DefaultModifierRegistry.java index 7c6d6b471..afbefd26b 100644 --- a/src/main/java/com/profiler/modifier/DefaultModifierRegistry.java +++ b/src/main/java/com/profiler/modifier/DefaultModifierRegistry.java @@ -60,27 +60,27 @@ public class DefaultModifierRegistry implements ModifierRegistry { } } - public void addConnectorModifier() { - HTTPClientModifier httpClientModifier = new HTTPClientModifier(byteCodeInstrumentor); - addModifier(httpClientModifier); + public void addConnectorModifier() { + HTTPClientModifier httpClientModifier = new HTTPClientModifier(byteCodeInstrumentor); + addModifier(httpClientModifier); - MemcachedClientModifier memcachedClientModifier = new MemcachedClientModifier(byteCodeInstrumentor); - addModifier(memcachedClientModifier); - - ArcusClientModifier arcusClientModifier = new ArcusClientModifier(byteCodeInstrumentor); - addModifier(arcusClientModifier); +// MemcachedClientModifier memcachedClientModifier = new MemcachedClientModifier(byteCodeInstrumentor); +// addModifier(memcachedClientModifier); +// +// ArcusClientModifier arcusClientModifier = new ArcusClientModifier(byteCodeInstrumentor); +// addModifier(arcusClientModifier); +// +// BaseOperationModifier baseOperationModifier = new BaseOperationModifier(byteCodeInstrumentor); +// addModifier(baseOperationModifier); +// +// CacheManagerModifier cacheManagerModifier = new CacheManagerModifier(byteCodeInstrumentor); +// addModifier(cacheManagerModifier); + } - BaseOperationModifier baseOperationModifier = new BaseOperationModifier(byteCodeInstrumentor); - addModifier(baseOperationModifier); - - CacheManagerModifier cacheManagerModifier = new CacheManagerModifier(byteCodeInstrumentor); - addModifier(cacheManagerModifier); - } - - public void addBLOCModifier() { - HTTPHandlerModifier httpHandlerModifier = new HTTPHandlerModifier(byteCodeInstrumentor); - addModifier(httpHandlerModifier); - } + public void addBLOCModifier() { + HTTPHandlerModifier httpHandlerModifier = new HTTPHandlerModifier(byteCodeInstrumentor); + addModifier(httpHandlerModifier); + } public void addTomcatModifier() { StandardHostValveInvokeModifier standardHostValveInvokeModifier = new StandardHostValveInvokeModifier(byteCodeInstrumentor); diff --git a/src/main/java/com/profiler/modifier/bloc/handler/interceptors/ExecuteMethodInterceptor.java b/src/main/java/com/profiler/modifier/bloc/handler/interceptors/ExecuteMethodInterceptor.java index 2b9a88a4c..d249a6e4b 100644 --- a/src/main/java/com/profiler/modifier/bloc/handler/interceptors/ExecuteMethodInterceptor.java +++ b/src/main/java/com/profiler/modifier/bloc/handler/interceptors/ExecuteMethodInterceptor.java @@ -57,7 +57,7 @@ public class ExecuteMethodInterceptor implements StaticAroundInterceptor, ByteCo } else { trace = new Trace(); if (logger.isLoggable(Level.INFO)) { - logger.info("TraceID not exist. start new trace. " + trace.getCurrentTraceId()); + logger.info("TraceID not exist. start new trace. " + trace.getTraceId()); logger.log(Level.FINE, "requestUrl:" + requestURL + " clientIp" + clientIP + " parameter:" + parameters); } traceContext.attachTraceObject(trace); @@ -81,7 +81,8 @@ public class ExecuteMethodInterceptor implements StaticAroundInterceptor, ByteCo @Override public void after(Object target, String className, String methodName, String parameterDescription, Object[] args, Object result) { if (logger.isLoggable(Level.INFO)) { - logger.info("after " + StringUtils.toString(target) + " " + className + "." + methodName + parameterDescription + " args:" + Arrays.toString(args) + " result:" + result); +// logger.info("after " + StringUtils.toString(target) + " " + className + "." + methodName + parameterDescription + " args:" + Arrays.toString(args) + " result:" + result); + logger.info("after " + StringUtils.toString(target) + " " + className + "." + methodName + parameterDescription + " args:" + Arrays.toString(args)); } TraceContext traceContext = TraceContext.getTraceContext(); diff --git a/src/main/java/com/profiler/modifier/connector/interceptors/Execute2MethodInterceptor.java b/src/main/java/com/profiler/modifier/connector/interceptors/Execute2MethodInterceptor.java index 30ae463f0..739cefcb9 100644 --- a/src/main/java/com/profiler/modifier/connector/interceptors/Execute2MethodInterceptor.java +++ b/src/main/java/com/profiler/modifier/connector/interceptors/Execute2MethodInterceptor.java @@ -21,7 +21,7 @@ import com.profiler.util.StringUtils; /** * Method interceptor *

- * + *

*

  * org.apache.http.impl.client.AbstractHttpClient.
  * public final HttpResponse execute(HttpUriRequest request) throws IOException, ClientProtocolException
@@ -29,60 +29,60 @@ import com.profiler.util.StringUtils;
  */
 public class Execute2MethodInterceptor implements StaticAroundInterceptor, ByteCodeMethodDescriptorSupport {
 
-	private final Logger logger = Logger.getLogger(Execute2MethodInterceptor.class.getName());
-	private MethodDescriptor descriptor;
+    private final Logger logger = Logger.getLogger(Execute2MethodInterceptor.class.getName());
+    private MethodDescriptor descriptor;
 
-	@Override
-	public void before(Object target, String className, String methodName, String parameterDescription, Object[] args) {
-		if (logger.isLoggable(Level.INFO)) {
-			logger.info("before " + StringUtils.toString(target) + " " + className + "." + methodName + parameterDescription + " args:" + Arrays.toString(args));
-		}
-		TraceContext traceContext = TraceContext.getTraceContext();
-		Trace trace = traceContext.currentTraceObject();
-		if (trace == null) {
-			return;
-		}
-		trace.traceBlockBegin();
-		trace.markBeforeTime();
+    @Override
+    public void before(Object target, String className, String methodName, String parameterDescription, Object[] args) {
+        if (logger.isLoggable(Level.INFO)) {
+            logger.info("before " + StringUtils.toString(target) + " " + className + "." + methodName + parameterDescription + " args:" + Arrays.toString(args));
+        }
+        TraceContext traceContext = TraceContext.getTraceContext();
+        Trace trace = traceContext.currentTraceObject();
+        if (trace == null) {
+            return;
+        }
+        trace.traceBlockBegin();
+        trace.markBeforeTime();
 
-		TraceID nextId = trace.getCurrentTraceId();
+        TraceID nextId = trace.getTraceId();
 
-		final HttpUriRequest request = (HttpUriRequest) args[0];
+        final HttpUriRequest request = (HttpUriRequest) args[0];
 
-		// UUID format을 그대로.
-		request.addHeader(Header.HTTP_TRACE_ID.toString(), nextId.getId().toString());
-		request.addHeader(Header.HTTP_SPAN_ID.toString(), Long.toString(nextId.getSpanId()));
-		request.addHeader(Header.HTTP_PARENT_SPAN_ID.toString(), Long.toString(nextId.getParentSpanId()));
-		request.addHeader(Header.HTTP_SAMPLED.toString(), String.valueOf(nextId.isSampled()));
-		request.addHeader(Header.HTTP_FLAGS.toString(), String.valueOf(nextId.getFlags()));
+        // UUID format을 그대로.
+        request.addHeader(Header.HTTP_TRACE_ID.toString(), nextId.getId().toString());
+        request.addHeader(Header.HTTP_SPAN_ID.toString(), Long.toString(nextId.getSpanId()));
+        request.addHeader(Header.HTTP_PARENT_SPAN_ID.toString(), Long.toString(nextId.getParentSpanId()));
+        request.addHeader(Header.HTTP_SAMPLED.toString(), String.valueOf(nextId.isSampled()));
+        request.addHeader(Header.HTTP_FLAGS.toString(), String.valueOf(nextId.getFlags()));
 
-		HttpHost host = URIUtils.extractHost(request.getURI());
+        HttpHost host = URIUtils.extractHost(request.getURI());
 
-		trace.recordRpcName(ServiceType.HTTP_CLIENT, request.getProtocolVersion().toString(), "CLIENT");
-		trace.recordEndPoint(host.getHostName());
-		trace.recordAttribute("http.url", request.getRequestLine().getUri());
-	}
+        trace.recordRpcName(ServiceType.HTTP_CLIENT, request.getProtocolVersion().toString(), "CLIENT");
+        trace.recordEndPoint(host.getHostName());
+        trace.recordAttribute("http.url", request.getRequestLine().getUri());
+    }
 
-	@Override
-	public void after(Object target, String className, String methodName, String parameterDescription, Object[] args, Object result) {
-		if (logger.isLoggable(Level.INFO)) {
-			logger.info("after " + StringUtils.toString(target) + " " + className + "." + methodName + parameterDescription + " args:" + Arrays.toString(args) + " result:" + result);
-		}
+    @Override
+    public void after(Object target, String className, String methodName, String parameterDescription, Object[] args, Object result) {
+        if (logger.isLoggable(Level.INFO)) {
+            logger.info("after " + StringUtils.toString(target) + " " + className + "." + methodName + parameterDescription + " args:" + Arrays.toString(args));
+        }
 
-		TraceContext traceContext = TraceContext.getTraceContext();
-		Trace trace = traceContext.currentTraceObject();
-		if (trace == null) {
-			return;
-		}
-		trace.recordApi(descriptor);
-		trace.recordException(result);
+        TraceContext traceContext = TraceContext.getTraceContext();
+        Trace trace = traceContext.currentTraceObject();
+        if (trace == null) {
+            return;
+        }
+        trace.recordApi(descriptor);
+        trace.recordException(result);
 
-		trace.markAfterTime();
-		trace.traceBlockEnd();
-	}
+        trace.markAfterTime();
+        trace.traceBlockEnd();
+    }
 
-	@Override
-	public void setMethodDescriptor(MethodDescriptor descriptor) {
-		this.descriptor = descriptor;
-	}
+    @Override
+    public void setMethodDescriptor(MethodDescriptor descriptor) {
+        this.descriptor = descriptor;
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/com/profiler/modifier/connector/interceptors/ExecuteMethodInterceptor.java b/src/main/java/com/profiler/modifier/connector/interceptors/ExecuteMethodInterceptor.java
index a6d45b64c..947da1c59 100644
--- a/src/main/java/com/profiler/modifier/connector/interceptors/ExecuteMethodInterceptor.java
+++ b/src/main/java/com/profiler/modifier/connector/interceptors/ExecuteMethodInterceptor.java
@@ -47,7 +47,8 @@ public class ExecuteMethodInterceptor implements StaticAroundInterceptor, ByteCo
         trace.traceBlockBegin();
         trace.markBeforeTime();
 
-        TraceID nextId = trace.getCurrentTraceId();
+        TraceID nextId = trace.getTraceId();
+        nextId.getNextTraceId();
         final HttpHost host = (HttpHost) args[0];
         final HttpRequest request = (HttpRequest) args[1];
         // UUID format을 그대로.
@@ -65,7 +66,7 @@ public class ExecuteMethodInterceptor implements StaticAroundInterceptor, ByteCo
     @Override
     public void after(Object target, String className, String methodName, String parameterDescription, Object[] args, Object result) {
         if (logger.isLoggable(Level.INFO)) {
-            logger.info("after " + StringUtils.toString(target) + " " + className + "." + methodName + parameterDescription + " args:" + Arrays.toString(args) + " result:" + result);
+            logger.info("after " + StringUtils.toString(target) + " " + className + "." + methodName + parameterDescription + " args:" + Arrays.toString(args));
         }
 
         TraceContext traceContext = TraceContext.getTraceContext();
diff --git a/src/main/java/com/profiler/modifier/tomcat/interceptors/StandardHostValveInvokeInterceptor.java b/src/main/java/com/profiler/modifier/tomcat/interceptors/StandardHostValveInvokeInterceptor.java
index 695627387..a518affbf 100644
--- a/src/main/java/com/profiler/modifier/tomcat/interceptors/StandardHostValveInvokeInterceptor.java
+++ b/src/main/java/com/profiler/modifier/tomcat/interceptors/StandardHostValveInvokeInterceptor.java
@@ -57,7 +57,7 @@ public class StandardHostValveInvokeInterceptor implements StaticAroundIntercept
             } else {
                 trace = new Trace();
                 if (logger.isLoggable(Level.INFO)) {
-                    logger.info("TraceID not exist. start new trace. " + trace.getCurrentTraceId());
+                    logger.info("TraceID not exist. start new trace. " + trace.getTraceId());
                     logger.log(Level.FINE, "requestUrl:" + requestURL + " clientIp" + clientIP + " parameter:" + parameters);
                 }
                 traceContext.attachTraceObject(trace);
diff --git a/src/main/java/com/profiler/sender/UdpDataSender.java b/src/main/java/com/profiler/sender/UdpDataSender.java
index 3ff015fb8..065687774 100644
--- a/src/main/java/com/profiler/sender/UdpDataSender.java
+++ b/src/main/java/com/profiler/sender/UdpDataSender.java
@@ -103,7 +103,7 @@ public class UdpDataSender implements DataSender, Runnable {
                     continue;
                 }
                 send0(dto);
-            } catch (Exception e) {
+            } catch (Throwable e) {
                 logger.log(Level.WARNING, "Unexpected Error", e);
             }
         }
@@ -121,6 +121,7 @@ public class UdpDataSender implements DataSender, Runnable {
         }
         byte[] sendData = serialize(tBase);
         if (sendData == null) {
+            logger.warning("sendData is null");
             return;
         }
         DatagramPacket packet = new DatagramPacket(sendData, sendData.length);
diff --git a/src/test/java/com/profiler/context/CallStackTest.java b/src/test/java/com/profiler/context/CallStackTest.java
index b68221c9c..c08328464 100644
--- a/src/test/java/com/profiler/context/CallStackTest.java
+++ b/src/test/java/com/profiler/context/CallStackTest.java
@@ -13,10 +13,13 @@ public class CallStackTest {
 
     @Test
     public void testPush() throws Exception {
-        CallStack callStack = new CallStack();
+        TraceID traceID = TraceID.newTraceId();
+        CallStack callStack = new CallStack(traceID);
         int stackIndex = callStack.getStackFrameIndex();
         logger.info(String.valueOf(stackIndex));
+        callStack.push();
 
+        callStack.pop();
     }
 
     @Test
diff --git a/src/test/java/com/profiler/context/TraceTest.java b/src/test/java/com/profiler/context/TraceTest.java
index 18ae67401..c8fa6fda4 100644
--- a/src/test/java/com/profiler/context/TraceTest.java
+++ b/src/test/java/com/profiler/context/TraceTest.java
@@ -1,10 +1,15 @@
 package com.profiler.context;
 
-import org.junit.Test;
-
 import com.profiler.common.ServiceType;
+import com.profiler.sender.DataSender;
+
+import org.apache.thrift.TBase;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class TraceTest {
+    private Logger logger = LoggerFactory.getLogger(this.getClass());
 
     @Test
     public void trace() {
@@ -16,20 +21,54 @@ public class TraceTest {
         trace.recordRpcName(ServiceType.UNKNOWN, "service_name", "http://");
         trace.recordEndPoint("http:localhost:8080");
         trace.recordAttribute("KEY", "VALUE");
-        trace.record(Annotation.ServerRecv);
 
         // get data form db
         getDataFromDB(trace);
 
         // response to client
-        trace.record(Annotation.ServerSend);
 
         trace.traceBlockEnd();
     }
 
+
+    @Test
+    public void popEventTest() {
+        TraceID traceID = TraceID.newTraceId();
+        Trace trace = new Trace(traceID);
+        TestDataSender dataSender = new TestDataSender();
+        trace.setDataSender(dataSender);
+//        trace.traceBlockBegin();
+
+        // response to client
+
+        trace.traceBlockEnd(0);
+
+        logger.info(String.valueOf(dataSender.event));
+    }
+
+    public class TestDataSender implements DataSender {
+        public boolean event;
+
+        @Override
+        public boolean send(TBase data) {
+            event = true;
+            return false;
+        }
+
+        @Override
+        public boolean send(Thriftable thriftable) {
+            this.event = true;
+            return false;  //To change body of implemented methods use File | Settings | File Templates.
+        }
+
+        @Override
+        public void stop() {
+        }
+    }
+
+
     private void getDataFromDB(Trace trace) {
         trace.traceBlockBegin();
-        trace.record(Annotation.ClientSend);
 
         // db server request
         trace.recordRpcName(ServiceType.MYSQL, "mysql", "rpc");
@@ -37,7 +76,6 @@ public class TraceTest {
 
         // get a db response
 
-        trace.record(Annotation.ClientRecv);
         trace.traceBlockEnd();