Skip to content

Commit 30017fa

Browse files
committed
feat: aop切面日志新增json参数打印和高并发场景
1. 打印json类型的参数以及参数名和参数值 2. 高并发场景多线程情况下, 将日志封装到对象中一起打印
1 parent 3547f84 commit 30017fa

File tree

3 files changed

+151
-37
lines changed

3 files changed

+151
-37
lines changed

demo-log-aop/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@
2323
</properties>
2424

2525
<dependencies>
26+
27+
<dependency>
28+
<groupId>com.google.guava</groupId>
29+
<artifactId>guava</artifactId>
30+
</dependency>
31+
2632
<dependency>
2733
<groupId>org.springframework.boot</groupId>
2834
<artifactId>spring-boot-starter-web</artifactId>
Lines changed: 125 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,28 @@
11
package com.xkcoding.log.aop.aspectj;
22

3+
import cn.hutool.core.util.ArrayUtil;
34
import cn.hutool.json.JSONUtil;
5+
import com.google.common.collect.Maps;
46
import eu.bitwalker.useragentutils.UserAgent;
7+
import lombok.AllArgsConstructor;
8+
import lombok.Builder;
9+
import lombok.Data;
10+
import lombok.NoArgsConstructor;
511
import lombok.extern.slf4j.Slf4j;
6-
import org.aspectj.lang.JoinPoint;
712
import org.aspectj.lang.ProceedingJoinPoint;
8-
import org.aspectj.lang.annotation.*;
13+
import org.aspectj.lang.Signature;
14+
import org.aspectj.lang.annotation.Around;
15+
import org.aspectj.lang.annotation.Aspect;
16+
import org.aspectj.lang.annotation.Pointcut;
17+
import org.aspectj.lang.reflect.MethodSignature;
918
import org.springframework.stereotype.Component;
1019
import org.springframework.web.context.request.RequestContextHolder;
1120
import org.springframework.web.context.request.ServletRequestAttributes;
1221

1322
import javax.servlet.http.HttpServletRequest;
23+
import java.net.InetAddress;
24+
import java.net.UnknownHostException;
25+
import java.util.Collections;
1426
import java.util.Map;
1527
import java.util.Objects;
1628

@@ -20,14 +32,13 @@
2032
* </p>
2133
*
2234
* @author yangkai.shen
35+
* @author chen qi
2336
* @date Created in 2018-10-01 22:05
2437
*/
2538
@Aspect
2639
@Component
2740
@Slf4j
2841
public class AopLog {
29-
private static final String START_TIME = "request-start";
30-
3142
/**
3243
* 切入点
3344
*/
@@ -36,27 +47,6 @@ public void log() {
3647

3748
}
3849

39-
/**
40-
* 前置操作
41-
*
42-
* @param point 切入点
43-
*/
44-
@Before("log()")
45-
public void beforeLog(JoinPoint point) {
46-
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
47-
48-
HttpServletRequest request = Objects.requireNonNull(attributes).getRequest();
49-
50-
log.info("【请求 URL】:{}", request.getRequestURL());
51-
log.info("【请求 IP】:{}", request.getRemoteAddr());
52-
log.info("【请求类名】:{},【请求方法名】:{}", point.getSignature().getDeclaringTypeName(), point.getSignature().getName());
53-
54-
Map<String, String[]> parameterMap = request.getParameterMap();
55-
log.info("【请求参数】:{},", JSONUtil.toJsonStr(parameterMap));
56-
Long start = System.currentTimeMillis();
57-
request.setAttribute(START_TIME, start);
58-
}
59-
6050
/**
6151
* 环绕操作
6252
*
@@ -66,25 +56,123 @@ public void beforeLog(JoinPoint point) {
6656
*/
6757
@Around("log()")
6858
public Object aroundLog(ProceedingJoinPoint point) throws Throwable {
59+
60+
// 开始打印请求日志
61+
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
62+
HttpServletRequest request = Objects.requireNonNull(attributes).getRequest();
63+
64+
// 打印请求相关参数
65+
long startTime = System.currentTimeMillis();
6966
Object result = point.proceed();
70-
log.info("【返回值】:{}", JSONUtil.toJsonStr(result));
67+
String header = request.getHeader("User-Agent");
68+
UserAgent userAgent = UserAgent.parseUserAgentString(header);
69+
70+
final Log l = Log.builder()
71+
.threadId(Long.toString(Thread.currentThread().getId()))
72+
.threadName(Thread.currentThread().getName())
73+
.ip(getIp(request))
74+
.url(request.getRequestURL().toString())
75+
.classMethod(String.format("%s.%s", point.getSignature().getDeclaringTypeName(),
76+
point.getSignature().getName()))
77+
.httpMethod(request.getMethod())
78+
.requestParams(getNameAndValue(point))
79+
.result(result)
80+
.timeCost(System.currentTimeMillis() - startTime)
81+
.userAgent(header)
82+
.browser(userAgent.getBrowser().toString())
83+
.os(userAgent.getOperatingSystem().toString()).build();
84+
85+
log.info("Request Log Info : {}", JSONUtil.toJsonStr(l));
86+
7187
return result;
7288
}
7389

7490
/**
75-
* 后置操作
91+
* 获取方法参数名和参数值
92+
* @param joinPoint
93+
* @return
7694
*/
77-
@AfterReturning("log()")
78-
public void afterReturning() {
79-
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
80-
HttpServletRequest request = Objects.requireNonNull(attributes).getRequest();
95+
private Map<String, Object> getNameAndValue(ProceedingJoinPoint joinPoint) {
8196

82-
Long start = (Long) request.getAttribute(START_TIME);
83-
Long end = System.currentTimeMillis();
84-
log.info("【请求耗时】:{}毫秒", end - start);
97+
final Signature signature = joinPoint.getSignature();
98+
MethodSignature methodSignature = (MethodSignature) signature;
99+
final String[] names = methodSignature.getParameterNames();
100+
final Object[] args = joinPoint.getArgs();
85101

86-
String header = request.getHeader("User-Agent");
87-
UserAgent userAgent = UserAgent.parseUserAgentString(header);
88-
log.info("【浏览器类型】:{},【操作系统】:{},【原始User-Agent】:{}", userAgent.getBrowser().toString(), userAgent.getOperatingSystem().toString(), header);
102+
if (ArrayUtil.isEmpty(names) || ArrayUtil.isEmpty(args)) {
103+
return Collections.emptyMap();
104+
}
105+
if (names.length != args.length) {
106+
log.warn("{}方法参数名和参数值数量不一致", methodSignature.getName());
107+
return Collections.emptyMap();
108+
}
109+
Map<String, Object> map = Maps.newHashMap();
110+
for (int i = 0; i < names.length; i++) {
111+
map.put(names[i], args[i]);
112+
}
113+
return map;
114+
}
115+
116+
private static final String UNKNOWN = "unknown";
117+
118+
/**
119+
* 获取ip地址
120+
*/
121+
public static String getIp(HttpServletRequest request) {
122+
String ip = request.getHeader("x-forwarded-for");
123+
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
124+
ip = request.getHeader("Proxy-Client-IP");
125+
}
126+
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
127+
ip = request.getHeader("WL-Proxy-Client-IP");
128+
}
129+
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
130+
ip = request.getRemoteAddr();
131+
}
132+
String comma = ",";
133+
String localhost = "127.0.0.1";
134+
if (ip.contains(comma)) {
135+
ip = ip.split(",")[0];
136+
}
137+
if (localhost.equals(ip)) {
138+
// 获取本机真正的ip地址
139+
try {
140+
ip = InetAddress.getLocalHost().getHostAddress();
141+
} catch (UnknownHostException e) {
142+
log.error(e.getMessage(), e);
143+
}
144+
}
145+
return ip;
146+
}
147+
148+
@Data
149+
@Builder
150+
@NoArgsConstructor
151+
@AllArgsConstructor
152+
static class Log {
153+
// 线程id
154+
private String threadId;
155+
// 线程名称
156+
private String threadName;
157+
// ip
158+
private String ip;
159+
// url
160+
private String url;
161+
// http方法 GET POST PUT DELETE PATCH
162+
private String httpMethod;
163+
// 类方法
164+
private String classMethod;
165+
// 请求参数
166+
private Object requestParams;
167+
// 返回参数
168+
private Object result;
169+
// 接口耗时
170+
private Long timeCost;
171+
// 操作系统
172+
private String os;
173+
// 浏览器
174+
private String browser;
175+
// user-agent
176+
private String userAgent;
89177
}
90178
}

demo-log-aop/src/main/java/com/xkcoding/log/aop/controller/TestController.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,25 @@
22

33
import cn.hutool.core.lang.Dict;
44
import cn.hutool.core.util.StrUtil;
5+
import cn.hutool.json.JSONUtil;
6+
import lombok.extern.slf4j.Slf4j;
57
import org.springframework.web.bind.annotation.GetMapping;
8+
import org.springframework.web.bind.annotation.PostMapping;
9+
import org.springframework.web.bind.annotation.RequestBody;
610
import org.springframework.web.bind.annotation.RestController;
711

12+
import java.util.Map;
13+
814
/**
915
* <p>
1016
* 测试 Controller
1117
* </p>
1218
*
1319
* @author yangkai.shen
20+
* @author chen qi
1421
* @date Created in 2018-10-01 22:10
1522
*/
23+
@Slf4j
1624
@RestController
1725
public class TestController {
1826

@@ -27,4 +35,16 @@ public Dict test(String who) {
2735
return Dict.create().set("who", StrUtil.isBlank(who) ? "me" : who);
2836
}
2937

38+
/**
39+
* 测试post json方法
40+
* @param map 请求的json参数
41+
* @return {@link Dict}
42+
*/
43+
@PostMapping("/testJson")
44+
public Dict testJson(@RequestBody Map<String, Object> map) {
45+
46+
final String jsonStr = JSONUtil.toJsonStr(map);
47+
log.info(jsonStr);
48+
return Dict.create().set("json", map);
49+
}
3050
}

0 commit comments

Comments
 (0)