问题
We are using Spring with slf4j and hibernate, I'm trying to figure out a way to log exceptions and errors automatically (i.e without initiating an instance of the debugger in each class), so that it may catch any error or exception thrown and also get class and method name in the log,
I read a very short note about using aspects & interceptors for this, so could you provide me with some detailed way to implement this,
Regards,
回答1:
an exception aspect could look like this:
@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;
}
}
}
spring conf:
<!-- 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>
EDIT:
if you want the logger to log on behalf of the wrapped bean, you could of course do:
LoggerFactory.getLogger(pjp.getTarget().getClass()).warn("damn!");
or if you prefere the declaring class of this method rather than the actual (potentially proxied/auto-generated type):
LoggerFactory.getLogger(pjp.getSignature().getDeclaringType()).warn("damn!");
Honestly, I can't estimate the performance implications of calling LoggerFactory.getLogger(..) every time. I'd assume that it shouldn't be too bad, as exceptions are exceptional (i.e. rare) anyway.
回答2:
With pure Aspect J (than you can use it for not spring managed beans too). This excample loggs all exceptions "returned" by a service method. But you can change the pointcut that it matches other methods too.
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);
}
}
It is written for JUnit, but you can easely adapt it.
来源:https://stackoverflow.com/questions/5309717/spring-slf4j-how-to-automatically-log-errors-and-exceptions