Spring Boot2集成AOPLog来记录接口访问日志

 更新时间:2019年06月28日 09:23:08   作者:空山新雨  
这篇文章主要介绍了Spring Boot2集成AOPLog来记录接口访问日志,日志是一个Web项目中必不可少的部分,借助它我们可以做许多事情,比如问题排查、访问统计、监控告警等,需要的朋友可以参考下

前言

日志是一个Web项目中必不可少的部分,借助它我们可以做许多事情,比如问题排查、访问统计、监控告警等。一般通过引入slf4j的一些实现框架来做日志功能,如log4j,logback,log4j2,其性能也是依次增强。在springboot中,默认使用的框架是logback。

我们经常需要在方法开头或结尾加日志记录传入参数或返回结果,以此来复现当时的请求情况。但是手动添加日志,不仅繁琐重复,也影响代码的美观简洁。本文引入一个基于AOP实现的日志框架,并通过spring-boot-starter的方式完成集成。

1. aop-logging项目

项目地址

该项目基于 , 在其基础上添加了ReqId来串联某次客户端请求(参考com.github.nickvl.xspring.core.log.aop.ReqIdFilter), 添加了方法执行时长(参考com.github.nickvl.xspring.core.log.aop.AOPLogger.logTheMethod方法中elapsedTime)。

该项目提供了基于注解的AOP日志功能。根据不同的日志级别,提供的注解有LogTrace,LogDebug,LogInfo,LogWarn,LogError,LogFatal,LogException,可修饰于类(等同于该类内所有方法上添加)与方法上,前面六个分别表示在不同日志级别下记录方法被调用的日志,LogException表示在方法抛出异常时,记录相应日志。

这些注解都提供了一个LogPoint枚举类型的属性value,取值{IN,OUT,BOTH},分别表示在方法调用入口、方法调用返回前,以及包含两者的位置打印对应日志,默认为BOTH。

2. 集成

可可以通过基于xml或基于java配置的方式来集成AOP日志功能,我这里基于java配置(基于xml的方式参考源码README文件)并且通过spring-boot-starter的形式进行封装(源码地址),避免每个项目都需要配置。自动配置类如下

@Configuration
@ConditionalOnClass(AOPLogger.class)
@ConditionalOnMissingBean(AOPLogger.class)
public class AopLoggerAutoConfiguration {
  private static final boolean SKIP_NULL_FIELDS = true;
  private static final Set<String> EXCLUDE_SECURE_FIELD_NAMES = Collections.emptySet();
  @Bean
  public AOPLogger aopLogger() {
    AOPLogger aopLogger = new AOPLogger();
    aopLogger.setLogAdapter(new UniversalLogAdapter(SKIP_NULL_FIELDS, EXCLUDE_SECURE_FIELD_NAMES));
    return aopLogger;
  }
  /**
  * 注册一个过滤器,用来生成一个reqId,标记一次请求,从而将本次请求所产生的日志串联起来
  * @param
  * @return
  */
  @Bean
  public FilterRegistrationBean reqIdFilter() {
    ReqIdFilter reqIdFilter = new ReqIdFilter();
    FilterRegistrationBean registrationBean = new FilterRegistrationBean();
    registrationBean.setFilter(reqIdFilter);
    List<String> urlPatterns = Collections.singletonList("/*");
    registrationBean.setUrlPatterns(urlPatterns);
    registrationBean.setOrder(100);
    return registrationBean;
  }
}

将基础框架base-spring-boot通过mvn clean install进行本地安装后,即可在项目中通过依赖进行引入(基础框架中已在spring-boot-parent中引入,直接继承亦可),如

<dependency>
<groupId>cn.jboost.springboot</groupId>
<artifactId>aoplog-spring-boot-starter</artifactId>
<version>1.2-SNAPSHOT</version>
</dependency>

3. 使用

引入依赖之后,我们再定义一个日志配置文件logback-spring.xml,为了后面方便地将日志导入ELK做集中的日志分析管理,该配置文件中将日志以json格式输出,并根据日志级别分别写入debug.log,info.log,warn.log,error.log以及interface.log(专用于接口访问日志),配置示例如下(完整配置

<appender name="interfaceLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
 <file>${logPath}/elk/interface.log</file>
 <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
  <providers>
  <pattern>
   <pattern>
   {
   "project": "${projectName}",
   "timestamp": "%date{\"yyyy-MM-dd'T'HH:mm:ss,SSSZ\"}",
   "log_level": "%level",
   "thread": "%thread",
   "class_name": "%X{callingClass}",
   "class_method":"%X{callingMethod}",
   "line_number": null,
   "message": "%message",
   "stack_trace": "%exception{5}",
   "req_id": "%X{reqId}",
   "elapsed_time": "#asLong{%X{elapsedTime}}"
   }
   </pattern>
  </pattern>
  </providers>
 </encoder>
 <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
  <level>INFO</level>
 </filter>
 <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
  <fileNamePattern>${logPath}/bak/interface.%d{yyyy-MM-dd}.log</fileNamePattern>
  <maxHistory>30</maxHistory>
  <totalSizeCap>1GB</totalSizeCap>
 </rollingPolicy>
 </appender>

为了将该日志配置文件可以不经修改地达到复用,将一些参数配置外置了,故需在配置文件applicaiton.yml中配置如下参数

logger:
path: D:\logs #默认当前项目路径下的logs目录
level: info # 默认info
apiPackage: cn.jboost.springboot.aoplog.controller #必须配置, api接口类所在包
rootPackage: cn.jboost.springboot #必须配置,项目根包,记录该包内各类通过slf4j输出的日志

最后,直接在需要记录访问日志的接口类上加注解@LogInfo就行了,如

@RestController
@RequestMapping("test")
@LogInfo
public class AoplogTestController {
  @GetMapping
  public String test(@RequestParam String user){
    return "Hi " + user;
  }
}

注意:在pom.xml中默认添加的spring-boot-maven-plugin下需要添加repackage的goal才能自动生成日志目录与日志文件,如下所示

<build>
 <plugins>
 <plugin>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-maven-plugin</artifactId>
  <executions>
  <execution>
   <goals>
   <goal>repackage</goal>
   </goals>
  </execution>
  </executions>
 </plugin>
 </plugins>
</build>

启动程序,调用@LogInfo标注的接口类下的API时,可以看到控制台有打印接口访问日志,如执行demo程序(源码),调用  http://localhost:8080/test?user=jboost 时,控制台打印日志如下

[2019-06-27 14:29:59] [INFO ] [http-nio-8080-exec-1] [cn.jboost.springboot.aoplog.controller.AoplogTestController:184] --calling: test(user=jboost)
[2019-06-27 14:29:59] [INFO ] [http-nio-8080-exec-1] [cn.jboost.springboot.aoplog.controller.AoplogTestController:189] --returning: test(1 arguments):Hi jboost

日志文件interface.log中打印日志如下,(其中req_id在本次请求的所有日志都相同,这样就可以将一次请求的所有日志串联起来,便于分析与定位问题;elapsed_time标明了方法执行时长,可用于接口性能监测)

{"project":"aoplog-test","timestamp":"2019-06-27T14:29:59,030+0800","log_level":"INFO","thread":"http-nio-8080-exec-1","class_name":"cn.jboost.springboot.aoplog.controller.AoplogTestController","class_method":"test","line_number":null,"message":"calling: test(user=jboost)","stack_trace":"","req_id":"5d146267aa147904bc014e71","elapsed_time":null}
{"project":"aoplog-test","timestamp":"2019-06-27T14:29:59,036+0800","log_level":"INFO","thread":"http-nio-8080-exec-1","class_name":"cn.jboost.springboot.aoplog.controller.AoplogTestController","class_method":"test","line_number":null,"message":"returning: test(1 arguments):Hi jboost","stack_trace":"","req_id":"5d146267aa147904bc014e71","elapsed_time":2}

4. 总结

Web项目中经常需要通过查看接口请求及返回参数来定位问题,手动编写代码打印显得繁琐而重复。使用aop-logging通过简单的注解即可实现接口日志自动打印。本文介绍的方案与日志配置模板可直接用于实际项目开发。当然,注解不仅可用于Controller层,也可以用于Service等其它层,但一般Controller层加上即可,避免日志打印过多。

本文示例项目源码地址

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • 详解Spring注入集合(数组、List、Map、Set)类型属性

    详解Spring注入集合(数组、List、Map、Set)类型属性

    这篇文章主要介绍了详解Spring注入集合(数组、List、Map、Set)类型属性,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • Java线程安全中的单例模式

    Java线程安全中的单例模式

    这篇文章主要介绍了Java线程安全中的单例模式,需要的朋友可以参考下
    2015-02-02
  • Java 8新的时间日期库的20个使用示例

    Java 8新的时间日期库的20个使用示例

    这篇文章主要介绍了Java 8新的时间日期库的20个使用示例,需要的朋友可以参考下
    2015-04-04
  • Java使用多线程异步执行批量更新操作方法

    Java使用多线程异步执行批量更新操作方法

    这篇文章主要介绍了Java使用多线程异步执行批量更新操作,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-01-01
  • Dwr3.0纯注解(纯Java Code配置)配置与应用浅析二之前端调用后端

    Dwr3.0纯注解(纯Java Code配置)配置与应用浅析二之前端调用后端

    我们讲到了后端纯Java Code的Dwr3配置,完全去掉了dwr.xml配置文件,但是对于使用注解的类却没有使用包扫描,而是在Servlet初始化参数的classes里面加入了我们的Service组件的声明暴露,对于这个问题需要后面我们再细细研究下这篇文章,主要分析介绍前端怎么直接调用后端
    2016-04-04
  • Java定义画板类的方法

    Java定义画板类的方法

    这篇文章主要为大家详细介绍了Java定义画板类的方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06
  • SpringBoot @Profile的使用

    SpringBoot @Profile的使用

    本文主要介绍了SpringBoot @Profile的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-06-06
  • springboot的application.yml配置port不生效的解决方案

    springboot的application.yml配置port不生效的解决方案

    这篇文章主要介绍了springboot的application.yml配置port不生效的解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-07-07
  • MyBatis与Spring中的SqlSession详解

    MyBatis与Spring中的SqlSession详解

    在MyBatis中,你可以使用SqlSessionFactory来创建SqlSession,使用MyBatis-Spring之后,你不再需要直接使用SqlSessionFactory了,接下来通过示例代码讲解MyBatis与Spring中的SqlSession,需要的朋友可以参考下
    2024-05-05
  • Java BigDecimal类用法详解

    Java BigDecimal类用法详解

    BigDecimal 由任意精度的整数非标度值 和32 位的整数标度 (scale) 组成。如果为零或正数,则标度是小数点后的位数。如果为负数,则将该数的非标度值乘以 10 的负scale 次幂。
    2016-06-06

最新评论