java中类型记录器,使用Javassist记录方法调用和参数值,如何在每个检测类中显示记录器类?...

该工具(在

this repo中)包括3个类(下面给出).问题是如何使我的ParaTracer.Logger类在我的每个类中都可见(例如下面的java.util.Random).语句cp.importPackage(“ParaTracer.Logger”);似乎不起作用,我收到此错误:

java.lang.NoClassDefFoundError:ParaTracer / Logger

在java.util.Random.nextLong(Random.java)

我尝试在每个检测类中动态加载Logger类.但似乎我错误地使用了Class.getMethod(),或者Javassist编译器太原始而无法编译动态类加载代码.我收到此错误:

javassist.CannotCompileException:[source error] java.lang.Class中找不到getMethod(java.lang.String,java.lang.Class,java.lang.Class)

使用定义Premain-Class的MANIFEST.MF文件将以下3个类导出到JAR文件中,并在使用该开关运行任何已检测程序时传递给JVM:

-javaagent:/Path/To/ParaTracerAgent.jar

这是3个班级.

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() + ".(\" );" );

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() + ".(\" );" );

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;

}

}

线程安全的记录器类由下式给出:

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 > 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() );

}

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 >();

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值