Q6:メソッドの引数をログに記録するには?

以下のようなアスペクトを作成します。

package logtest.aop.aspect;

import org.apache.log4j.*;

aspect MethodParams {
        
    private static final Logger logger = 
        Logger.getLogger("logtest.aop.aspect.MethodParams");
    pointcut methodParams(): execution(public * *.*(..));

    before (): methodParams() {
        trace(thisJoinPoint.getSignature(), thisJoinPoint.getArgs());
    }
    
    private static void trace(Object sig, Object[] args){
        StringBuffer buf = new StringBuffer();
        buf.append(sig);
        int length = args.length;
        if (args != null && length != 0) {
            buf.append(": args(");
            for (int i = 0; i < length - 1; i++) {
                buf.append(args[i] + ",");
            }
            buf.append(args[length - 1] + ")");
        }
        logger.debug(buf);
    }
    
}

Q3 のアスペクトを実行すると、以下のようなログが出力されます。

DEBUG - void logtest.aop.Main.main(String[]): args([Ljava.lang.String;@1bd0dd4)
DEBUG - void logtest.aop.Test1.test1(String): args(param1)
DEBUG - void logtest.aop.Test1.test2(int): args(2)
DEBUG - void logtest.aop.Test1.test3(int, int): args(2,3)
DEBUG - void logtest.aop.Test1.test4(int[]): args([I@11c8a71)
DEBUG - void logtest.aop.Test1.test5(Custom): args(logtest.aop.Custom@c53dce)
DEBUG - int logtest.aop.Test1.test6()
DEBUG - String logtest.aop.Test1.test7()
DEBUG - String[] logtest.aop.Test1.test8()
DEBUG - String logtest.aop.Test1.test9()

元のソースにまったく手を入れることなくすべての public メソッドの引数がシグネチャも含めて表示されました。ログ挿入箇所が少なければ、ソースにコードを直接書いた方が早いのですが、大量にログを埋め込まなければならない場合にとても便利だと思います。

ただ、toString() を実装していないクラスが引数の場合は、オブジェクトの hashcode がそのまま表示されてしまいます。その場合は上の trace() メソッド内で引数の型をチェックすれば、型に応じた対応ができます(もちろん型毎に記述することになるため面倒ですが)。あらかじめデバッグを想定して、toString() を実装しておくことや、型チェックで対応することが必要になるかもしれません。


トップページへ戻る