【问题标题】:Adding logging to specific existing spring boot endpoints将日志记录添加到特定的现有 Spring Boot 端点
【发布时间】:2020-04-26 03:11:47
【问题描述】:

我们有几个带有数百个端点的 Spring Boot Rest API。

是否有任何工具或库可用于监控特定端点,将请求、响应和时间记录到自定义数据库?

有什么特别的可以附加到正在运行的服务上吗?

我听说过 Actuator、AOP、AspectJ,但我不确定这是我们想要的吗?

谢谢

【问题讨论】:

  • 这是个好问题
  • 如果你不确定你想要什么,那我们怎么知道呢?
  • 只使用网络过滤器

标签: rest spring-boot logging endpoint


【解决方案1】:

您可以为给定包的每个方法创建一个记录进入/退出日志和时间执行的方面。

要计算执行时间,可以使用springStopwatch。但是,您必须小心性能影响。 (生产环境不推荐这个类)


    import org.springframework.util.StopWatch;

    @Aspect
    @Component
    public class LoggingAspect {

        private final Logger log = LoggerFactory.getLogger(this.getClass());

        /**
         * Pointcut that matches all services and Web REST endpoints.
         */
        @Pointcut("within(@org.springframework.stereotype.Service *)" +
            " || within(@org.springframework.web.bind.annotation.RestController *)")
        public void springBeanPointcut() {
            // Method is empty as this is just a Pointcut, the implementations are in the advices.
        }

        /**
         * Pointcut that matches all Spring beans in the application's endpoint packages.
         */
        @Pointcut("within(your.pack.num1..*)" +
            " || within(your.pack.num2..*)" +
            " || within(your.pack.num3..*)")
        public void applicationPackagePointcut() {
            // Method is empty as this is just a Pointcut, the implementations are in the advices.
        }

        /**
         * Advice that logs methods throwing exceptions.
         *
         * @param joinPoint join point for advice
         * @param e exception
         */
        @AfterThrowing(pointcut = "applicationPackagePointcut() && springBeanPointcut()", throwing = "e")
        public void logAfterThrowing(JoinPoint joinPoint, Throwable e) {
            log.error("Exception in {}.{}() with cause = {}", joinPoint.getSignature().getDeclaringTypeName(),
                joinPoint.getSignature().getName(), e.getCause() != null ? e.getCause() : "NULL");
        }

        /**
         * Advice that logs when a method is entered and exited.
         *
         * @param joinPoint join point for advice
         * @return result
         * @throws Throwable throws IllegalArgumentException
         */
        @Around("applicationPackagePointcut() && springBeanPointcut()")
        public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
          StopWatch stopWatch;
            if (log.isDebugEnabled()) {
                stopWatch= new StopWatch();
                stopWatch.start();
                log.debug("Enter: {}.{}() with argument[s] = {}", joinPoint.getSignature().getDeclaringTypeName(),
                    joinPoint.getSignature().getName(), Arrays.toString(joinPoint.getArgs()));
            }
            try {
                try{
                Object result = joinPoint.proceed();
                }finally{
                stopWatch.stop();
                }
                if (log.isDebugEnabled()) {
                    log.debug("Exit: {}.{}() with result = {} and execution time {}", joinPoint.getSignature().getDeclaringTypeName(),
                        joinPoint.getSignature().getName(), result,stopWatch.getTotalTimeMillis());
                }
                return result;
            } catch (IllegalArgumentException e) {
                log.error("Illegal argument: {} in {}.{}()", Arrays.toString(joinPoint.getArgs()),
                    joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
                throw e;
            }
        }
    }

【讨论】:

  • 这是针对现有端点的单独解决方案吗?还是必须修改/注释源代码才能正常工作?
  • 此解决方案使用面向方面的编程。您无需更改现有代码。您只需将要拦截的包添加到 Aspect Pointcut 即可。
猜你喜欢
  • 2020-07-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-26
  • 2017-11-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-03
相关资源
最近更新 更多