slf4j と休止状態で Spring を使用しています。例外とエラーを自動的にログに記録する方法を見つけようとしています (つまり、各クラスでデバッガーのインスタンスを開始せずに)。ログでクラスとメソッド名を取得し、
これにアスペクトとインターセプターを使用することに関する非常に短いメモを読んだので、これを実装する詳細な方法を教えてください。
よろしく、
例外の側面は次のようになります。
@Aspect
public class ExceptionAspect {
private static final Logger log = LoggerFactory.getLogger(ExceptionAspect.class);
public Object handle(ProceedingJoinPoint pjp) throws Throwable {
try {
return pjp.proceed();
} catch (Throwable t) {
// so something with t: log, wrap, return default, ...
log.warn("invocation of " + pjp.getSignature().toLongString() + " failed", t);
// I hate logging and re-raising, but let's do it for the sake of this example
throw t;
}
}
}
春の設定:
<!-- log exceptions for any method call to any object in a package called 'svc' -->
<bean class="org.example.aspects.ExceptionAspect" name="exceptionAspect" />
<aop:config>
<aop:aspect ref="exceptionAspect">
<aop:around method="handle" pointcut="execution(* org.example..svc..*.*(..))" />
</aop:aspect>
</aop:config>
編集:
ラップされた Bean に代わってロガーにログを記録させたい場合は、もちろん次のようにすることができます。
LoggerFactory.getLogger(pjp.getTarget().getClass()).warn("damn!");
または、実際の (潜在的にプロキシされた/自動生成された型) よりも、このメソッドの宣言クラスを好む場合:
LoggerFactory.getLogger(pjp.getSignature().getDeclaringType()).warn("damn!");
正直なところ、毎回 LoggerFactory.getLogger(..) を呼び出すことのパフォーマンスへの影響を見積もることはできません。いずれにせよ、例外は例外的 (すなわちまれ) であるため、それほど悪くはないと思います。
純粋な Aspect J を使用します (Spring で管理されていない Bean にも使用できます)。この例では、サービス メソッドによって「返された」すべての例外がログに記録されます。ただし、他の方法と一致するようにポイントカットを変更することもできます。
package test.infrastructure.exception;
import java.util.Arrays;
import org.apache.log4j.*;
import org.aspectj.lang.Signature;
import org.springframework.stereotype.Service;
/** Exception logger*/
public aspect AspectJExceptionLoggerAspect {
/** The name of the used logger. */
public final static String LOGGER_NAME = "test.infrastructure.exception.EXCEPTION_LOGGER";
/** Logger used to log messages. */
private static final Logger LOGGER = Logger.getLogger(LOGGER_NAME);
AspectJExceptionLoggerAspect() {
}
/**
* Pointcut for all service methods.
*
* Service methods are determined by two constraints:
* <ul>
* <li>they are public</li>
* <li>the are located in a class of name *SericeImpl within (implement an interface)
* {@link test.service} package</li>
* <li>they are located within a class with an {@link Service} annotation</li>
* </ul>
*/
pointcut serviceFunction()
: (execution(public * test.Service.*.*ServiceImpl.*(..)))
&& (within(@Service *));
/** Log exceptions thrown from service functions. */
after() throwing(Throwable ex) : serviceFunction() {
Signature sig = thisJoinPointStaticPart.getSignature();
Object[] args = thisJoinPoint.getArgs();
String location = sig.getDeclaringTypeName() + '.' + sig.getName() + ", args=" + Arrays.toString(args);
LOGGER.warn("exception within " + location, ex);
}
}
JUnit用に書かれていますが、簡単に適応させることができます。