From 14786d640e96857c5a010088998db9e16bab4f78 Mon Sep 17 00:00:00 2001 From: Chisu Yu Date: Mon, 21 Jan 2013 08:13:20 +0000 Subject: [PATCH] =?UTF-8?q?[=EC=9C=A0=EC=B9=98=EC=88=98]=20[NOBTS]=20modif?= =?UTF-8?q?y=20servlet=20interceptor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://svn.bds.nhncorp.com/pe/hippo-tomcat-profiler/trunk@1107 84d0f5b1-2673-498c-a247-62c4ff18d310 --- .../java/com/profiler/TomcatProfiler.java | 180 +++++++++--------- .../java/com/profiler/context/SubSpan.java | 6 +- .../modifier/DefaultModifierRegistry.java | 14 +- .../interceptors/MethodInterceptor.java | 76 ++++++++ .../modifier/servlet/FilterModifier.java | 53 ++++++ .../modifier/servlet/HttpServletModifier.java | 4 +- .../SpringFrameworkServletModifier.java | 4 +- .../interceptors/DoXXXInterceptor.java | 24 +++ 8 files changed, 259 insertions(+), 102 deletions(-) create mode 100644 src/main/java/com/profiler/modifier/method/interceptors/MethodInterceptor.java create mode 100644 src/main/java/com/profiler/modifier/servlet/FilterModifier.java diff --git a/src/main/java/com/profiler/TomcatProfiler.java b/src/main/java/com/profiler/TomcatProfiler.java index 89a1cf546..286e37435 100644 --- a/src/main/java/com/profiler/TomcatProfiler.java +++ b/src/main/java/com/profiler/TomcatProfiler.java @@ -1,12 +1,5 @@ package com.profiler; -import com.profiler.config.ProfilerConfig; -import com.profiler.interceptor.bci.ByteCodeInstrumentor; -import com.profiler.interceptor.bci.JavaAssistByteCodeInstrumentor; -import com.profiler.modifier.DefaultModifierRegistry; -import com.profiler.modifier.Modifier; -import com.profiler.modifier.ModifierRegistry; - import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.IllegalClassFormatException; import java.lang.instrument.Instrumentation; @@ -14,111 +7,118 @@ import java.security.ProtectionDomain; import java.util.logging.Level; import java.util.logging.Logger; +import com.profiler.config.ProfilerConfig; +import com.profiler.interceptor.bci.ByteCodeInstrumentor; +import com.profiler.interceptor.bci.JavaAssistByteCodeInstrumentor; +import com.profiler.modifier.DefaultModifierRegistry; +import com.profiler.modifier.Modifier; +import com.profiler.modifier.ModifierRegistry; + public class TomcatProfiler implements ClassFileTransformer { - private static final Logger logger = Logger.getLogger(TomcatProfiler.class.getName()); + private static final Logger logger = Logger.getLogger(TomcatProfiler.class.getName()); - private String agentArgString = ""; + private String agentArgString = ""; - private Instrumentation instrumentation; - private final ByteCodeInstrumentor byteCodeInstrumentor; + private Instrumentation instrumentation; + private final ByteCodeInstrumentor byteCodeInstrumentor; - private final ModifierRegistry modifierRepository; + private final ModifierRegistry modifierRepository; - private final ProfilerConfig profilerConfig; - private final Agent agent; + private final ProfilerConfig profilerConfig; + private final Agent agent; + public static void premain(String agentArgs, Instrumentation instrumentation) { + try { + ProfilerConfig profilerConfig = new ProfilerConfig(); + profilerConfig.readConfigFile(); + if (!profilerConfig.isProfileEnable()) { + logger.warning("Profiler Agent not started. PROFILE_ENABLE=" + profilerConfig.isProfileEnable()); + return; + } + Agent agent = new Agent(profilerConfig); + new TomcatProfiler(agentArgs, instrumentation, agent, profilerConfig); + } catch (Exception e) { + logger.log(Level.SEVERE, "Profiler Agent start fail. Cause:" + e.getMessage(), e); + } + } - public static void premain(String agentArgs, Instrumentation instrumentation) { - try { - ProfilerConfig profilerConfig = new ProfilerConfig(); - profilerConfig.readConfigFile(); - if (!profilerConfig.isProfileEnable()) { - logger.warning("Profiler Agent not started. PROFILE_ENABLE=" + profilerConfig.isProfileEnable()); - return; - } - Agent agent = new Agent(profilerConfig); - new TomcatProfiler(agentArgs, instrumentation, agent, profilerConfig); - } catch (Exception e) { - logger.log(Level.SEVERE, "Profiler Agent start fail. Cause:" + e.getMessage(), e); - } - } + public TomcatProfiler(String agentArgs, Instrumentation instrumentation, Agent agent, ProfilerConfig profilerConfig) { + this.agentArgString = agentArgs; + this.profilerConfig = profilerConfig; + this.agent = agent; - public TomcatProfiler(String agentArgs, Instrumentation instrumentation, Agent agent, ProfilerConfig profilerConfig) { - this.agentArgString = agentArgs; - this.profilerConfig = profilerConfig; - this.agent = agent; + this.instrumentation = instrumentation; + this.instrumentation.addTransformer(this); - this.instrumentation = instrumentation; - this.instrumentation.addTransformer(this); + String[] paths = getTomcatlibPath(); + this.byteCodeInstrumentor = new JavaAssistByteCodeInstrumentor(paths); - String[] paths = getTomcatlibPath(); - this.byteCodeInstrumentor = new JavaAssistByteCodeInstrumentor(paths); + this.modifierRepository = createModifierRegistry(); + } - this.modifierRepository = createModifierRegistry(); - } + private String[] getTomcatlibPath() { + String catalinaHome = System.getProperty("catalina.home"); - private String[] getTomcatlibPath() { - String catalinaHome = System.getProperty("catalina.home"); + if (catalinaHome == null) { + logger.info("CATALINA_HOME is null"); + return null; + } - if (catalinaHome == null) { - logger.info("CATALINA_HOME is null"); - return null; - } + if (logger.isLoggable(Level.INFO)) { + logger.info("CATALINA_HOME=" + catalinaHome); + } - if (logger.isLoggable(Level.INFO)) { - logger.info("CATALINA_HOME=" + catalinaHome); - } + // TODO This is draft. How can we support both Tomcat and BLOC without this configuration? + String type = System.getProperty("hippo.servertype", "tomcat"); - // TODO This is draft. How can we support both Tomcat and BLOC without this configuration? - String type = System.getProperty("hippo.servertype", "tomcat"); + if (type.equals("bloc")) { + return new String[] { catalinaHome + "/server/lib/catalina.jar", catalinaHome + "/common/lib/servlet-api.jar" }; + } else { + return new String[] { catalinaHome + "/lib/servlet-api.jar", catalinaHome + "/lib/catalina.jar" }; + } + } - if (type.equals("bloc")) { - return new String[]{catalinaHome + "/server/lib/catalina.jar", catalinaHome + "/common/lib/servlet-api.jar"}; - } else { - return new String[]{catalinaHome + "/lib/servlet-api.jar", catalinaHome + "/lib/catalina.jar"}; - } - } + private ModifierRegistry createModifierRegistry() { + DefaultModifierRegistry modifierRepository = new DefaultModifierRegistry(byteCodeInstrumentor, agent, profilerConfig); - private ModifierRegistry createModifierRegistry() { - DefaultModifierRegistry modifierRepository = new DefaultModifierRegistry(byteCodeInstrumentor, agent, profilerConfig); + modifierRepository.addTomcatModifier(); - modifierRepository.addTomcatModifier(); + // jdbc + modifierRepository.addJdbcModifier(); - // jdbc - modifierRepository.addJdbcModifier(); + // rpc + modifierRepository.addConnectorModifier(); - // rpc - modifierRepository.addConnectorModifier(); + // bloc + modifierRepository.addBLOCModifier(); - // bloc - modifierRepository.addBLOCModifier(); + return modifierRepository; + } - return modifierRepository; - } + @Override + public byte[] transform(ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classFileBuffer) throws IllegalClassFormatException { + // fast java class skip + if (className.startsWith("java")) { + if (className.startsWith("/", 4) || className.startsWith("x/", 4)) { + return classFileBuffer; + } + } + Modifier findModifier = this.modifierRepository.findModifier(className); + if (findModifier == null) { + findModifier = this.modifierRepository.findModifier("*"); + // return null; + } + if (logger.isLoggable(Level.FINE)) { + logger.fine("[transform] cl" + classLoader + " className:" + className + " Modifier:" + findModifier.getClass().getName()); + } + String javassistClassName = className.replace('/', '.'); - @Override - public byte[] transform(ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classFileBuffer) throws IllegalClassFormatException { - // fast java class skip - if (className.startsWith("java")) { - if (className.startsWith("/", 4) || className.startsWith("x/", 4)) { - return classFileBuffer; - } - } - Modifier findModifier = this.modifierRepository.findModifier(className); - if (findModifier == null) { - return null; - } - if (logger.isLoggable(Level.FINE)) { - logger.fine("[transform] cl" + classLoader + " className:" + className + " Modifier:" + findModifier.getClass().getName()); - } - String javassistClassName = className.replace('/', '.'); - - try { - return findModifier.modify(classLoader, javassistClassName, protectionDomain, classFileBuffer); - } catch (Exception e) { - logger.log(Level.SEVERE, "Modifier:" + findModifier.getTargetClass() + " modify fail. Cause:" + e.getMessage(), e); - return null; - } - } + try { + return findModifier.modify(classLoader, javassistClassName, protectionDomain, classFileBuffer); + } catch (Exception e) { + logger.log(Level.SEVERE, "Modifier:" + findModifier.getTargetClass() + " modify fail. Cause:" + e.getMessage(), e); + return null; + } + } } diff --git a/src/main/java/com/profiler/context/SubSpan.java b/src/main/java/com/profiler/context/SubSpan.java index 9482dbac4..921f710a7 100644 --- a/src/main/java/com/profiler/context/SubSpan.java +++ b/src/main/java/com/profiler/context/SubSpan.java @@ -159,7 +159,11 @@ public class SubSpan implements Thriftable { subSpan.setRpc(rpc); subSpan.setServiceName(serviceName); - subSpan.setServiceType(serviceType.getCode()); + + if (serviceType != null) { + subSpan.setServiceType(serviceType.getCode()); + } + subSpan.setEndPoint(endPoint); subSpan.setErr(exception); diff --git a/src/main/java/com/profiler/modifier/DefaultModifierRegistry.java b/src/main/java/com/profiler/modifier/DefaultModifierRegistry.java index efeb7cbc2..324108158 100644 --- a/src/main/java/com/profiler/modifier/DefaultModifierRegistry.java +++ b/src/main/java/com/profiler/modifier/DefaultModifierRegistry.java @@ -31,7 +31,9 @@ import com.profiler.modifier.db.mysql.MySQLStatementModifier; 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.servlet.FilterModifier; import com.profiler.modifier.servlet.HttpServletModifier; +import com.profiler.modifier.servlet.SpringFrameworkServletModifier; import com.profiler.modifier.tomcat.CatalinaModifier; import com.profiler.modifier.tomcat.StandardHostValveInvokeModifier; import com.profiler.modifier.tomcat.TomcatConnectorModifier; @@ -65,6 +67,9 @@ public class DefaultModifierRegistry implements ModifierRegistry { } public void addConnectorModifier() { + FilterModifier filterModifier = new FilterModifier(byteCodeInstrumentor, agent); + addModifier(filterModifier); + HTTPClientModifier httpClientModifier = new HTTPClientModifier(byteCodeInstrumentor, agent); addModifier(httpClientModifier); @@ -87,19 +92,14 @@ public class DefaultModifierRegistry implements ModifierRegistry { } public void addTomcatModifier() { - // TODO 포함시키면 다음 exception이 발생하여 일단 주석처리함. - // ???: Tomcat StandardHostValve trace start fail. Caused:already Trace Object exist. - // java.lang.IllegalStateException: already Trace Object exist. - // at com.profiler.context.TraceContext.attachTraceObject(TraceContext.java:51) - StandardHostValveInvokeModifier standardHostValveInvokeModifier = new StandardHostValveInvokeModifier(byteCodeInstrumentor, agent); addModifier(standardHostValveInvokeModifier); HttpServletModifier httpServletModifier = new HttpServletModifier(byteCodeInstrumentor, agent); addModifier(httpServletModifier); - // SpringFrameworkServletModifier springServletModifier = new SpringFrameworkServletModifier(byteCodeInstrumentor, agent); - // addModifier(springServletModifier); + SpringFrameworkServletModifier springServletModifier = new SpringFrameworkServletModifier(byteCodeInstrumentor, agent); + addModifier(springServletModifier); Modifier tomcatStandardServiceModifier = new TomcatStandardServiceModifier(byteCodeInstrumentor, agent); addModifier(tomcatStandardServiceModifier); diff --git a/src/main/java/com/profiler/modifier/method/interceptors/MethodInterceptor.java b/src/main/java/com/profiler/modifier/method/interceptors/MethodInterceptor.java new file mode 100644 index 000000000..3eaf938d4 --- /dev/null +++ b/src/main/java/com/profiler/modifier/method/interceptors/MethodInterceptor.java @@ -0,0 +1,76 @@ +package com.profiler.modifier.method.interceptors; + +import java.util.Arrays; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.profiler.context.Trace; +import com.profiler.context.TraceContext; +import com.profiler.interceptor.ApiIdSupport; +import com.profiler.interceptor.ByteCodeMethodDescriptorSupport; +import com.profiler.interceptor.MethodDescriptor; +import com.profiler.interceptor.StaticAroundInterceptor; +import com.profiler.interceptor.TraceContextSupport; +import com.profiler.util.StringUtils; + +/** + * + * @author netspider + * + */ +public class MethodInterceptor implements StaticAroundInterceptor, ByteCodeMethodDescriptorSupport, ApiIdSupport, TraceContextSupport { + + private final Logger logger = Logger.getLogger(MethodInterceptor.class.getName()); + private MethodDescriptor descriptor; + private int apiId; + private TraceContext traceContext; + + @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)); + } + + Trace trace = TraceContext.getTraceContext().currentTraceObject(); + if (trace == null) { + return; + } + + trace.traceBlockBegin(); + trace.markBeforeTime(); + } + + @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)); + } + + Trace trace = TraceContext.getTraceContext().currentTraceObject(); + if (trace == null) { + return; + } + + trace.recordApi(descriptor); + // trace.recordApi(this.apiId); + trace.recordException(result); + + trace.markAfterTime(); + trace.traceBlockEnd(); + } + + @Override + public void setMethodDescriptor(MethodDescriptor descriptor) { + this.descriptor = descriptor; + } + + @Override + public void setApiId(int apiId) { + this.apiId = apiId; + } + + @Override + public void setTraceContext(TraceContext traceContext) { + this.traceContext = traceContext; + } +} diff --git a/src/main/java/com/profiler/modifier/servlet/FilterModifier.java b/src/main/java/com/profiler/modifier/servlet/FilterModifier.java new file mode 100644 index 000000000..fb112e75a --- /dev/null +++ b/src/main/java/com/profiler/modifier/servlet/FilterModifier.java @@ -0,0 +1,53 @@ +package com.profiler.modifier.servlet; + +import java.security.ProtectionDomain; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.profiler.Agent; +import com.profiler.interceptor.Interceptor; +import com.profiler.interceptor.bci.ByteCodeInstrumentor; +import com.profiler.interceptor.bci.InstrumentClass; +import com.profiler.interceptor.bci.InstrumentException; +import com.profiler.modifier.AbstractModifier; + +/** + * + * @author netspider + * + */ +public class FilterModifier extends AbstractModifier { + + private final Logger logger = Logger.getLogger(FilterModifier.class.getName()); + + public FilterModifier(ByteCodeInstrumentor byteCodeInstrumentor, Agent agent) { + super(byteCodeInstrumentor, agent); + } + + public String getTargetClass() { + return "javax/servlet/Filter"; + } + + public byte[] modify(ClassLoader classLoader, String javassistClassName, ProtectionDomain protectedDomain, byte[] classFileBuffer) { + if (logger.isLoggable(Level.INFO)) { + logger.info("Modifing. " + javassistClassName); + } + + byteCodeInstrumentor.checkLibrary(classLoader, javassistClassName); + + try { + Interceptor doFilterInterceptor = byteCodeInstrumentor.newInterceptor(classLoader, protectedDomain, "com.profiler.modifier.method.interceptors.MethodInterceptor"); + + setTraceContext(doFilterInterceptor); + + InstrumentClass servlet = byteCodeInstrumentor.getClass(javassistClassName); + + servlet.addInterceptor("doFilter", new String[] { "javax.servlet.ServletRequest", "javax.servlet.ServletResponse", "javax.servlet.FilterChain" }, doFilterInterceptor); + + return servlet.toBytecode(); + } catch (InstrumentException e) { + logger.log(Level.WARNING, "modify fail. Cause:" + e.getMessage(), e); + return null; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/profiler/modifier/servlet/HttpServletModifier.java b/src/main/java/com/profiler/modifier/servlet/HttpServletModifier.java index 580dad6db..918a4daf6 100644 --- a/src/main/java/com/profiler/modifier/servlet/HttpServletModifier.java +++ b/src/main/java/com/profiler/modifier/servlet/HttpServletModifier.java @@ -36,8 +36,8 @@ public class HttpServletModifier extends AbstractModifier { byteCodeInstrumentor.checkLibrary(classLoader, javassistClassName); try { - Interceptor doGetInterceptor = byteCodeInstrumentor.newInterceptor(classLoader, protectedDomain, "com.profiler.modifier.servlet.interceptors.DoXXXInterceptor"); - Interceptor doPostInterceptor = byteCodeInstrumentor.newInterceptor(classLoader, protectedDomain, "com.profiler.modifier.servlet.interceptors.DoXXXInterceptor"); + Interceptor doGetInterceptor = byteCodeInstrumentor.newInterceptor(classLoader, protectedDomain, "com.profiler.modifier.method.interceptors.MethodInterceptor"); + Interceptor doPostInterceptor = byteCodeInstrumentor.newInterceptor(classLoader, protectedDomain, "com.profiler.modifier.method.interceptors.MethodInterceptor"); setTraceContext(doGetInterceptor); setTraceContext(doPostInterceptor); diff --git a/src/main/java/com/profiler/modifier/servlet/SpringFrameworkServletModifier.java b/src/main/java/com/profiler/modifier/servlet/SpringFrameworkServletModifier.java index f67dec6d1..863ee6c3f 100644 --- a/src/main/java/com/profiler/modifier/servlet/SpringFrameworkServletModifier.java +++ b/src/main/java/com/profiler/modifier/servlet/SpringFrameworkServletModifier.java @@ -36,8 +36,8 @@ public class SpringFrameworkServletModifier extends AbstractModifier { byteCodeInstrumentor.checkLibrary(classLoader, javassistClassName); try { - Interceptor doGetInterceptor = byteCodeInstrumentor.newInterceptor(classLoader, protectedDomain, "com.profiler.modifier.servlet.interceptors.DoXXXInterceptor"); - Interceptor doPostInterceptor = byteCodeInstrumentor.newInterceptor(classLoader, protectedDomain, "com.profiler.modifier.servlet.interceptors.DoXXXInterceptor"); + Interceptor doGetInterceptor = byteCodeInstrumentor.newInterceptor(classLoader, protectedDomain, "com.profiler.modifier.method.interceptors.MethodInterceptor"); + Interceptor doPostInterceptor = byteCodeInstrumentor.newInterceptor(classLoader, protectedDomain, "com.profiler.modifier.method.interceptors.MethodInterceptor"); setTraceContext(doGetInterceptor); setTraceContext(doPostInterceptor); diff --git a/src/main/java/com/profiler/modifier/servlet/interceptors/DoXXXInterceptor.java b/src/main/java/com/profiler/modifier/servlet/interceptors/DoXXXInterceptor.java index 91af356f5..c1a0943ff 100644 --- a/src/main/java/com/profiler/modifier/servlet/interceptors/DoXXXInterceptor.java +++ b/src/main/java/com/profiler/modifier/servlet/interceptors/DoXXXInterceptor.java @@ -30,6 +30,30 @@ public class DoXXXInterceptor implements StaticAroundInterceptor, ByteCodeMethod private int apiId; private TraceContext traceContext; +/* + java.lang.IllegalStateException: already Trace Object exist. + at com.profiler.context.TraceContext.attachTraceObject(TraceContext.java:54) + at com.profiler.modifier.servlet.interceptors.DoXXXInterceptor.before(DoXXXInterceptor.java:62) + at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java) // profile method +** at javax.servlet.http.HttpServlet.service(HttpServlet.java:617) // profile method + at javax.servlet.http.HttpServlet.service(HttpServlet.java:717) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) +** at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) // make traceId here + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293) + at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859) + at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:602) + at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489) + at java.lang.Thread.run(Thread.java:680) +*/ @Override public void before(Object target, String className, String methodName, String parameterDescription, Object[] args) { if (logger.isLoggable(Level.INFO)) {