使用Javassist记录方法调用和参数值,如何使记录器类在每个插入指令的类中可见?
工具(in)包括3类(如下所示)。问题是如何使我的使用Javassist记录方法调用和参数值,如何使记录器类在每个插入指令的类中可见?,java,logging,javassist,Java,Logging,Javassist,工具(in)包括3类(如下所示)。问题是如何使我的ParaTracer.Logger类在每个class I仪器中可见(例如下面显示的java.util.Random)。语句cp.importPackage(“ParaTracer.Logger”)似乎不起作用,我遇到以下错误: java.lang.NoClassDefFoundError:ParaTracer/Logger 在java.util.Random.nextLong(Random.java) 我尝试在每个插入指令的类中动态加载Logge
ParaTracer.Logger
类在每个class I仪器中可见(例如下面显示的java.util.Random
)。语句cp.importPackage(“ParaTracer.Logger”)代码>似乎不起作用,我遇到以下错误:
java.lang.NoClassDefFoundError:ParaTracer/Logger
在java.util.Random.nextLong(Random.java)
我尝试在每个插入指令的类中动态加载Logger
类。但似乎我使用的Class.getMethod()
不正确,或者Javassist编译器太原始,无法编译动态类加载代码。我得到这个错误:
javassist.CannotCompileException:[源代码错误]在java.lang.Class中找不到getMethod(java.lang.String、java.lang.Class、java.lang.Class)
以下3个类被导出到一个JAR文件中,其中MANIFEST.MF文件定义了Premain类
,并在使用开关运行任何插入指令的程序时传递给JVM:
-javaagent:/Path/To/pararaceragent.jar
这是三节课
package ParaTracer;
import java.lang.instrument.Instrumentation;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtField;
import javassist.CtNewConstructor;
import javassist.CtNewMethod;
public class ParaTracer {
private static volatile Instrumentation instr;
public static void premain(String agentArgs, Instrumentation inst) {
instr = inst;
SimpleClassTransformer transformer = new SimpleClassTransformer();
inst.addTransformer( transformer, false );
}
}
变压器等级:
package ParaTracer;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import java.util.HashMap;
import java.util.HashSet;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
public class SimpleClassTransformer implements ClassFileTransformer {
public HashMap< String, HashSet< String > > mInstrumentedMethods;
public SimpleClassTransformer() {
mInstrumentedMethods = new HashMap< String, HashSet< String > >();
mInstrumentedMethods.put( "java.util.Random", new HashSet< String >() );
mInstrumentedMethods.get( "java.util.Random").add( "nextLong" );
}
@Override
public byte[] transform(
ClassLoader loader,
String className,
Class<?> classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
System.err.println( "---- Instrumenting: " + className );
byte[] byteCode = classfileBuffer;
String normalizedClassName = className.replaceAll("/", ".");
if ( mInstrumentedMethods.containsKey( normalizedClassName ) ) {
try {
ClassPool cp = ClassPool.getDefault();
cp.importPackage( "ParaTracer.Logger");
CtClass cc = cp.get( normalizedClassName );
for( String method : mInstrumentedMethods.get( normalizedClassName ) ) {
CtMethod m = cc.getDeclaredMethod( method );
StringBuilder sbs = new StringBuilder();
sbs.append( "long tid = Thread.currentThread().getId();" );
sbs.append( "StringBuilder sbArgs = new StringBuilder();" );
sbs.append( "sbArgs.append( System.identityHashCode( $0 ) );" );
CtClass[] pTypes = m.getParameterTypes();
for( int i=0; i < pTypes.length; ++i ) {
CtClass pType = pTypes[i];
if ( pType.isPrimitive() ) {
sbs.append( "sbArgs.append( \", \" + $args[" + i + "] );" );
} else {
sbs.append( "sbArgs.append( \", \" + System.identityHashCode( $args[" + i + "] ) );" );
}
}
sbs.append( "ParaTracer.Logger.pushArgs( tid, sbArgs.toString() );" );
sbs.append( "StringBuilder sb = new StringBuilder();" );
sbs.append( "sb.append( tid + \" : " + m.getLongName() + ".<START>(\" );" );
sbs.append( "sb.append( sbArgs.toString() );" );
sbs.append( "sb.append( \")\" );" );
sbs.append( "ParaTracer.Logger.print( sb.toString() );" );
m.insertBefore("{" + sbs.toString() + "}");
StringBuilder sbe = new StringBuilder();
sbe.append( "long tid = Thread.currentThread().getId();" );
sbe.append( "String args = ParaTracer.Logger.popArgs( tid );" );
sbe.append( "StringBuilder sb = new StringBuilder();" );
sbe.append( "sb.append( tid + \" : " + m.getLongName() + ".<END>(\" );" );
sbe.append( "sb.append( args );" );
sbe.append( "sb.append( \")\" );" );
sbe.append( "ParaTracer.Logger.print( sb.toString() );" );
m.insertAfter("{" + sbe.toString() + "}");
}
byteCode = cc.toBytecode();
cc.detach();
} catch (Exception ex) {
ex.printStackTrace();
}
}
return byteCode;
}
}
packageparatracer;
导入java.lang.instrument.ClassFileTransformer;
导入java.lang.instrument.IllegalClassFormatException;
导入java.security.ProtectionDomain;
导入java.util.HashMap;
导入java.util.HashSet;
导入javassist.ClassPool;
导入javassist.CtClass;
导入javassist.CtMethod;
公共类SimpleClassTransformer实现ClassFileTransformer{
公共HashMap>mInstrumentedMethods;
公共SimpleClassTransformer(){
mInstrumentedMethods=newhashmap>();
mInstrumentedMethods.put(“java.util.Random”,新的HashSet());
mInstrumentedMethods.get(“java.util.Random”).add(“nextLong”);
}
@凌驾
公共字节[]转换(
类加载器,
字符串类名称,
类被重新定义,
ProtectionDomain ProtectionDomain,
字节[]classfileBuffer)引发IllegalClassFormatException{
System.err.println(“----检测:“+className”);
字节[]字节码=classfileBuffer;
字符串normalizedClassName=className.replaceAll(“/”,“);
if(mInstrumentedMethods.containsKey(normalizedClassName)){
试一试{
ClassPool cp=ClassPool.getDefault();
cp.importPackage(“ParaTracer.Logger”);
CtClass cc=cp.get(normalizedClassName);
for(字符串方法:mInstrumentedMethods.get(normalizedClassName)){
CTM方法=cc.getDeclaredMethod(方法);
StringBuilder sbs=新的StringBuilder();
append(“longtid=Thread.currentThread().getId();”;
append(“StringBuilder sbArgs=new StringBuilder();”;
append(“sbArgs.append(System.identityHashCode($0));”;
CtClass[]pTypes=m.getParameterTypes();
对于(int i=0;i
线程安全记录器类由以下内容给出:
package ParaTracer;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Stack;
public class Logger {
private static String loggerFilePath = "\"/some/fixed/path\"";
private static FileWriter fw;
private static PrintWriter out;
private static HashMap< Long, Stack<String> > callStacks;
public static synchronized void pushArgs( long tid, String args ) {
try {
init();
} catch (IOException e) {
e.printStackTrace();
}
if ( ! callStacks.containsKey( tid ) ) {
callStacks.put( tid, new Stack<String>() );
}
callStacks.get( tid ).push( args );
}
public static synchronized String popArgs( long tid ) {
assert( callStacks.containsKey( tid ) );
assert( ! callStacks.get( tid ).empty() );
return callStacks.get( tid ).pop();
}
public static synchronized void shutdown() {
if ( fw == null ) return;
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static synchronized void print( String str ) {
try {
init();
} catch (IOException e) {
e.printStackTrace();
}
out.print( str );
}
private static void init() throws IOException {
if ( fw != null ) return;
fw = new FileWriter( loggerFilePath );
out = new PrintWriter( fw );
callStacks = new HashMap< Long, Stack<String> >();
}
}
packageparatracer;
导入java.io.FileWriter;
导入java.io.IOException;
导入java.io.PrintWriter;
导入java.util.HashMap;
导入java.util.Stack;
公共类记录器{
私有静态字符串loggerFilePath=“\”/some/fixed/path\”;
私有静态文件编写器;
专用静态打印输出;
私有静态HashMapcallStacks;
公共静态同步void pushArgs(长tid,字符串args){
试一试{
init();
}捕获(IOE异常){
e、 printStackTrace();
}
如果(!callStacks.containsKey(tid)){
put(tid,newstack());
}
调用堆栈.get(tid).push(args);
}
公共静态同步字符串popArgs(长tid){
断言(callStacks.containsKey)
@Override
public byte[] transform(
ClassLoader loader,
String className,
Class<?> classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer)
throws IllegalClassFormatException {
byte[] byteCode = classfileBuffer;
String normalizedClassName = className.replaceAll("/", ".");
System.out.println( "\tNormalized: " + normalizedClassName );
ClassMonitorSet classMonitorSet = monitorClass( normalizedClassName );
if ( classMonitorSet != null ) {
System.out.println( "\tMonitoring: " + normalizedClassName );
try {
ClassPool cp = ClassPool.getDefault();
CtClass cc = cp.get( normalizedClassName );
for( String methodName : classMonitorSet.monitorSet ) {
CtMethod[] methods = cc.getDeclaredMethods( methodName );
for( CtMethod method : methods ) {
StringBuilder sbs = new StringBuilder();
sbs.append( "long tid = Thread.currentThread().getId();" );
sbs.append( "StringBuilder sbArgs = new StringBuilder();" );
sbs.append( "sbArgs.append( System.identityHashCode( $0 ) );" );
CtClass[] pTypes = method.getParameterTypes();
for( int i=0; i < pTypes.length; ++i ) {
CtClass pType = pTypes[i];
if ( pType.isPrimitive() ) {
sbs.append( "sbArgs.append( \", \" + $args[" + i + "] );" );
} else {
sbs.append( "sbArgs.append( \", \" + System.identityHashCode( $args[" + i + "] ) );" );
}
}
sbs.append( "StringBuilder sb = new StringBuilder();" );
sbs.append( "sb.append( tid + \" : " + method.getLongName() + ".<START>(\" );" );
sbs.append( "sb.append( sbArgs.toString() );" );
sbs.append( "sb.append( \")\" );" );
sbs.append( "String fPath = \"/path/to/log.out\";" );
sbs.append( "try {" );
sbs.append( " java.io.FileWriter fw = new java.io.FileWriter( fPath, true );" );
sbs.append( " java.io.PrintWriter out = new java.io.PrintWriter( fw, true );" );
sbs.append( " out.println( sb.toString() );" );
sbs.append( " fw.close();" );
sbs.append( "} catch (java.io.IOException e) {" );
sbs.append( " e.printStackTrace();" );
sbs.append( "}" );
method.insertBefore("{" + sbs.toString() + "}");
StringBuilder sbe = new StringBuilder();
sbe.append( "long tid = Thread.currentThread().getId();" );
sbe.append( "StringBuilder sb = new StringBuilder();" );
sbe.append( "sb.append( tid + \" : " + method.getLongName() + ".<END>(*)\" );" );
sbe.append( "String fPath = \"/path/to/log.out\";" );
sbe.append( "try {" );
sbe.append( " java.io.FileWriter fw = new java.io.FileWriter( fPath, true );" );
sbe.append( " java.io.PrintWriter out = new java.io.PrintWriter( fw, true );" );
sbe.append( " out.println( sb.toString() );" );
sbe.append( " fw.close();" );
sbe.append( "} catch (java.io.IOException e) {" );
sbe.append( " e.printStackTrace();" );
sbe.append( "}" );
method.insertAfter("{" + sbe.toString() + "}");
}
}
byteCode = cc.toBytecode();
cc.detach();
} catch (Exception ex) {
ex.printStackTrace();
}
}
return byteCode;
}
Boot-Class-Path: ParaTracerLogger.jar