主要功能实现 : 在API每次被请求时,可以在整个方法调用链路中记录一条唯一的API请求日志,可以记录请求中绝大部分关键内容。并且可以自定义实现对日志收集(直接标准输出,或写入到文件或数据库)。
比如传参,响应,请求url,请求方法,clientIp,耗时,请求成功或异常,请求头等等。
@Log4a
注解的方法,会记录一个线程中唯一一个Log4对象,读取AOP中的方法信息(入参,方法等等) 字段 | 类型 | 注释 | 是否默认记录 |
---|---|---|---|
clientIp | String | 请求客户端的Ip | 是 |
reqUrl | String | 请求地址 | 是 |
headers | Object | 请求头部信息(可选择记录) | 是,默认记录user-agent,content-type |
type | String | 操作类型 | 是,默认值undefined |
content | StringBuilder | 步骤内容信息 | 否,方法内容,可使用Log4.step进行内容步骤记录 |
字段 | 类型 | 注释 | 默认 |
---|---|---|---|
type | String | 操作类型 | 默认值"undefined" |
method | boolean | 是否记录请求的本地java方法 | true |
costTime | boolean | 是否记录整个方法耗时 | true |
headers | String[] | 记录的header信息 | 默认"User-Agent","content-type" |
args | boolean | 是否记录请求参数 | true |
respBody | boolean | 是否记录响应参数 | true |
stackTrace | boolean | 当目标方法发生异常时,是否追加异常堆栈信息到content | false |
costTime | boolean | 是否记录整个方法耗时 | true |
collector | Class<? extends LogCollector> | 指定日志收集器 | 默认空的收集器不指定 |
直接在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(); } }
这里调用了service方法,Log4.step 方法记录每一个步骤详细内容
/** * @author EalenXie Created on 2020/1/16 10:49. */ @Service @Slf4j public class DemoService { /** * 测试方法, 使用Log4.step记录步骤 */ public void sayHello(Map<String, Object> 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中获取到记录的日志内容。
{ "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" }
{ "args": "<?xml version=/"1.0/" encoding=/"UTF-8/" ?><xml><message>1111 </message><username>zhangsan</username></xml>", "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/" ?><xml><message>1111 </message><username>zhangsan</username></xml>", "success": true, "type": "测试API" }
{ "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), 有时间会一直维护和优化。