diff --git a/src/main/java/com/profiler/Agent.java b/src/main/java/com/profiler/Agent.java index cc1244ba6..84c8d8ce3 100644 --- a/src/main/java/com/profiler/Agent.java +++ b/src/main/java/com/profiler/Agent.java @@ -4,6 +4,7 @@ import java.util.Map.Entry; import java.util.logging.Logger; import com.profiler.common.dto.thrift.AgentInfo; +import com.profiler.context.TraceContext; import com.profiler.sender.DataSender; public class Agent { @@ -81,6 +82,8 @@ public class Agent { public void start() { logger.info("Starting HIPPO Agent."); + // trace context 새롭게 생성. + TraceContext.initialize(); systemMonitor.start(); } diff --git a/src/main/java/com/profiler/SystemMonitor.java b/src/main/java/com/profiler/SystemMonitor.java index b38d2a78c..195a85d7b 100644 --- a/src/main/java/com/profiler/SystemMonitor.java +++ b/src/main/java/com/profiler/SystemMonitor.java @@ -2,6 +2,7 @@ package com.profiler; import static com.profiler.config.TomcatProfilerConfig.JVM_STAT_GAP; +import java.io.IOException; import java.lang.management.GarbageCollectorMXBean; import java.lang.management.ManagementFactory; import java.lang.management.MemoryMXBean; @@ -11,11 +12,12 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; +import java.util.logging.Level; import java.util.logging.Logger; import com.profiler.common.dto.thrift.JVMInfoThriftDTO; +import com.profiler.context.TraceContext; import com.profiler.sender.DataSender; -import com.profiler.trace.RequestTracer; import com.sun.management.OperatingSystemMXBean; /** @@ -49,53 +51,64 @@ public class SystemMonitor { executor.shutdown(); } - private static class Worker implements Runnable { - - private JVMInfoThriftDTO currentDto = new JVMInfoThriftDTO(); + static class Worker implements Runnable { public void run() { + JVMInfoThriftDTO jvmInfo = new JVMInfoThriftDTO(); try { - currentDto = new JVMInfoThriftDTO(); - currentDto.setAgentId(Agent.getInstance().getAgentId()); - currentDto.setDataTime(System.currentTimeMillis()); + jvmInfo = new JVMInfoThriftDTO(); + jvmInfo.setAgentId(Agent.getInstance().getAgentId()); + jvmInfo.setDataTime(System.currentTimeMillis()); - getActiveThreadCount(); - getGCState(); - getMemoryState(); - getProcessCPUUsage(); + TraceContext traceContext = TraceContext.getTraceContext(); + activeThread(traceContext, jvmInfo); - DataSender.getInstance().addDataToSend(currentDto); + setGCState(jvmInfo); + setMemoryState(jvmInfo); + setProcessCPUUsage(jvmInfo); + + DataSender.getInstance().addDataToSend(jvmInfo); } catch (Exception e) { - + logger.log(Level.INFO, "JvmInfo collect error Cause:" + e.getMessage(), e); } } - private void getActiveThreadCount() throws Exception { - int currentSize = RequestTracer.getActiveThreadCount(); - currentDto.setActiveThreadCount(currentSize); - } + private void activeThread(TraceContext traceContext, JVMInfoThriftDTO jvmInfo) { + int activeThread = traceContext.getActiveThreadCounter().getActiveThread(); + jvmInfo.setActiveThreadCount(activeThread); + } - private void getGCState() throws Exception { + + private void setGCState(JVMInfoThriftDTO jvmInfo) throws Exception { List list = ManagementFactory.getGarbageCollectorMXBeans(); if (list.size() == 2) { - GarbageCollectorMXBean bean1 = list.get(0); - currentDto.setGc1Count(bean1.getCollectionCount()); - currentDto.setGc1Time(bean1.getCollectionTime()); - GarbageCollectorMXBean bean2 = list.get(1); - currentDto.setGc2Count(bean2.getCollectionCount()); - currentDto.setGc2Time(bean2.getCollectionTime()); - } + // 제네레이션 기반일 경우 young, old 2개. +// young.getName() // young gc type + GarbageCollectorMXBean young = list.get(0); + jvmInfo.setGc1Count(young.getCollectionCount()); + jvmInfo.setGc1Time(young.getCollectionTime()); + + GarbageCollectorMXBean old = list.get(1); +// old.getName() // old gc type + jvmInfo.setGc2Count(old.getCollectionCount()); + jvmInfo.setGc2Time(old.getCollectionTime()); + } else { + // g1 ? + if(logger.isLoggable(Level.FINE)) { + logger.fine("unknown gc type. gc collector size:" + list.size()); + } + } } - public void getMemoryState() throws Exception { + public void setMemoryState(JVMInfoThriftDTO jvmInfo) throws Exception { MemoryMXBean bean = ManagementFactory.getMemoryMXBean(); MemoryUsage heap = bean.getHeapMemoryUsage(); MemoryUsage nonHeap = bean.getNonHeapMemoryUsage(); - currentDto.setHeapUsed(heap.getUsed()); - currentDto.setHeapCommitted(heap.getCommitted()); - currentDto.setNonHeapUsed(nonHeap.getUsed()); - currentDto.setNonHeapCommitted(nonHeap.getCommitted()); + jvmInfo.setHeapUsed(heap.getUsed()); + jvmInfo.setHeapCommitted(heap.getCommitted()); + jvmInfo.setNonHeapUsed(nonHeap.getUsed()); + jvmInfo.setNonHeapCommitted(nonHeap.getCommitted()); } long previousCpuTime = 0; @@ -104,11 +117,10 @@ public class SystemMonitor { /** * I don't know why should I divide by 10 in this result. But it works. - * - -; - * + * * @throws Exception */ - private void getProcessCPUUsage() throws Exception { + private void setProcessCPUUsage(JVMInfoThriftDTO jvmInfo) throws Exception { try { if (processCPUAvailable) { OperatingSystemMXBean sunOSMBean = ManagementFactory.newPlatformMXBeanProxy(ManagementFactory.getPlatformMBeanServer(), ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME, OperatingSystemMXBean.class); @@ -121,12 +133,13 @@ public class SystemMonitor { if (previousCpuTime != 0) { long usedCPUTotal = (cpuTime - previousCpuTime) / 1000000; double usedCPU = (0.1D * usedCPUTotal) / (processorCount * JVM_STAT_GAP / 1000.0); - currentDto.setProcessCPUTime(usedCPU); + jvmInfo.setProcessCPUTime(usedCPU); } previousCpuTime = cpuTime; + } - } catch (Exception e) { - e.printStackTrace(); + } catch (IOException e) { + processCPUAvailable = false; } } diff --git a/src/main/java/com/profiler/context/ActiveThreadCounter.java b/src/main/java/com/profiler/context/ActiveThreadCounter.java new file mode 100644 index 000000000..329ebe327 --- /dev/null +++ b/src/main/java/com/profiler/context/ActiveThreadCounter.java @@ -0,0 +1,23 @@ +package com.profiler.context; + +import java.util.concurrent.atomic.AtomicInteger; + +public class ActiveThreadCounter { + private AtomicInteger counter = new AtomicInteger(0); + + public void start() { + counter.incrementAndGet(); + } + + public void end() { + counter.decrementAndGet(); + } + + public int getActiveThread() { + return counter.get(); + } + + public void reset() { + counter.set(0); + } +} diff --git a/src/main/java/com/profiler/context/TraceContext.java b/src/main/java/com/profiler/context/TraceContext.java new file mode 100644 index 000000000..fc4716617 --- /dev/null +++ b/src/main/java/com/profiler/context/TraceContext.java @@ -0,0 +1,26 @@ +package com.profiler.context; + +import com.profiler.util.NamedThreadLocal; + +public class TraceContext { + + private static TraceContext CONTEXT = new TraceContext(); + + public static TraceContext initialize() { + return CONTEXT = new TraceContext(); + } + + public static TraceContext getTraceContext() { + return CONTEXT; + } + +// private ThreadLocal threadLocal = new NamedThreadLocal("threadLocalTraceContext"); + private final ActiveThreadCounter activeThreadCounter = new ActiveThreadCounter(); + + public TraceContext() { + } + + public ActiveThreadCounter getActiveThreadCounter() { + return activeThreadCounter; + } +} diff --git a/src/main/java/com/profiler/context/TraceID.java b/src/main/java/com/profiler/context/TraceID.java index 6caf7f78d..b876f971d 100644 --- a/src/main/java/com/profiler/context/TraceID.java +++ b/src/main/java/com/profiler/context/TraceID.java @@ -47,32 +47,28 @@ public class TraceID { this.span = span; } - @Override - public boolean equals(Object o) { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; - TraceKey that = (TraceKey) o; + TraceKey traceKey = (TraceKey) o; - if (least != that.least) - return false; - if (most != that.most) - return false; - if (span != that.span) - return false; + if (least != traceKey.least) return false; + if (most != traceKey.most) return false; + if (span != traceKey.span) return false; - return true; - } + return true; + } - @Override - public int hashCode() { - int result = (int) (most ^ (most >>> 32)); - result = 31 * result + (int) (least ^ (least >>> 32)); - return result; - } - } + @Override + public int hashCode() { + int result = (int) (most ^ (most >>> 32)); + result = 31 * result + (int) (least ^ (least >>> 32)); + result = 31 * result + (int) (span ^ (span >>> 32)); + return result; + } + } public long getParentSpanId() { return parentSpanId; diff --git a/src/main/java/com/profiler/modifier/DefaultModifierRegistry.java b/src/main/java/com/profiler/modifier/DefaultModifierRegistry.java index c3ea8f798..8b177cd2a 100644 --- a/src/main/java/com/profiler/modifier/DefaultModifierRegistry.java +++ b/src/main/java/com/profiler/modifier/DefaultModifierRegistry.java @@ -21,7 +21,7 @@ import com.profiler.modifier.db.oracle.OraclePreparedStatementModifier; import com.profiler.modifier.db.oracle.OracleResultSetModifier; import com.profiler.modifier.db.oracle.OracleStatementModifier; import com.profiler.modifier.tomcat.CatalinaModifier; -import com.profiler.modifier.tomcat.EntryPointStandardHostValveModifier; +import com.profiler.modifier.tomcat.StandardHostValveInvokeInterceptor; import com.profiler.modifier.tomcat.TomcatConnectorModifier; import com.profiler.modifier.tomcat.TomcatStandardServiceModifier; @@ -57,8 +57,8 @@ public class DefaultModifierRegistry implements ModifierRegistry { } public void addTomcatModifier() { - Modifier entryPointStandardHostValveModifier = new EntryPointStandardHostValveModifier(byteCodeInstrumentor); - addModifier(entryPointStandardHostValveModifier); + StandardHostValveInvokeInterceptor standardHostValveInvokeInterceptor = new StandardHostValveInvokeInterceptor(byteCodeInstrumentor); + addModifier(standardHostValveInvokeInterceptor); Modifier tomcatStandardServiceModifier = new TomcatStandardServiceModifier(byteCodeInstrumentor); addModifier(tomcatStandardServiceModifier); diff --git a/src/main/java/com/profiler/modifier/tomcat/EntryPointStandardHostValveModifier.java b/src/main/java/com/profiler/modifier/tomcat/StandardHostValveInvokeInterceptor.java similarity index 65% rename from src/main/java/com/profiler/modifier/tomcat/EntryPointStandardHostValveModifier.java rename to src/main/java/com/profiler/modifier/tomcat/StandardHostValveInvokeInterceptor.java index 602ada3ee..61a1b0c3f 100644 --- a/src/main/java/com/profiler/modifier/tomcat/EntryPointStandardHostValveModifier.java +++ b/src/main/java/com/profiler/modifier/tomcat/StandardHostValveInvokeInterceptor.java @@ -21,11 +21,11 @@ import com.profiler.trace.RequestTracer; * @author cowboy93, netspider * */ -public class EntryPointStandardHostValveModifier extends AbstractModifier { +public class StandardHostValveInvokeInterceptor extends AbstractModifier { - private final Logger logger = Logger.getLogger(EntryPointStandardHostValveModifier.class.getName()); + private final Logger logger = Logger.getLogger(StandardHostValveInvokeInterceptor.class.getName()); - public EntryPointStandardHostValveModifier(ByteCodeInstrumentor byteCodeInstrumentor) { + public StandardHostValveInvokeInterceptor(ByteCodeInstrumentor byteCodeInstrumentor) { super(byteCodeInstrumentor); } @@ -43,10 +43,10 @@ public class EntryPointStandardHostValveModifier extends AbstractModifier { classPool.insertClassPath(new ByteArrayClassPath(javassistClassName, classFileBuffer)); try { - Interceptor interceptor = newInterceptor(classLoader, protectedDomain, "com.profiler.modifier.tomcat.interceptors.InvokeMethodInterceptor"); - InstrumentClass aClass = byteCodeInstrumentor.getClass(javassistClassName); - aClass.addInterceptor("invoke", new String[] { "org.apache.catalina.connector.Request", "org.apache.catalina.connector.Response" }, interceptor); - return aClass.toBytecode(); + Interceptor interceptor = newInterceptor(classLoader, protectedDomain, "com.profiler.modifier.tomcat.interceptors.StandardHostValveInvokeInterceptor"); + InstrumentClass standardHostValve = byteCodeInstrumentor.getClass(javassistClassName); + standardHostValve.addInterceptor("invoke", new String[] { "org.apache.catalina.connector.Request", "org.apache.catalina.connector.Response" }, interceptor); + return standardHostValve.toBytecode(); } catch (InstrumentException e) { logger.log(Level.WARNING, "modify fail. Cause:" + e.getMessage(), e); return null; @@ -55,8 +55,10 @@ public class EntryPointStandardHostValveModifier extends AbstractModifier { private void addRequiredCladdToCurrentClassLoader(ClassLoader classLoader) { try { + // TODO 이제 인터셉터에서 아래 클래스를 직접적으로 접근하는 일이 없으므로 없어도 될것 같음. classLoader.loadClass(RequestTracer.FQCN); classLoader.loadClass(CLASS_NAME_REQUEST_THRIFT_DTO); + // thrift에 대한 lib를 별도 가지고 있을려면 system및의 별도 classloader를 가지고 있어야 되는게 아닌지? classLoader.loadClass("org.apache.thrift.TBase"); } catch (Exception e) { if (logger.isLoggable(Level.WARNING)) { diff --git a/src/main/java/com/profiler/modifier/tomcat/interceptors/InvokeMethodInterceptor.java b/src/main/java/com/profiler/modifier/tomcat/interceptors/StandardHostValveInvokeInterceptor.java similarity index 59% rename from src/main/java/com/profiler/modifier/tomcat/interceptors/InvokeMethodInterceptor.java rename to src/main/java/com/profiler/modifier/tomcat/interceptors/StandardHostValveInvokeInterceptor.java index 9158c0c5f..e9c78389d 100644 --- a/src/main/java/com/profiler/modifier/tomcat/interceptors/InvokeMethodInterceptor.java +++ b/src/main/java/com/profiler/modifier/tomcat/interceptors/StandardHostValveInvokeInterceptor.java @@ -1,26 +1,32 @@ package com.profiler.modifier.tomcat.interceptors; +import java.util.Arrays; import java.util.Enumeration; import java.util.UUID; +import java.util.logging.Level; +import java.util.logging.Logger; import javax.servlet.http.HttpServletRequest; import com.profiler.StopWatch; -import com.profiler.context.Annotation; -import com.profiler.context.Header; -import com.profiler.context.SpanID; -import com.profiler.context.Trace; -import com.profiler.context.TraceID; +import com.profiler.context.*; import com.profiler.interceptor.StaticAroundInterceptor; -import com.profiler.trace.RequestTracer; import com.profiler.util.NumberUtils; +import com.profiler.util.StringUtils; -public class InvokeMethodInterceptor implements StaticAroundInterceptor { +public class StandardHostValveInvokeInterceptor implements StaticAroundInterceptor { + private final Logger logger = Logger.getLogger(StandardHostValveInvokeInterceptor.class.getName()); @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)); + } try { - HttpServletRequest request = (HttpServletRequest) args[0]; + TraceContext traceContext = TraceContext.getTraceContext(); + traceContext.getActiveThreadCounter().start(); + + HttpServletRequest request = (HttpServletRequest) args[0]; String requestURL = request.getRequestURI(); String clientIP = request.getRemoteAddr(); String parameters = getRequestParameter(request); @@ -29,11 +35,13 @@ public class InvokeMethodInterceptor implements StaticAroundInterceptor { if (traceId != null) { Trace.setTraceId(traceId); } else { - System.out.println(requestURL); - System.out.println(clientIP); - System.out.println(parameters); - - Trace.setTraceId(TraceID.newTraceId()); + TraceID newTraceID = TraceID.newTraceId(); + if (logger.isLoggable(Level.INFO)) { + logger.info("TraceID not exist. start new trace. " + newTraceID); + // 좀더 자세한 정보는 debug레벨로 + logger.log(Level.FINE, "requestUrl:" + requestURL + " clientIp" + clientIP + " parameter:" + parameters); + } + Trace.setTraceId(newTraceID); } Trace.recordRpcName("tomcat", requestURL); @@ -41,18 +49,25 @@ public class InvokeMethodInterceptor implements StaticAroundInterceptor { Trace.recordAttibute("http.params", parameters); Trace.record(Annotation.ServerRecv); -// RequestTracer.startTransaction(requestURL, clientIP, System.currentTimeMillis(), parameters); - - StopWatch.start("InvokeMethodInterceptor-starttime"); + StopWatch.start("StandardHostValveInvokeInterceptor-starttime"); } catch (Exception e) { - e.printStackTrace(); + if (logger.isLoggable(Level.WARNING)) { + logger.log(Level.WARNING, "Tomcat StandardHostValve trace start fail", e); + } } } @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); + } + + TraceContext traceContext = TraceContext.getTraceContext(); + traceContext.getActiveThreadCounter().end(); + // TODO result 가 Exception 타입일경우 호출 실패임. - Trace.record(Annotation.ServerSend, StopWatch.stopAndGetElapsed("InvokeMethodInterceptor-starttime")); + Trace.record(Annotation.ServerSend, StopWatch.stopAndGetElapsed("StandardHostValveInvokeInterceptor-starttime")); // RequestTracer.endTransaction(); // TODO: I'v changed point of removing. Trace.mutate() @@ -67,7 +82,6 @@ public class InvokeMethodInterceptor implements StaticAroundInterceptor { */ private TraceID populateTraceIdFromRequest(HttpServletRequest request) { String strUUID = request.getHeader(Header.HTTP_TRACE_ID.toString()); - if (strUUID != null) { UUID uuid = UUID.fromString(strUUID); long parentSpanID = NumberUtils.parseLong(request.getHeader(Header.HTTP_PARENT_SPAN_ID.toString()), SpanID.NULL); @@ -76,10 +90,9 @@ public class InvokeMethodInterceptor implements StaticAroundInterceptor { int flags = NumberUtils.parseInteger(request.getHeader(Header.HTTP_FLAGS.toString()), 0); TraceID id = new TraceID(uuid, parentSpanID, spanID, sampled, flags); - - // TODO : remove this, just for debug - System.out.println("\nGOT A TRACEID. TRACEID=" + id + "\n\n"); - + if (logger.isLoggable(Level.INFO)) { + logger.info("TraceID exist. continue trace. " + id); + } return id; } else { return null; diff --git a/src/test/java/com/profiler/SystemMonitorTest.java b/src/test/java/com/profiler/SystemMonitorTest.java new file mode 100644 index 000000000..ec9b94e23 --- /dev/null +++ b/src/test/java/com/profiler/SystemMonitorTest.java @@ -0,0 +1,23 @@ +package com.profiler; + +import org.junit.Test; + +/** + * Created with IntelliJ IDEA. + * User: emeroad + * Date: 12. 9. 24 + * Time: 오후 3:54 + * To change this template use File | Settings | File Templates. + */ +public class SystemMonitorTest { + @Test + public void testStart() throws Exception { + SystemMonitor.Worker systemMonitor = new SystemMonitor.Worker(); + systemMonitor.run(); + } + + @Test + public void testStop() throws Exception { + + } +} diff --git a/src/test/java/com/profiler/modifier/tomcat/InvokeMethodInterceptorTest.java b/src/test/java/com/profiler/modifier/tomcat/InvokeMethodInterceptorTest.java index 01c84c9e5..bf97a88ca 100644 --- a/src/test/java/com/profiler/modifier/tomcat/InvokeMethodInterceptorTest.java +++ b/src/test/java/com/profiler/modifier/tomcat/InvokeMethodInterceptorTest.java @@ -11,7 +11,7 @@ import javax.servlet.http.HttpServletResponse; import org.junit.Test; import com.profiler.context.Header; -import com.profiler.modifier.tomcat.interceptors.InvokeMethodInterceptor; +import com.profiler.modifier.tomcat.interceptors.StandardHostValveInvokeInterceptor; public class InvokeMethodInterceptorTest { @@ -31,7 +31,7 @@ public class InvokeMethodInterceptorTest { Enumeration enumeration = mock(Enumeration.class); when(request.getParameterNames()).thenReturn(enumeration); - InvokeMethodInterceptor interceptor = new InvokeMethodInterceptor(); + StandardHostValveInvokeInterceptor interceptor = new StandardHostValveInvokeInterceptor(); interceptor.before("target", "classname", "methodname", null, new Object[] { request, response }); interceptor.after("target", "classname", "methodname", null, new Object[] { request, response }, new Object()); @@ -56,7 +56,7 @@ public class InvokeMethodInterceptorTest { Enumeration enumeration = mock(Enumeration.class); when(request.getParameterNames()).thenReturn(enumeration); - InvokeMethodInterceptor interceptor = new InvokeMethodInterceptor(); + StandardHostValveInvokeInterceptor interceptor = new StandardHostValveInvokeInterceptor(); interceptor.before("target", "classname", "methodname", null, new Object[] { request, response }); interceptor.after("target", "classname", "methodname", null, new Object[] { request, response }, new Object());