From 30017fa381db25499f9700792df9898ed4934ad1 Mon Sep 17 00:00:00 2001
From: chenqi <1535985458@qq.com>
Date: Mon, 16 Nov 2020 20:27:06 +0800
Subject: [PATCH 1/2] =?UTF-8?q?feat:=20aop=E5=88=87=E9=9D=A2=E6=97=A5?=
=?UTF-8?q?=E5=BF=97=E6=96=B0=E5=A2=9Ejson=E5=8F=82=E6=95=B0=E6=89=93?=
=?UTF-8?q?=E5=8D=B0=E5=92=8C=E9=AB=98=E5=B9=B6=E5=8F=91=E5=9C=BA=E6=99=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
1. 打印json类型的参数以及参数名和参数值
2. 高并发场景多线程情况下, 将日志封装到对象中一起打印
---
demo-log-aop/pom.xml | 6 +
.../com/xkcoding/log/aop/aspectj/AopLog.java | 162 ++++++++++++++----
.../log/aop/controller/TestController.java | 20 +++
3 files changed, 151 insertions(+), 37 deletions(-)
diff --git a/demo-log-aop/pom.xml b/demo-log-aop/pom.xml
index 7113002aa..a01664fbf 100644
--- a/demo-log-aop/pom.xml
+++ b/demo-log-aop/pom.xml
@@ -23,6 +23,12 @@
+
+
+ com.google.guava
+ guava
+
+
org.springframework.boot
spring-boot-starter-web
diff --git a/demo-log-aop/src/main/java/com/xkcoding/log/aop/aspectj/AopLog.java b/demo-log-aop/src/main/java/com/xkcoding/log/aop/aspectj/AopLog.java
index 487a35a57..d39c093de 100644
--- a/demo-log-aop/src/main/java/com/xkcoding/log/aop/aspectj/AopLog.java
+++ b/demo-log-aop/src/main/java/com/xkcoding/log/aop/aspectj/AopLog.java
@@ -1,16 +1,28 @@
package com.xkcoding.log.aop.aspectj;
+import cn.hutool.core.util.ArrayUtil;
import cn.hutool.json.JSONUtil;
+import com.google.common.collect.Maps;
import eu.bitwalker.useragentutils.UserAgent;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
-import org.aspectj.lang.annotation.*;
+import org.aspectj.lang.Signature;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Collections;
import java.util.Map;
import java.util.Objects;
@@ -20,14 +32,13 @@
*
*
* @author yangkai.shen
+ * @author chen qi
* @date Created in 2018-10-01 22:05
*/
@Aspect
@Component
@Slf4j
public class AopLog {
- private static final String START_TIME = "request-start";
-
/**
* 切入点
*/
@@ -36,27 +47,6 @@ public void log() {
}
- /**
- * 前置操作
- *
- * @param point 切入点
- */
- @Before("log()")
- public void beforeLog(JoinPoint point) {
- ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
-
- HttpServletRequest request = Objects.requireNonNull(attributes).getRequest();
-
- log.info("【请求 URL】:{}", request.getRequestURL());
- log.info("【请求 IP】:{}", request.getRemoteAddr());
- log.info("【请求类名】:{},【请求方法名】:{}", point.getSignature().getDeclaringTypeName(), point.getSignature().getName());
-
- Map parameterMap = request.getParameterMap();
- log.info("【请求参数】:{},", JSONUtil.toJsonStr(parameterMap));
- Long start = System.currentTimeMillis();
- request.setAttribute(START_TIME, start);
- }
-
/**
* 环绕操作
*
@@ -66,25 +56,123 @@ public void beforeLog(JoinPoint point) {
*/
@Around("log()")
public Object aroundLog(ProceedingJoinPoint point) throws Throwable {
+
+ // 开始打印请求日志
+ ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
+ HttpServletRequest request = Objects.requireNonNull(attributes).getRequest();
+
+ // 打印请求相关参数
+ long startTime = System.currentTimeMillis();
Object result = point.proceed();
- log.info("【返回值】:{}", JSONUtil.toJsonStr(result));
+ String header = request.getHeader("User-Agent");
+ UserAgent userAgent = UserAgent.parseUserAgentString(header);
+
+ final Log l = Log.builder()
+ .threadId(Long.toString(Thread.currentThread().getId()))
+ .threadName(Thread.currentThread().getName())
+ .ip(getIp(request))
+ .url(request.getRequestURL().toString())
+ .classMethod(String.format("%s.%s", point.getSignature().getDeclaringTypeName(),
+ point.getSignature().getName()))
+ .httpMethod(request.getMethod())
+ .requestParams(getNameAndValue(point))
+ .result(result)
+ .timeCost(System.currentTimeMillis() - startTime)
+ .userAgent(header)
+ .browser(userAgent.getBrowser().toString())
+ .os(userAgent.getOperatingSystem().toString()).build();
+
+ log.info("Request Log Info : {}", JSONUtil.toJsonStr(l));
+
return result;
}
/**
- * 后置操作
+ * 获取方法参数名和参数值
+ * @param joinPoint
+ * @return
*/
- @AfterReturning("log()")
- public void afterReturning() {
- ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
- HttpServletRequest request = Objects.requireNonNull(attributes).getRequest();
+ private Map getNameAndValue(ProceedingJoinPoint joinPoint) {
- Long start = (Long) request.getAttribute(START_TIME);
- Long end = System.currentTimeMillis();
- log.info("【请求耗时】:{}毫秒", end - start);
+ final Signature signature = joinPoint.getSignature();
+ MethodSignature methodSignature = (MethodSignature) signature;
+ final String[] names = methodSignature.getParameterNames();
+ final Object[] args = joinPoint.getArgs();
- String header = request.getHeader("User-Agent");
- UserAgent userAgent = UserAgent.parseUserAgentString(header);
- log.info("【浏览器类型】:{},【操作系统】:{},【原始User-Agent】:{}", userAgent.getBrowser().toString(), userAgent.getOperatingSystem().toString(), header);
+ if (ArrayUtil.isEmpty(names) || ArrayUtil.isEmpty(args)) {
+ return Collections.emptyMap();
+ }
+ if (names.length != args.length) {
+ log.warn("{}方法参数名和参数值数量不一致", methodSignature.getName());
+ return Collections.emptyMap();
+ }
+ Map map = Maps.newHashMap();
+ for (int i = 0; i < names.length; i++) {
+ map.put(names[i], args[i]);
+ }
+ return map;
+ }
+
+ private static final String UNKNOWN = "unknown";
+
+ /**
+ * 获取ip地址
+ */
+ public static String getIp(HttpServletRequest request) {
+ String ip = request.getHeader("x-forwarded-for");
+ if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
+ ip = request.getHeader("Proxy-Client-IP");
+ }
+ if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
+ ip = request.getHeader("WL-Proxy-Client-IP");
+ }
+ if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
+ ip = request.getRemoteAddr();
+ }
+ String comma = ",";
+ String localhost = "127.0.0.1";
+ if (ip.contains(comma)) {
+ ip = ip.split(",")[0];
+ }
+ if (localhost.equals(ip)) {
+ // 获取本机真正的ip地址
+ try {
+ ip = InetAddress.getLocalHost().getHostAddress();
+ } catch (UnknownHostException e) {
+ log.error(e.getMessage(), e);
+ }
+ }
+ return ip;
+ }
+
+ @Data
+ @Builder
+ @NoArgsConstructor
+ @AllArgsConstructor
+ static class Log {
+ // 线程id
+ private String threadId;
+ // 线程名称
+ private String threadName;
+ // ip
+ private String ip;
+ // url
+ private String url;
+ // http方法 GET POST PUT DELETE PATCH
+ private String httpMethod;
+ // 类方法
+ private String classMethod;
+ // 请求参数
+ private Object requestParams;
+ // 返回参数
+ private Object result;
+ // 接口耗时
+ private Long timeCost;
+ // 操作系统
+ private String os;
+ // 浏览器
+ private String browser;
+ // user-agent
+ private String userAgent;
}
}
diff --git a/demo-log-aop/src/main/java/com/xkcoding/log/aop/controller/TestController.java b/demo-log-aop/src/main/java/com/xkcoding/log/aop/controller/TestController.java
index 0eda8962c..c261d7917 100644
--- a/demo-log-aop/src/main/java/com/xkcoding/log/aop/controller/TestController.java
+++ b/demo-log-aop/src/main/java/com/xkcoding/log/aop/controller/TestController.java
@@ -2,17 +2,25 @@
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONUtil;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
+import java.util.Map;
+
/**
*
* 测试 Controller
*
*
* @author yangkai.shen
+ * @author chen qi
* @date Created in 2018-10-01 22:10
*/
+@Slf4j
@RestController
public class TestController {
@@ -27,4 +35,16 @@ public Dict test(String who) {
return Dict.create().set("who", StrUtil.isBlank(who) ? "me" : who);
}
+ /**
+ * 测试post json方法
+ * @param map 请求的json参数
+ * @return {@link Dict}
+ */
+ @PostMapping("/testJson")
+ public Dict testJson(@RequestBody Map map) {
+
+ final String jsonStr = JSONUtil.toJsonStr(map);
+ log.info(jsonStr);
+ return Dict.create().set("json", map);
+ }
}
From d8935e6969c1d7886f0bcf9f082058d21f5d5754 Mon Sep 17 00:00:00 2001
From: chenqi <1535985458@qq.com>
Date: Tue, 17 Nov 2020 10:13:33 +0800
Subject: [PATCH 2/2] =?UTF-8?q?docs:=20=E4=BF=AE=E6=94=B9log-aop=E7=9A=84R?=
=?UTF-8?q?EADME.md=E6=96=87=E6=A1=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
demo-log-aop/README.md | 239 ++++++++++++++++++++++++++++-------------
1 file changed, 167 insertions(+), 72 deletions(-)
diff --git a/demo-log-aop/README.md b/demo-log-aop/README.md
index 526a7da29..14fea8048 100644
--- a/demo-log-aop/README.md
+++ b/demo-log-aop/README.md
@@ -30,6 +30,11 @@
+
+ com.google.guava
+ guava
+
+
org.springframework.boot
spring-boot-starter-web
@@ -86,73 +91,149 @@
*
*
* @author yangkai.shen
+ * @author chen qi
* @date Created in 2018-10-01 22:05
*/
@Aspect
@Component
@Slf4j
public class AopLog {
- private static final String START_TIME = "request-start";
-
- /**
- * 切入点
- */
- @Pointcut("execution(public * com.xkcoding.log.aop.controller.*Controller.*(..))")
- public void log() {
-
- }
-
- /**
- * 前置操作
- *
- * @param point 切入点
- */
- @Before("log()")
- public void beforeLog(JoinPoint point) {
- ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
-
- HttpServletRequest request = Objects.requireNonNull(attributes).getRequest();
-
- log.info("【请求 URL】:{}", request.getRequestURL());
- log.info("【请求 IP】:{}", request.getRemoteAddr());
- log.info("【请求类名】:{},【请求方法名】:{}", point.getSignature().getDeclaringTypeName(), point.getSignature().getName());
-
- Map parameterMap = request.getParameterMap();
- log.info("【请求参数】:{},", JSONUtil.toJsonStr(parameterMap));
- Long start = System.currentTimeMillis();
- request.setAttribute(START_TIME, start);
- }
-
- /**
- * 环绕操作
- *
- * @param point 切入点
- * @return 原方法返回值
- * @throws Throwable 异常信息
- */
- @Around("log()")
- public Object aroundLog(ProceedingJoinPoint point) throws Throwable {
- Object result = point.proceed();
- log.info("【返回值】:{}", JSONUtil.toJsonStr(result));
- return result;
- }
-
- /**
- * 后置操作
- */
- @AfterReturning("log()")
- public void afterReturning() {
- ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
- HttpServletRequest request = Objects.requireNonNull(attributes).getRequest();
-
- Long start = (Long) request.getAttribute(START_TIME);
- Long end = System.currentTimeMillis();
- log.info("【请求耗时】:{}毫秒", end - start);
-
- String header = request.getHeader("User-Agent");
- UserAgent userAgent = UserAgent.parseUserAgentString(header);
- log.info("【浏览器类型】:{},【操作系统】:{},【原始User-Agent】:{}", userAgent.getBrowser().toString(), userAgent.getOperatingSystem().toString(), header);
- }
+ /**
+ * 切入点
+ */
+ @Pointcut("execution(public * com.xkcoding.log.aop.controller.*Controller.*(..))")
+ public void log() {
+
+ }
+
+ /**
+ * 环绕操作
+ *
+ * @param point 切入点
+ * @return 原方法返回值
+ * @throws Throwable 异常信息
+ */
+ @Around("log()")
+ public Object aroundLog(ProceedingJoinPoint point) throws Throwable {
+
+ // 开始打印请求日志
+ ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
+ HttpServletRequest request = Objects.requireNonNull(attributes).getRequest();
+
+ // 打印请求相关参数
+ long startTime = System.currentTimeMillis();
+ Object result = point.proceed();
+ String header = request.getHeader("User-Agent");
+ UserAgent userAgent = UserAgent.parseUserAgentString(header);
+
+ final Log l = Log.builder()
+ .threadId(Long.toString(Thread.currentThread().getId()))
+ .threadName(Thread.currentThread().getName())
+ .ip(getIp(request))
+ .url(request.getRequestURL().toString())
+ .classMethod(String.format("%s.%s", point.getSignature().getDeclaringTypeName(),
+ point.getSignature().getName()))
+ .httpMethod(request.getMethod())
+ .requestParams(getNameAndValue(point))
+ .result(result)
+ .timeCost(System.currentTimeMillis() - startTime)
+ .userAgent(header)
+ .browser(userAgent.getBrowser().toString())
+ .os(userAgent.getOperatingSystem().toString()).build();
+
+ log.info("Request Log Info : {}", JSONUtil.toJsonStr(l));
+
+ return result;
+ }
+
+ /**
+ * 获取方法参数名和参数值
+ * @param joinPoint
+ * @return
+ */
+ private Map getNameAndValue(ProceedingJoinPoint joinPoint) {
+
+ final Signature signature = joinPoint.getSignature();
+ MethodSignature methodSignature = (MethodSignature) signature;
+ final String[] names = methodSignature.getParameterNames();
+ final Object[] args = joinPoint.getArgs();
+
+ if (ArrayUtil.isEmpty(names) || ArrayUtil.isEmpty(args)) {
+ return Collections.emptyMap();
+ }
+ if (names.length != args.length) {
+ log.warn("{}方法参数名和参数值数量不一致", methodSignature.getName());
+ return Collections.emptyMap();
+ }
+ Map map = Maps.newHashMap();
+ for (int i = 0; i < names.length; i++) {
+ map.put(names[i], args[i]);
+ }
+ return map;
+ }
+
+ private static final String UNKNOWN = "unknown";
+
+ /**
+ * 获取ip地址
+ */
+ public static String getIp(HttpServletRequest request) {
+ String ip = request.getHeader("x-forwarded-for");
+ if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
+ ip = request.getHeader("Proxy-Client-IP");
+ }
+ if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
+ ip = request.getHeader("WL-Proxy-Client-IP");
+ }
+ if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
+ ip = request.getRemoteAddr();
+ }
+ String comma = ",";
+ String localhost = "127.0.0.1";
+ if (ip.contains(comma)) {
+ ip = ip.split(",")[0];
+ }
+ if (localhost.equals(ip)) {
+ // 获取本机真正的ip地址
+ try {
+ ip = InetAddress.getLocalHost().getHostAddress();
+ } catch (UnknownHostException e) {
+ log.error(e.getMessage(), e);
+ }
+ }
+ return ip;
+ }
+
+ @Data
+ @Builder
+ @NoArgsConstructor
+ @AllArgsConstructor
+ static class Log {
+ // 线程id
+ private String threadId;
+ // 线程名称
+ private String threadName;
+ // ip
+ private String ip;
+ // url
+ private String url;
+ // http方法 GET POST PUT DELETE PATCH
+ private String httpMethod;
+ // 类方法
+ private String classMethod;
+ // 请求参数
+ private Object requestParams;
+ // 返回参数
+ private Object result;
+ // 接口耗时
+ private Long timeCost;
+ // 操作系统
+ private String os;
+ // 浏览器
+ private String browser;
+ // user-agent
+ private String userAgent;
+ }
}
```
@@ -165,22 +246,36 @@ public class AopLog {
*
*
* @author yangkai.shen
+ * @author chen qi
* @date Created in 2018-10-01 22:10
*/
+@Slf4j
@RestController
public class TestController {
- /**
- * 测试方法
- *
- * @param who 测试参数
- * @return {@link Dict}
- */
- @GetMapping("/test")
- public Dict test(String who) {
- return Dict.create().set("who", StrUtil.isBlank(who) ? "me" : who);
- }
-
+ /**
+ * 测试方法
+ *
+ * @param who 测试参数
+ * @return {@link Dict}
+ */
+ @GetMapping("/test")
+ public Dict test(String who) {
+ return Dict.create().set("who", StrUtil.isBlank(who) ? "me" : who);
+ }
+
+ /**
+ * 测试post json方法
+ * @param map 请求的json参数
+ * @return {@link Dict}
+ */
+ @PostMapping("/testJson")
+ public Dict testJson(@RequestBody Map map) {
+
+ final String jsonStr = JSONUtil.toJsonStr(map);
+ log.info(jsonStr);
+ return Dict.create().set("json", map);
+ }
}
```