TracingClassLoader
A ClassLoader that instruments classes on
load-time with tracing output statements.
Download sources for version 2.0, upgraded to work with Jakarta BCEL 20050813 (older version used
This is a ClassLoader that can add trace output around methods
of classes without modifying the classes on disk. It is one of a series
of experiments I intend to perform in the field of AOP.
The ClassLoader is initialized with a ClassMethodFilter, which is queried
to determine which classes and methods list should
be instrumented. In any case, the ClassLoader will not try to redefine classes
in packages starting with java.* (this is not possible), nor will it instrument
constructors (because the way I add instrumentation will not work with
constructors, which are validated with special rules).
The instrumentation is really basic for now. While entering a method it outputs:
``thread''``method name''(``arguments'')
or
``thread''``this''.``method name''(``arguments'')
depending on whether it's a static method or not, and while exiting it displays
``thread''``method name''==>``return value''
or
``thread''``method name''==>(void)
for void
methods. In case an exception is thrown, it outputs
``thread''``method name''==>threw exception ``exception''
This is sample output from a small run:
[dsouflis@localhost TracingClassLoader]java -classpath bcel.jar:aopclsuite.jar:. name.dsouflis.Trace test.TestTarget test.Main
Will trace test.TestTarget
Tracing class test.TestTarget
Thread[Thread-0,5,main]test.TestTarget@546e25.foo(3,test.TestTarget@546e25)
Thread[Thread-0,5,main]test.TestTarget@546e25.bar()
Thread[Thread-0,5,main]bar=>4
Thread[Thread-0,5,main]foo=>(void)
Thread[Thread-0,5,main]test.TestTarget@546e25.bar()
Thread[Thread-0,5,main]bar=>18
The utility name.dsouflis.aop.tracing.Trace is an application runner that uses
a TracingClassLoader to run a class. It takes two arguments, the first being
a comma-separated list of classes to trace, and the second being the class to
run. It is used like this:
java name.dsouflis.aop.tracing.JavaWrapper ``class to instrument,...'' ``class to run'' ``arguments...''
The utility name.dsouflis.aop.tracing.AddTracing is a utility that uses
internal methods of TracingClassLoader to instrument a class.
The class image on disk is modified, and one can inspect it with javap
or BCEL's listclass
. If you run it more than once, or trace the resulting
class, things will probably look very messy.
It is used like this:
java name.dsouflis.aop.tracing.AddTracing ``class to instrument''
The supplied aopclsuite.jar and bcel.jar must be in the CLASSPATH.
How the instrumentation works
All methods that are instrumented have their names changed to "hidden$name", and new methods are created to take their place. The new methods call the hidden ones and take care of the output before and after the call.
As an example, consider the following class:
/*
* TestTarget.java
*
* Created on April 2, 2002, 9:33 PM
*/
package test;
/**
*
* @author dsouflis
* @version
*/
public class TracingTarget extends Object {
int x;
/** Creates new TestTarget */
public TracingTarget() {
x=2;
}
public void foo(long y, TracingTarget t) {
t.x=(int)(y+x)+bar();
}
public int bar() {
return x*2;
}
public static void main(String[] args) {
TracingTarget t=new TracingTarget();
t.foo(3,t);
t.bar();
t.foo(4,t);
}
}
The instrumentation added is marked in red, and
existing stuff that was modified is marked in blue:
Compiled from TestTarget.java
public class test.TestTarget extends java.lang.Object {
int x;
public test.TestTarget();
public void foo(long, test.TestTarget);
public int bar();
public static void main(java.lang.String[]);
}
Method test.TestTarget()
0 nop
1 aload_0
2 invokespecial #11
5 aload_0
6 iconst_2
7 putfield #13
10 return
Method void hidden$foo(long, test.TracingTarget)
0 nop
0 nop
1 aload_3
2 lload_1
3 aload_0
4 getfield #13
7 i2l
8 ladd
9 l2i
10 aload_0
11 invokevirtual #23
14 iadd
15 putfield #13
18 lload_1
19 ldc2_w #24
22 lcmp
23 ifne 36
26 new #27
29 dup
30 ldc #29
32 invokespecial #32
35 athrow
36 return
Method int hidden$bar()
0 nop
0 nop
1 aload_0
2 getfield #13
5 iconst_2
6 imul
7 ireturn
Method void hidden$main(java.lang.String[])
0 nop
0 nop
1 new #2
4 dup
5 invokespecial #38
8 astore_1
9 aload_1
10 ldc2_w #39
13 aload_1
14 invokevirtual #42
17 aload_1
18 invokevirtual #23
21 pop
22 aload_1
23 ldc2_w #24
26 aload_1
27 invokevirtual #42
30 return
Method void foo(long, test.TestTarget)
0 getstatic #53
3 invokestatic #67
6 invokevirtual #73
9 getstatic #53
12 aload_0
13 invokevirtual #73
16 getstatic #53
19 ldc #75
21 invokevirtual #61
24 getstatic #53
27 ldc #77
29 invokevirtual #61
32 getstatic #53
35 ldc #79
37 invokevirtual #61
40 getstatic #53
43 lload_1
44 invokevirtual #82
47 getstatic #53
50 ldc #84
52 invokevirtual #61
55 getstatic #53
58 aload_3
59 invokevirtual #73
62 getstatic #53
65 ldc #86
67 invokevirtual #58
70 aload_0
71 lload_1
72 aload_3
73 invokespecial #70
76 getstatic #53
79 invokestatic #67
82 invokevirtual #73
85 getstatic #53
88 ldc #77
90 invokevirtual #61
93 getstatic #53
96 ldc #88 (void)">
98 invokevirtual #58
101 return
102 astore 4
104 getstatic #53
107 invokestatic #67
110 invokevirtual #73
113 getstatic #53
116 ldc #77
118 invokevirtual #61
121 getstatic #53
124 ldc #90 threw exception ">
126 invokevirtual #61
129 getstatic #53
132 aload 4
134 invokevirtual #92
137 aload 4
139 athrow
Exception table:
from to target type
0 102 102 any
Method int bar()
0 getstatic #53
3 invokestatic #67
6 invokevirtual #73
9 getstatic #53
12 aload_0
13 invokevirtual #73
16 getstatic #53
19 ldc #75
21 invokevirtual #61
24 getstatic #53
27 ldc #99
29 invokevirtual #61
32 getstatic #53
35 ldc #79
37 invokevirtual #61
40 getstatic #53
43 ldc #86
45 invokevirtual #58
48 aload_0
49 invokespecial #97
52 getstatic #53
55 invokestatic #67
58 invokevirtual #73
61 getstatic #53
64 ldc #99
66 invokevirtual #61
69 istore_1
70 getstatic #53
73 ldc #101 ">
75 invokevirtual #61
78 getstatic #53
81 iload_1
82 invokevirtual #104
85 iload_1
86 ireturn
87 astore_1
88 getstatic #53
91 invokestatic #67
94 invokevirtual #73
97 getstatic #53
100 ldc #99
102 invokevirtual #61
105 getstatic #53
108 ldc #90 threw exception ">
110 invokevirtual #61
113 getstatic #53
116 aload_1
117 invokevirtual #92
120 aload_1
121 athrow
Exception table:
from to target type
0 87 87 any
Method void main(java.lang.String[])
0 getstatic #53
3 invokestatic #67
6 invokevirtual #73
9 getstatic #53
12 ldc #111
14 invokevirtual #61
17 getstatic #53
20 ldc #79
22 invokevirtual #61
25 getstatic #53
28 aload_0
29 invokevirtual #73
32 getstatic #53
35 ldc #86
37 invokevirtual #58
40 aload_0
41 invokestatic #109
44 getstatic #53
47 invokestatic #67
50 invokevirtual #73
53 getstatic #53
56 ldc #111
58 invokevirtual #61
61 getstatic #53
64 ldc #88 (void)">
66 invokevirtual #58
69 return
70 astore_1
71 getstatic #53
74 invokestatic #67
77 invokevirtual #73
80 getstatic #53
83 ldc #111
85 invokevirtual #61
88 getstatic #53
91 ldc #90 threw exception ">
93 invokevirtual #61
96 getstatic #53
99 aload_1
100 invokevirtual #92
103 aload_1
104 athrow
Exception table:
from to target type
0 70 70 any