【问题标题】:Spring - slf4J : how to automatically log errors and exceptions?Spring - slf4J:如何自动记录错误和异常?
【发布时间】:2011-03-15 09:23:57
【问题描述】:

我们将 Spring 与 slf4j 和休眠一起使用,我正在尝试找出一种自动记录异常和错误的方法(即不启动每个类中的调试器实例),以便它可以捕获任何错误或异常抛出并在日志中获取类和方法名,

我阅读了一篇关于为此使用方面和拦截器的简短说明,您能否提供一些详细的实现方式,

问候,

【问题讨论】:

  • 这将实现您从堆栈跟踪中没有的什么?如果您计划通过方面记录和吞下异常,那对我来说听起来是个很糟糕的主意。

标签: java hibernate spring aspectj slf4j


【解决方案1】:

异常方面可能如下所示:

@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(..) 对性能的影响。我认为它应该不会太糟糕,因为无论如何例外都是例外(即罕见)。

【讨论】:

  • 您的回答非常清楚,但是如果我希望记录器使用调用类名而不是我的方面类名进行记录怎么办?
  • 你的回答越来越好了,你也提到了性能问题,我也在想,非常感谢
  • @Ali.Wassouf 如果您的问题是关于 spring-boot 中的注释配置而不是 XML,它应该像在类型中添加 @Component 和在方法中添加 @Around("execution(..)") 一样简单
  • 我想我们可以将其与常规日志记录相结合以记录方法调用
【解决方案2】:

使用纯 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 编写的,但您可以轻松适应它。

【讨论】:

    猜你喜欢
    • 2015-02-14
    • 1970-01-01
    • 1970-01-01
    • 2011-11-21
    • 2011-11-25
    • 1970-01-01
    • 1970-01-01
    • 2011-08-22
    • 1970-01-01
    相关资源
    最近更新 更多