How can I log the parameters passed to a method at runtime ? Is there any Java library for this or any any exception that can be raised to monitor it ?
Asked
Active
Viewed 7,463 times
4
-
what do you mean when you say `monitor the values` – Kshitij Jun 20 '12 at 06:47
-
Im not quite sure what you're asking here. Do you want to check for valid input to a method? and how bad input can be handled? – John Snow Jun 20 '12 at 06:49
-
@Kshitij I mean i want to store the values in a file as soon as they are passed to a method of a running program. – Sanyam Goel Jun 20 '12 at 07:23
-
@JimmyGustafsson suppose we have a method add(int a , int b ) in a class Sum.java. Now for example this is executed. At run time user or some other method feeds this method inputs. I want to log these input values. – Sanyam Goel Jun 20 '12 at 07:26
3 Answers
5
You can use javassist's ProxyFactory
or Translator
to change to print the arguments at runtime:
Using Translator
(with a new ClassLoader
):
public static class PrintArgumentsTranslator implements Translator {
public void start(ClassPool pool) {}
@Override
public void onLoad(ClassPool pool, String cname)
throws NotFoundException, CannotCompileException {
CtClass c = pool.get(cname);
for (CtMethod m : c.getDeclaredMethods())
insertLogStatement(c, m);
for (CtConstructor m : c.getConstructors())
insertLogStatement(c, m);
}
private void insertLogStatement(CtClass c, CtBehavior m) {
try {
List<String> args = new LinkedList<String>();
for (int i = 0; i < m.getParameterTypes().length; i++)
args.add("$" + (i + 1));
String toPrint =
"\"----- calling: "+c.getName() +"." + m.getName()
+ args.toString()
.replace("[", "(\" + ")
.replace(",", " + \", \" + ")
.replace("]", "+\")\"");
m.insertBefore("System.out.println("+toPrint+");");
} catch (Exception e) {
// ignore any exception (we cannot insert log statement)
}
}
}
*Note that you need to change the default ClassLoader
so that you can instrument the classes, so before calling your main
you need some inserted the following code:
public static void main(String[] args) throws Throwable {
ClassPool cp = ClassPool.getDefault();
Loader cl = new Loader(cp);
cl.addTranslator(cp, new PrintArgumentsTranslator());
cl.run("test.Test$MyApp", args); // or whatever class you want to start with
}
public class MyApp {
public MyApp() {
System.out.println("Inside: MyApp constructor");
}
public static void main(String[] args) {
System.out.println("Inside: main method");
new MyApp().method("Hello World!", 4711);
}
public void method(String string, int i) {
System.out.println("Inside: MyApp method");
}
}
Outputs:
----- calling: test.Test$MyApp.main([Ljava.lang.String;@145e044)
Inside: main method
----- calling: test.Test$MyApp.Test$MyApp()
Inside: MyApp constructor
----- calling: test.Test$MyApp.method(Hello World!, 4711)
Inside: MyApp method
Using ProxyFactory
public class Test {
public String method(String string, int integer) {
return String.format("%s %d", string, integer);
}
public static void main(String[] args) throws Exception {
ProxyFactory f = new ProxyFactory();
f.setSuperclass(Test.class);
Class<?> c = f.createClass();
MethodHandler mi = new MethodHandler() {
public Object invoke(
Object self, Method m, Method proceed, Object[] args)
throws Throwable {
System.out.printf("Method %s called with %s%n",
m.getName(), Arrays.toString(args));
// call the original method
return proceed.invoke(self, args);
}
};
Test foo = (Test) c.newInstance();
((Proxy) foo).setHandler(mi);
foo.method("Hello", 4711);
}
}
Output:
Method method called with [Hello, 4711]

dacwe
- 43,066
- 12
- 116
- 140
3
You should try to use AOP. Here is an example that does more or less what you want: How to use AOP with AspectJ for logging?
1
I think you can register your MBean
then only you will be able to check using JMX.
Link: http://docs.oracle.com/cd/E19159-01/819-7758/gcitp/index.html

amicngh
- 7,831
- 3
- 35
- 54