aop对请求后端的参数修改_基于AOP和ThreadLocal实现日志记录

本文介绍了如何利用AOP和ThreadLocal实现API请求的日志记录。通过在Controller方法或类上添加注解,系统能够捕获并记录请求的URL、方法、参数、响应、客户端IP等信息,并提供JSON、XML和form格式的数据记录。日志收集可以自定义,例如写入文件或数据库。示例代码展示了如何使用和配置这一系统。
摘要由CSDN通过智能技术生成

75004ceca3cc59ea28500f2668732ae9.png

作者 | EalenXie  

来源 | cnblogs.com/ealenxie/p/13208498.html

基于AOP和ThreadLocal实现的一个日志记录的例子

主要功能实现 : 在API每次被请求时,可以在整个方法调用链路中记录一条唯一的API请求日志,可以记录请求中绝大部分关键内容。并且可以自定义实现对日志收集(直接标准输出,或写入到文件或数据库)。

比如传参,响应,请求url,请求方法,clientIp,耗时,请求成功或异常,请求头等等。

实现的核心为AOP以及ThreadLocal。
  • AOP 会切所有被@Log4a注解的方法,会记录一个线程中唯一一个Log4对象,读取AOP中的方法信息(入参,方法等等)

  • 抓取请求的内容和HttpServletRequest中的内容,解析入参。

  • 日志收集(自定义实现,建议该过程异步)

  • 记录无论目标方法成功或失败,在执行完成后都将对ThreadLocal中的资源进行释放。

Log4 记录的内容
字段类型注释是否默认记录
clientIpString请求客户端的Ip
reqUrlString请求地址
headersObject请求头部信息(可选择记录)是,默认记录user-agent,content-type
typeString操作类型是,默认值undefined
contentStringBuilder步骤内容信息否,方法内容,可使用Log4.step进行内容步骤记录
Log4a 注解选项说明
字段类型注释默认
typeString操作类型默认值"undefined"
methodboolean是否记录请求的本地java方法true
costTimeboolean是否记录整个方法耗时true
headersString[]记录的header信息默认"User-Agent","content-type"
argsboolean是否记录请求参数true
respBodyboolean是否记录响应参数true
stackTraceboolean当目标方法发生异常时,是否追加异常堆栈信息到contentfalse
costTimeboolean是否记录整个方法耗时true
collectorClass extends LogCollector>指定日志收集器默认空的收集器不指定
例子使用说明
@Log4a注解使用

直接在Controller 方法或类上加上注解@Log4a,可以对该Controller中所有方法进行日志记录与收集

例如 :

@Log4a(type = "测试API", stackTrace = true)
@RestController
public class DemoController {
    @Resource
    private DemoService demoService;
    /**
     * JSON数据测试
     */
    @PostMapping("/sayHello")
    public ResponseEntity> sayHello(@RequestBody Map<String, Object> request) {
        demoService.sayHello(request);
        return ResponseEntity.ok(request);
    }
    /**
     * RequestParam 参数测试
     */
    @PostMapping("/params")
    public ResponseEntity> params(@RequestParam Integer a) {
        return ResponseEntity.ok(a);
    }
    /**
     * 无参测试
     */
    @GetMapping("/noArgs")
    public ResponseEntity> noArgs() {
        return ResponseEntity.ok().build();
    }
    /**
     * XML 格式数据测试
     */
    @PostMapping(value = "/callXml", consumes = {MediaType.APPLICATION_XML_VALUE})
    public XmlDataDTO callXml(@RequestBody XmlDataDTO dataDTO) {
        return dataDTO;
    }
    /**
     * 特殊对象测试
     */
    @GetMapping("/callHttpServletRequest")
    public ResponseEntity> callHttpServletRequest(HttpServletRequest request) {
        return ResponseEntity.ok().build();
    }
}
Log4.step 记录详细步骤内容

这里调用了service方法,Log4.step 方法记录每一个步骤详细内容

/**
 * @author EalenXie Created on 2020/1/16 10:49.
 */
@Service
@Slf4j
public class DemoService {
    /**
     * 测试方法, 使用Log4.step记录步骤
     */
    public void sayHello(Map words) {Log4.step("1. 请求来了,执行业务动作");log.info("do somethings");Log4.step("2. 业务动作执行完成");
    }
}
自定义的全局日志收集器

本例中写了一个最简单的直接append写入到文件中,你可以选择自定义的方式进行日志收集(例如写入到数据库或者日志文件,或日志收集框架中,这个过程建议异步处理,可在collect方法上面加入注解@Async)

@Component
public class DemoLogCollector implements LogCollector {
    
    @Override
    public void collect(Log4 log4) throws LogCollectException {
        try {
            File file = new File("D:\\home\\temp\\日志.txt");
            if (!file.getParentFile().exists()) {
                FileUtils.forceMkdir(file.getParentFile());
            }
            try (FileWriter fw = new FileWriter(file, true)) {
                fw.append(log4.toString());
            }
        } catch (IOException e) {
            throw new LogCollectException(e);
        }
    }
}

测试后 , 可以从 D:\home\temp\日志.txt中获取到记录的日志内容。

json格式的数据记录(参数JSON):
{
  "args": {
    "id": 999,
    "value": "content"
  },
  "clientIp": "192.168.1.54",
  "content": "1. 请求来了,执行业务动作\n2. 业务动作执行完成\n",
  "costTime": 2,
  "headers": {
    "User-Agent": "Apache-HttpClient/4.5.10 (Java/11.0.5)",
    "Content-Type": "application/json"
  },
  "logDate": 1593341797293,
  "method": "name.ealen.demo.controller.DemoController#sayHello",
  "reqUrl": "http://localhost:9527/sayHello",
  "respBody": {
    "headers": {},
    "statusCodeValue": 200,
    "body": {
      "id": 999,
      "value": "content"
    },
    "statusCode": "OK"
  },
  "success": true,
  "type": "测试API"
}
XML格式的数据(参数XML):
{
  "args": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>1111 zhangsan",
  "clientIp": "192.168.1.54",
  "content": "",
  "costTime": 4,
  "headers": {
    "User-Agent": "Apache-HttpClient/4.5.10 (Java/11.0.5)",
    "Content-Type": "application/xml"
  },
  "logDate": 1593394523000,
  "method": "name.ealen.demo.controller.DemoController#callXml",
  "reqUrl": "http://localhost:9527/callXml",
  "respBody": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>1111 zhangsan",
  "success": true,
  "type": "测试API"
}
form参数格式的数据(以参数键值对形式):
{
  "args": "z=11&a=1",
  "clientIp": "192.168.1.54",
  "content": "",
  "costTime": 1,
  "headers": {
    "User-Agent": "Apache-HttpClient/4.5.10 (Java/11.0.5)",
    "Content-Type": "application/x-www-form-urlencoded"
  },
  "logDate": 1593342114342,
  "method": "name.ealen.demo.controller.DemoController#params",
  "reqUrl": "http://localhost:9527/params",
  "respBody": {
    "headers": {},
    "statusCodeValue": 200,
    "body": 1,
    "statusCode": "OK"
  },
  "success": true,
  "type": "测试API"
}

特殊参数格式(目前暂为键值对形式,参数默认取对象的toString()方法):

{
  "args": "request=org.apache.catalina.connector.RequestFacade@754f30c3",
  "clientIp": "192.168.1.54",
  "content": "",
  "costTime": 1,
  "headers": {
    "User-Agent": "Apache-HttpClient/4.5.10 (Java/11.0.5)"
  },
  "logDate": 1593342220880,
  "method": "name.ealen.demo.controller.DemoController#callHttpServletRequest",
  "reqUrl": "http://localhost:9527/callHttpServletRequest",
  "respBody": {
    "headers": {},
    "statusCodeValue": 200,
    "body": null,
    "statusCode": "OK"
  },
  "success": true,
  "type": "测试API"
}

Github项目地址 :https://github.com/EalenXie/Log4a

目前暂时项目命名为Log4a(Log for API), 有时间会一直维护和优化

405b9bdf522c1ff504d85d16a9516b99.gif

250beb6e0f5a255912e78a58043b75e9.gif

  • 程序员值得收藏的精选11套后台登录页面和管理页面模版

  • 50份优秀Java求职者简历

  • SpringCloud前后端分离实战项目视频教程分享

  • 2020年全网最全BAT笔试面试题打包分享

感谢点赞支持下哈 22b34c0eff4768154ae96aaaf31fc88c.gif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值