diff --git a/src/main/java/com/profiler/interceptor/bci/InstrumentClass.java b/src/main/java/com/profiler/interceptor/bci/InstrumentClass.java index 55a3b4164..996a28bd2 100644 --- a/src/main/java/com/profiler/interceptor/bci/InstrumentClass.java +++ b/src/main/java/com/profiler/interceptor/bci/InstrumentClass.java @@ -4,9 +4,13 @@ import com.profiler.interceptor.Interceptor; public interface InstrumentClass { + boolean insertCodeBeforeMethod(String methodName, String[] args, String code); + + boolean insertCodeAfterMethod(String methodName, String[] args, String code); + boolean addInterceptor(String methodName, String[] args, Interceptor interceptor); - boolean addInterceptor(String methodName, String[] args, Interceptor interceptor, Type type); + boolean addInterceptor(String methodName, String[] args, Interceptor interceptor, Type type); boolean addDebugLogBeforeAfterMethod(); @@ -16,5 +20,9 @@ public interface InstrumentClass { Class toClass(); - boolean addTraceVariable(String variableName, String setterName, String getterName, String variableType); + boolean addTraceVariable(String variableName, String setterName, String getterName, String variableType); + + boolean insertCodeAfterConstructor(String[] args, String code); + + boolean insertCodeBeforeConstructor(String[] args, String code); } diff --git a/src/main/java/com/profiler/interceptor/bci/JavaAssistByteCodeInstrumentor.java b/src/main/java/com/profiler/interceptor/bci/JavaAssistByteCodeInstrumentor.java index 97e2d0a28..d420cc17c 100644 --- a/src/main/java/com/profiler/interceptor/bci/JavaAssistByteCodeInstrumentor.java +++ b/src/main/java/com/profiler/interceptor/bci/JavaAssistByteCodeInstrumentor.java @@ -118,9 +118,9 @@ public class JavaAssistByteCodeInstrumentor implements ByteCodeInstrumentor { logger.info("Loaded " + filePath + " library."); } } catch (NotFoundException e) { - if (logger.isLoggable(Level.WARNING)) { - logger.log(Level.WARNING, "lib not fail. " + e.getMessage(), e); - } + if (logger.isLoggable(Level.WARNING)) { + logger.log(Level.WARNING, "lib not fail. " + e.getMessage(), e); + } } } } diff --git a/src/main/java/com/profiler/interceptor/bci/JavaAssistClass.java b/src/main/java/com/profiler/interceptor/bci/JavaAssistClass.java index b8c1d1efa..4af6d7544 100644 --- a/src/main/java/com/profiler/interceptor/bci/JavaAssistClass.java +++ b/src/main/java/com/profiler/interceptor/bci/JavaAssistClass.java @@ -25,36 +25,105 @@ public class JavaAssistClass implements InstrumentClass { this.ctClass = ctClass; } - public CtClass getCtClass() { - return ctClass; - } + public CtClass getCtClass() { + return ctClass; + } - // TODO return type을 별도 exception으로 할지 추가 검토가 필요함. - public boolean addTraceVariable(String variableName, String setterName, String getterName, String variableType) { - try { - CtClass type = instrumentor.getClassPool().get(variableType); - CtField traceVariable = new CtField(type, variableName, ctClass); - ctClass.addField(traceVariable); - CtMethod setterMethod = CtNewMethod.setter(setterName, traceVariable); - ctClass.addMethod(setterMethod); - CtMethod getterMethod = CtNewMethod.getter(getterName, traceVariable); - ctClass.addMethod(getterMethod); - return true; - } catch (NotFoundException e) { - if (logger.isLoggable(Level.WARNING)) { + @Override + public boolean insertCodeBeforeConstructor(String[] args, String code) { + try { + CtConstructor constructor = getConstructor(args); + if (constructor == null) { + return false; + } + constructor.insertBefore(code); + return true; + } catch (Exception e) { + if (logger.isLoggable(Level.WARNING)) { logger.log(Level.WARNING, e.getMessage(), e); } - } catch (CannotCompileException e) { - if (logger.isLoggable(Level.WARNING)) { + return false; + } + } + + @Override + public boolean insertCodeAfterConstructor(String[] args, String code) { + try { + CtConstructor constructor = getConstructor(args); + if (constructor == null) { + return false; + } + constructor.insertAfter(code); + return true; + } catch (Exception e) { + if (logger.isLoggable(Level.WARNING)) { logger.log(Level.WARNING, e.getMessage(), e); } - } - return false; - } + return false; + } + } - @Override + @Override + public boolean insertCodeBeforeMethod(String methodName, String[] args, String code) { + try { + CtMethod method = getMethod(methodName, args); + if (method == null) { + return false; + } + method.insertBefore(code); + return true; + } catch (Exception e) { + if (logger.isLoggable(Level.WARNING)) { + logger.log(Level.WARNING, e.getMessage(), e); + } + return false; + } + } + + @Override + public boolean insertCodeAfterMethod(String methodName, String[] args, String code) { + try { + CtMethod method = getMethod(methodName, args); + if (method == null) { + return false; + } + method.insertAfter(code); + return true; + } catch (Exception e) { + if (logger.isLoggable(Level.WARNING)) { + logger.log(Level.WARNING, e.getMessage(), e); + } + return false; + } + } + + // TODO return type을 별도 exception으로 할지 추가 검토가 필요함. + @Override + public boolean addTraceVariable(String variableName, String setterName, String getterName, String variableType) { + try { + CtClass type = instrumentor.getClassPool().get(variableType); + CtField traceVariable = new CtField(type, variableName, ctClass); + ctClass.addField(traceVariable); + CtMethod setterMethod = CtNewMethod.setter(setterName, traceVariable); + ctClass.addMethod(setterMethod); + CtMethod getterMethod = CtNewMethod.getter(getterName, traceVariable); + ctClass.addMethod(getterMethod); + return true; + } catch (NotFoundException e) { + if (logger.isLoggable(Level.WARNING)) { + logger.log(Level.WARNING, e.getMessage(), e); + } + } catch (CannotCompileException e) { + if (logger.isLoggable(Level.WARNING)) { + logger.log(Level.WARNING, e.getMessage(), e); + } + } + return false; + } + + @Override public boolean addInterceptor(String methodName, String[] args, Interceptor interceptor) { - return addInterceptor(methodName, args, interceptor, Type.auto); + return addInterceptor(methodName, args, interceptor, Type.auto); } @Override @@ -63,31 +132,31 @@ public class JavaAssistClass implements InstrumentClass { return false; CtMethod method = getMethod(methodName, args); - if(method == null) { - return false; - } + if (method == null) { + return false; + } int id = InterceptorRegistry.addInterceptor(interceptor); try { - if(type == Type.auto) { - if (interceptor instanceof StaticAroundInterceptor) { - addStaticAroundInterceptor(methodName, id, method); - } else if (interceptor instanceof StaticBeforeInterceptor) { - addStaticBeforeInterceptor(methodName, id, method); - } else if (interceptor instanceof StaticAfterInterceptor) { - addStaticAfterInterceptor(methodName, id, method); - } else { - return false; - } - } else if(type == Type.around && interceptor instanceof StaticAroundInterceptor) { - addStaticAroundInterceptor(methodName, id, method); - } else if(type == Type.before && interceptor instanceof StaticBeforeInterceptor) { - addStaticBeforeInterceptor(methodName, id, method); - } else if(type == Type.after && interceptor instanceof StaticAfterInterceptor) { - addStaticAfterInterceptor(methodName, id, method); - } else { - return false; - } + if (type == Type.auto) { + if (interceptor instanceof StaticAroundInterceptor) { + addStaticAroundInterceptor(methodName, id, method); + } else if (interceptor instanceof StaticBeforeInterceptor) { + addStaticBeforeInterceptor(methodName, id, method); + } else if (interceptor instanceof StaticAfterInterceptor) { + addStaticAfterInterceptor(methodName, id, method); + } else { + return false; + } + } else if (type == Type.around && interceptor instanceof StaticAroundInterceptor) { + addStaticAroundInterceptor(methodName, id, method); + } else if (type == Type.before && interceptor instanceof StaticBeforeInterceptor) { + addStaticBeforeInterceptor(methodName, id, method); + } else if (type == Type.after && interceptor instanceof StaticAfterInterceptor) { + addStaticAfterInterceptor(methodName, id, method); + } else { + return false; + } return true; } catch (NotFoundException e) { if (logger.isLoggable(Level.WARNING)) { @@ -110,9 +179,9 @@ public class JavaAssistClass implements InstrumentClass { StringBuilder after = new StringBuilder(1024); after.append("{"); addGetStaticAfterInterceptor(after, id); - String target = getTarget(behavior); - String returnType = getReturnType(behavior); - after.append(" interceptor.after(" + target + ", \"" + ctClass.getName() + "\", \"" + methodName + "\", $args, " + returnType + ");"); + String target = getTarget(behavior); + String returnType = getReturnType(behavior); + after.append(" interceptor.after(" + target + ", \"" + ctClass.getName() + "\", \"" + methodName + "\", $args, " + returnType + ");"); after.append("}"); String buildAfter = after.toString(); if (logger.isLoggable(Level.INFO)) { @@ -135,31 +204,31 @@ public class JavaAssistClass implements InstrumentClass { } - private String getTarget(CtBehavior behavior) { - boolean staticMethod = isStatic(behavior); - if(staticMethod) { - return "null"; - } else { - return "this"; - } - } + private String getTarget(CtBehavior behavior) { + boolean staticMethod = isStatic(behavior); + if (staticMethod) { + return "null"; + } else { + return "this"; + } + } - public String getReturnType(CtBehavior behavior) throws NotFoundException { - if(behavior instanceof CtMethod) { - CtClass returnType = ((CtMethod) behavior).getReturnType(); - if(CtClass.voidType == returnType) { - return "null"; - } - } - return "($w)$_"; - } + public String getReturnType(CtBehavior behavior) throws NotFoundException { + if (behavior instanceof CtMethod) { + CtClass returnType = ((CtMethod) behavior).getReturnType(); + if (CtClass.voidType == returnType) { + return "null"; + } + } + return "($w)$_"; + } - private boolean isStatic(CtBehavior behavior) { - int modifiers = behavior.getModifiers(); - return java.lang.reflect.Modifier.isStatic(modifiers); - } + private boolean isStatic(CtBehavior behavior) { + int modifiers = behavior.getModifiers(); + return java.lang.reflect.Modifier.isStatic(modifiers); + } - private void addGetStaticAfterInterceptor(StringBuilder after, int id) { + private void addGetStaticAfterInterceptor(StringBuilder after, int id) { after.append(" com.profiler.interceptor.StaticAfterInterceptor interceptor = " + "(com.profiler.interceptor.StaticAfterInterceptor) com.profiler.interceptor.InterceptorRegistry.getInterceptor("); after.append(id); after.append(");"); @@ -169,8 +238,8 @@ public class JavaAssistClass implements InstrumentClass { StringBuilder code = new StringBuilder(1024); code.append("{"); addGetBeforeInterceptor(id, code); - String target = getTarget(behavior); - code.append(" interceptor.before(" + target + ", \"" + ctClass.getName() + "\", \"" + methodName + "\", $args);"); + String target = getTarget(behavior); + code.append(" interceptor.before(" + target + ", \"" + ctClass.getName() + "\", \"" + methodName + "\", $args);"); code.append("}"); String buildBefore = code.toString(); if (logger.isLoggable(Level.INFO)) { @@ -279,15 +348,27 @@ public class JavaAssistClass implements InstrumentClass { private CtMethod getMethod(String methodName, String[] args) { try { - CtClass[] params = getCtParameter(args); - return ctClass.getDeclaredMethod(methodName, params); - } catch (NotFoundException e) { + CtClass[] params = getCtParameter(args); + return ctClass.getDeclaredMethod(methodName, params); + } catch (NotFoundException e) { if (logger.isLoggable(Level.WARNING)) { logger.log(Level.WARNING, e.getMessage(), e); } - } - return null; - } + } + return null; + } + + private CtConstructor getConstructor(String[] args) { + try { + CtClass[] params = getCtParameter(args); + return ctClass.getDeclaredConstructor(params); + } catch (NotFoundException e) { + if (logger.isLoggable(Level.WARNING)) { + logger.log(Level.WARNING, e.getMessage(), e); + } + } + return null; + } private CtClass[] getCtParameter(String[] args) throws NotFoundException { if (args == null) { @@ -320,6 +401,4 @@ public class JavaAssistClass implements InstrumentClass { } return null; } - - } diff --git a/src/main/java/com/profiler/interceptor/bci/Type.java b/src/main/java/com/profiler/interceptor/bci/Type.java index e8f1c00ad..bc922fe19 100644 --- a/src/main/java/com/profiler/interceptor/bci/Type.java +++ b/src/main/java/com/profiler/interceptor/bci/Type.java @@ -1,5 +1,5 @@ package com.profiler.interceptor.bci; public enum Type { - around, before, after, auto + around, before, after, auto } diff --git a/src/main/java/com/profiler/modifier/arcus/ArcusClientModifier.java b/src/main/java/com/profiler/modifier/arcus/ArcusClientModifier.java index 22dda2cfa..1f2e670e9 100644 --- a/src/main/java/com/profiler/modifier/arcus/ArcusClientModifier.java +++ b/src/main/java/com/profiler/modifier/arcus/ArcusClientModifier.java @@ -1,15 +1,11 @@ package com.profiler.modifier.arcus; -import java.nio.ByteBuffer; import java.security.ProtectionDomain; import java.util.logging.Level; import java.util.logging.Logger; -import javassist.CtClass; -import javassist.CtMethod; - -import com.profiler.context.Trace; import com.profiler.interceptor.bci.ByteCodeInstrumentor; +import com.profiler.interceptor.bci.InstrumentClass; import com.profiler.modifier.AbstractModifier; /** @@ -37,45 +33,67 @@ public class ArcusClientModifier extends AbstractModifier { try { classLoader.loadClass("net.spy.memcached.ops.OperationState"); - CtClass cc = classPool.get(javassistClassName); - CtClass[] params1 = new CtClass[1]; - params1[0] = classPool.getCtClass("net.spy.memcached.ops.OperationState"); - CtMethod transitionStateMethod = cc.getDeclaredMethod("transitionState", params1); + InstrumentClass aClass = byteCodeInstrumentor.getClass(javassistClassName); - StringBuilder code = new StringBuilder(); - code.append("{"); - -// code.append("System.out.println($1);"); -// code.append("System.out.println(\"Change state \" + state + \" -> \" + newState);"); -// code.append("System.out.println(handlingNode);"); -// code.append("System.out.println(\"cmd=\" + ((cmd == null) ? null : new String(cmd.array())));"); -// code.append("System.out.println(Thread.currentThread().getId());"); -// code.append("System.out.println(Thread.currentThread().getName());"); -// code.append("System.out.println(\"\");"); -// code.append("System.out.println(\"\");"); -// code.append("System.out.println(\"\");"); - - code.append("if (newState == net.spy.memcached.ops.OperationState.READING) {"); - code.append(" java.net.SocketAddress socketAddress = handlingNode.getSocketAddress();"); - code.append(" if (socketAddress instanceof java.net.InetSocketAddress) {"); - code.append(" java.net.InetSocketAddress addr = (java.net.InetSocketAddress) handlingNode.getSocketAddress();"); - code.append(" com.profiler.context.Trace.recordEndPoint(addr.getHostName(), addr.getPort());"); - code.append(" }"); - code.append(" com.profiler.context.Trace.recordRpcName(\"arcus\", ((cmd == null) ? \"UNKNOWN\" : new String(cmd.array())));"); - code.append(" System.out.println(\"CS\");"); - code.append(" com.profiler.context.Trace.record(com.profiler.context.Annotation.ClientSend);"); - code.append("} else if (newState == net.spy.memcached.ops.OperationState.COMPLETE) {"); - code.append(" System.out.println(\"CR\");"); - code.append(" com.profiler.context.Trace.record(com.profiler.context.Annotation.ClientRecv);"); - code.append("}"); - - code.append("}"); - transitionStateMethod.insertBefore(code.toString()); - - return cc.toBytecode(); + /** + * inject both current and next traceId. + */ + aClass.addTraceVariable("__traceId", "__setTraceId", "__getTraceId", "com.profiler.context.TraceID"); + aClass.addTraceVariable("__nextTraceId", "__setNextTraceId", "__getNextTraceId", "com.profiler.context.TraceID"); + aClass.insertCodeAfterConstructor(null, "{ __setTraceId(com.profiler.context.Trace.getCurrentTraceId()); __setNextTraceId(com.profiler.context.Trace.getNextId()); }"); + + aClass.insertCodeBeforeMethod("transitionState", new String[] { "net.spy.memcached.ops.OperationState" }, getTransitionStateAfterCode()); + + return aClass.toBytecode(); } catch (Exception e) { - e.printStackTrace(); + if (logger.isLoggable(Level.WARNING)) { + logger.log(Level.WARNING, e.getMessage(), e); + } return null; } } + + /** + * Logic is different in OperationState. + * + * @return + */ + private String getTransitionStateAfterCode() { + StringBuilder code = new StringBuilder(); + code.append("{"); + + /** + * If current traceID is not exists, take nextId for current traceID. + */ + code.append("if (com.profiler.context.Trace.getCurrentTraceId() == null) { com.profiler.context.Trace.setTraceId(__nextTraceId); }"); + + // code.append("System.out.println(__traceId);"); + // code.append("System.out.println($1);"); + // code.append("System.out.println(\"Change state \" + state + \" -> \" + newState);"); + // code.append("System.out.println(handlingNode);"); + // code.append("System.out.println(\"cmd=\" + ((cmd == null) ? null : new String(cmd.array())));"); + // code.append("System.out.println(Thread.currentThread().getId());"); + // code.append("System.out.println(Thread.currentThread().getName());"); + // code.append("System.out.println(\"\");"); + // code.append("System.out.println(\"\");"); + // code.append("System.out.println(\"\");"); + + code.append("if (newState == net.spy.memcached.ops.OperationState.READING) {"); + code.append(" java.net.SocketAddress socketAddress = handlingNode.getSocketAddress();"); + code.append(" if (socketAddress instanceof java.net.InetSocketAddress) {"); + code.append(" java.net.InetSocketAddress addr = (java.net.InetSocketAddress) handlingNode.getSocketAddress();"); + code.append(" com.profiler.context.Trace.recordEndPoint(addr.getHostName(), addr.getPort());"); + code.append(" }"); + code.append(" com.profiler.context.Trace.recordRpcName(\"arcus\", ((cmd == null) ? \"UNKNOWN\" : new String(cmd.array())));"); + code.append(" System.out.println(\"CS\");"); + code.append(" com.profiler.context.Trace.record(com.profiler.context.Annotation.ClientSend);"); + code.append("} else if (newState == net.spy.memcached.ops.OperationState.COMPLETE) {"); + code.append(" System.out.println(\"CR\");"); + code.append(" com.profiler.context.Trace.record(com.profiler.context.Annotation.ClientRecv);"); + code.append("}"); + + code.append("}"); + + return code.toString(); + } } \ No newline at end of file