4

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 ?

4
  • what do you mean when you say monitor the values Commented Jun 20, 2012 at 6: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? Commented Jun 20, 2012 at 6: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. Commented Jun 20, 2012 at 7: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. Commented Jun 20, 2012 at 7:26

3 Answers 3

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]
Sign up to request clarification or add additional context in comments.

2 Comments

ProxyFactory and Translator links are dead.
@macawm, fixed links
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?

Comments

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.