AopLog是基于Spring Aop 和ThreadLocal实现的一个专门对申请办法内容日志的拦挡与解决的日志工具包。

场景 :

  1. 应用Spring Aop拦挡参数日志目前大部分做法都基本上大同小异,不想日后每个我的项目工程都写一份这样的Aop拦挡解决日志的代码,甚至代码侵入。
  2. 我想晓得一些绝对重要的申请办法的申请参数,响应参数,申请头,以及外部耗时,办法是胜利还是失败等等信息。产生谬误时我也不晓得执行到哪一步产生了异样,是不是某个参数导致出的逻辑问题。
  3. 一般的log.info或warn信息没有所属申请的高低关系,并不不便查看和剖析。
  4. 正式环境中,我并不想打印太多无意义的info日志(有些只是为了排查问题打印的日志,程序失常运行时其实毫无意义),只心愿在产生异样时记录日志或者只心愿每次申请只记录一条次要害的申请信息。
  5. 日志的收集,我心愿将这些申请的日志记录下来,记录的实现形式我本人决定,比方失常的日志打印,常见的日志写入数据库,日志写入到文件,日志入队列等等。
  6. 整个日志的记录齐全不烦扰失常申请办法的流程,日志的收集解决异步化,齐全不影响失常申请办法的性能与响应。
  7. 只须要通过@AopLog注解决定是否记录。

疾速开始

我的项目通过maven的pom.xml引入

<dependency>    <groupId>com.github.ealenxie</groupId>    <artifactId>aop-log</artifactId>    <version>2.1</version></dependency>

或者通过gradle引入

compile group: 'com.github.ealenxie', name: 'aop-log', version: '2.1'

@AopLog注解应用,进行日志记录

间接在类(作用类的所有办法)或类办法(作用于办法)上加上注解@AopLog,进行日志记录

例如 :

import com.github.AopLog;import name.ealen.infra.base.resp.RespBody;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;/** * @author EalenXie create on 2020/6/22 14:28 */@AopLog(type = "测试",stackTraceOnErr = true)@RestControllerpublic class AppController {    @GetMapping("/app/sayHello")    public RespBody<String> sayHello() {        return RespBody.ok("hello EalenXie");    }}

自定义全局的日志收集器实现收集 LogCollector

例如只是简略打印,或写入到库等等。

import com.fasterxml.jackson.core.JsonProcessingException;import com.fasterxml.jackson.databind.ObjectMapper;import com.github.LogData;import com.github.collector.LogCollector;import lombok.extern.slf4j.Slf4j;import org.springframework.stereotype.Component;/** * @author EalenXie create on 2020/9/15 13:46 * 此为样例参考 * 配置一个简略的日志收集器 这里只是做了一个log.info打印一下,能够在这里写入到数据库中或者写入 */@Slf4j@Componentpublic class AopLogCollector implements LogCollector {    private ObjectMapper objectMapper = new ObjectMapper();    @Override    public void collect(LogData logData) {        try {            log.info(objectMapper.writeValueAsString(logData));        } catch (JsonProcessingException e) {            e.printStackTrace();        }    }}

配置@Component的全局日志收集器只能配置一个。

接口调用 /say/hello 测试即可看看到控制台打印出后果 :

2020-09-16 16:01:04.782  INFO 2012 --- [AsyncExecutor-2] name.ealen.infra.advice.AopLogCollector  : {"appName":"app-template","host":"127.0.0.1","port":8080,"clientIp":"192.168.110.1","reqUrl":"http://localhost:8080/app/sayHello","httpMethod":"GET","headers":{"User-Agent":"Apache-HttpClient/4.5.10 (Java/11.0.5)"},"type":"测试","content":"","method":"name.ealen.api.facade.AppController#sayHello","args":null,"respBody":{"code":"200","desc":"OK","message":"申请胜利","dateTime":"2020-09-16 16:01:04","body":"hello EalenXie"},"logDate":1600243264780,"costTime":1,"threadName":"http-nio-8080-exec-3","threadId":33,"success":true}

记录的日志对象LogData属性阐明

LogData 记录的内容

| 字段 | 类型 | 正文 |
| :------- | :------------ | :----- |
| appName | String | 利用名称|
| host | String | 主机 |
| port | int | 端口号 |
| clientIp | String | 申请客户端的Ip |
| reqUrl | String | 申请地址 |
| headers | Object | 申请头部信息(可抉择记录) 默认记录user-agent,content-type |
| type | String | 操作类型,默认值undefined |
| content | String | 办法步骤内容,默认是空,可应用LogData.step进行内容步骤记录 |
| method | String | 申请的本地java办法 |
| args | Object | 办法申请参数 |
| respBody | Object | 办法响应参数 |
| costTime | long | 整个办法耗时|
| logDate | Date | Log产生工夫,LogData对象初始化的工夫 |
| threadName | String | 线程名称 |
| threadId | long | 线程Id |
| success | boolean | 执行状态,胜利(true)/异样(false) |

AopLog 注解选项阐明

选项类型阐明默认
logOnErrboolean仅当产生异样时才记录收集false
typeString操作类型默认值"undefined"
headersString[]记录的header信息 ,抉择要记录哪些header信息默认"User-Agent","content-type"
argsboolean是否记录申请参数true
respBodyboolean是否记录响应参数true
stackTraceOnErrboolean当指标办法产生异样时,是否追加异样堆栈信息到LogData的content中false
asyncModeboolean异步形式收集true
collectorClass<? extends LogCollector>指定日志收集器默认不调整收集器,应用全局的日志收集器

LogData的step办法。

记录步骤。(如果某些重要步骤心愿被记录下来)
例如 :

import com.github.AopLog;import com.github.LogData;import name.ealen.infra.base.resp.RespBody;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;/** * @author EalenXie create on 2020/6/22 14:28 */@AopLog(type = "测试",stackTraceOnErr = true)@RestControllerpublic class AppController {    @GetMapping("/app/sayHello")    public RespBody<String> sayHello() {        LogData.step("1. 第一步执行实现");        //......        LogData.step("2. 第二步执行实现");        //.....        LogData.step("3. service的办法执行实现");        //.....        return RespBody.ok("hello EalenXie");    }}

留神: 此办法如果不在被@AopLog注解的办法的整体调用链路中应用,则以后线程中的ThreadLocal中的LogData不会开释,须要手动调用LogData.removeCurrent();

此时再次接口调用 /say/hello 测试即可看看到控制台打印出后果,重点察看content字段 :

2020-09-16 17:26:20.285  INFO 3284 --- [AsyncExecutor-2] name.ealen.infra.advice.AopLogCollector  : {"appName":"app-template","host":"127.0.0.1","port":8080,"clientIp":"192.168.110.1","reqUrl":"http://localhost:8080/app/sayHello","httpMethod":"GET","headers":{"User-Agent":"Apache-HttpClient/4.5.10 (Java/11.0.5)"},"type":"测试","content":"1. 第一步执行实现\n2. 第二步执行实现\n3. service的办法执行实现\n","method":"name.ealen.api.facade.AppController#sayHello","args":null,"respBody":{"code":"200","desc":"OK","message":"申请胜利","dateTime":"2020-09-16 17:26:20","body":"hello EalenXie"},"logDate":1600248380283,"costTime":1,"threadName":"http-nio-8080-exec-2","threadId":32,"success":true}

对于

开源Github地址 : [https://github.com/EalenXie/a...
](https://github.com/EalenXie/a...

感激各位提出意见和反对。