4

実行時にメソッドに渡されたパラメーターをログに記録するにはどうすればよいですか? これを監視するために発生させることができるJavaライブラリまたは例外はありますか?

4

3 に答える 3

5

javassistProxyFactoryまたはTranslatorを使用して、実行時に引数を出力するように変更できます。


使用Translator(新しい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)
        }
    }
}

ClassLoader*クラスをインストルメントできるようにデフォルトを変更する必要があることに注意してください。そのため、を呼び出す前にmain、次のコードを挿入する必要があります。

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");
    }
}

出力:

----- 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

使用する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);
    }
}

出力:

Method method called with [Hello, 4711]
于 2012-06-20T07:06:52.480 に答える
3

AOP を使用してみてください。多かれ少なかれあなたが望むことを行う例を次に示します: How to use AOP with AspectJ for logging?

于 2012-06-20T07:15:18.993 に答える
1

登録できると思いますのでMBean、JMXで確認できるのはあなただけです。

リンク: http ://docs.oracle.com/cd/E19159-01/819-7758/gcitp/index.html

于 2012-06-20T06:56:57.957 に答える