【问题标题】:Spring Boot Logging HTTP request and response and write logs to an SQL databaseSpring Boot Logging HTTP 请求和响应并将日志写入 SQL 数据库
【发布时间】:2020-05-08 11:21:26
【问题描述】:

我为公共 SOAP web service 开发了简单的 REST JSON 包装器。 Web 服务是一个简单的计算器,有 4 种方法:加法、除法、乘法和减法。

REST 包装器工作正常。我的下一个目标是记录 REST 包装器和 SOAP Web 服务之间的每个请求和响应,然后将日志条目写入 SQL 数据库。

我在完成任务时遇到了两个主要问题。

  1. 我不知道如何拦截包装器和Web服务之间的请求和响应以生成日志。

  2. 出于测试目的,尝试使用 DBAppender 生成日志条目并将其写入 SQL 数据库,但 DBAppender 生成了 3 个表。但我想将日志写入自定义表。

【问题讨论】:

标签: java spring spring-boot logging


【解决方案1】:

记录请求和响应的一种流行方法是使用spring-aop。但是,建议不要对spring-aop 执行性能密集型操作。这是在您的用例中使用 spring-aop 的示例。但是,与其每次都查询数据库以获取请求或响应日志,不如找到一种方法来批量处理日志以避免数据库访问开销。

添加 spring-boot-starter-aop 依赖项

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

为 spring 应用启用AspectJAutoproxy

@SpringBootApplication( )
@EnableAspectJAutoProxy( proxyTargetClass = true )
public class Application
{
    public static void main( String[] args )
    {
        SpringApplication.run( Application.class, args );
    }
}

添加方面类

@Aspect
@Component
public class CalculatorAspect
{
    private Logger LOGGER = Logger.getLogger( getClass().getName() );

    @Around( "execution(* com.example.Calculator.add(..))" ) // Add method
    public Object logInfoAboutAddOperation( ProceedingJoinPoint joinPoint ) throws Throwable
    {
        // Log here for request using joinPoint variable information
        // and add the necessary entries to DB
        Object proceed = joinPoint.proceed(); // This instructs the target to proceed with method execution which is the add() method
        // Log here for response and add the necessary info to DB

        return proceed; // This is mandatory and this contains the result of add() method. You can even change the actual result here
    }
}

有多种方法可以满足您的要求。有关spring-aop 的更多信息,请查看此link。通过使用相关的Advice,您也可以在Controller 层记录请求和响应。

【讨论】:

  • 感谢@Klaus 的解释。我开发了用于记录 http 响应和请求的拦截器。但是我也应该将这些日志保存到数据库中,并且从拦截器中执行它不是一个好主意。我认为您的建议最适合我的任务。感谢您的时间和回复。
【解决方案2】:

除了 Klaus 的回答,我想补充一点,您可以使用自定义注释到达切入点(您要拦截的方法)。

所以你可以这样定义你的注释:

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface LogCallToDB {
}

然后你可以围绕这个注解定义切面:

@Aspect
@Component
@Slf4j
public class LoggingToDBAspect {

@Around("@annotation(com.myltdcompany.myproject.infra.utils.LogCallToDB)")
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {

    Object proceed = joinPoint.proceed();

    final Signature signature = joinPoint.getSignature();
    Object[] args = joinPoint.getArgs();

    // write to DB using some wrapper like CallLoggingRepository

    return proceed;
}

然后您可以简单地在您想要将条目记录到 DB 的任何方法之上使用注释 @LogCallToDB。示例:

@LogCallToDB
public doubl add(double a, double b) {
  return a+b;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-18
    • 1970-01-01
    • 2014-06-13
    • 2022-01-25
    • 2017-08-07
    • 2022-06-21
    • 1970-01-01
    相关资源
    最近更新 更多