@@ -30,6 +30,11 @@ | |||
</properties> | |||
<dependencies> | |||
<dependency> | |||
<groupId>com.google.guava</groupId> | |||
<artifactId>guava</artifactId> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.springframework.boot</groupId> | |||
<artifactId>spring-boot-starter-web</artifactId> | |||
@@ -86,73 +91,149 @@ | |||
* </p> | |||
* | |||
* @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<String, String[]> 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<String, Object> 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<String, Object> 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 { | |||
* </p> | |||
* | |||
* @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<String, Object> map) { | |||
final String jsonStr = JSONUtil.toJsonStr(map); | |||
log.info(jsonStr); | |||
return Dict.create().set("json", map); | |||
} | |||
} | |||
``` | |||
@@ -23,6 +23,12 @@ | |||
</properties> | |||
<dependencies> | |||
<dependency> | |||
<groupId>com.google.guava</groupId> | |||
<artifactId>guava</artifactId> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.springframework.boot</groupId> | |||
<artifactId>spring-boot-starter-web</artifactId> | |||
@@ -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 @@ import java.util.Objects; | |||
* </p> | |||
* | |||
* @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 class AopLog { | |||
} | |||
/** | |||
* 前置操作 | |||
* | |||
* @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<String, String[]> parameterMap = request.getParameterMap(); | |||
log.info("【请求参数】:{},", JSONUtil.toJsonStr(parameterMap)); | |||
Long start = System.currentTimeMillis(); | |||
request.setAttribute(START_TIME, start); | |||
} | |||
/** | |||
* 环绕操作 | |||
* | |||
@@ -66,25 +56,123 @@ public class AopLog { | |||
*/ | |||
@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<String, Object> 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<String, Object> 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; | |||
} | |||
} |
@@ -2,17 +2,25 @@ package com.xkcoding.log.aop.controller; | |||
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; | |||
/** | |||
* <p> | |||
* 测试 Controller | |||
* </p> | |||
* | |||
* @author yangkai.shen | |||
* @author chen qi | |||
* @date Created in 2018-10-01 22:10 | |||
*/ | |||
@Slf4j | |||
@RestController | |||
public class TestController { | |||
@@ -27,4 +35,16 @@ public class TestController { | |||
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<String, Object> map) { | |||
final String jsonStr = JSONUtil.toJsonStr(map); | |||
log.info(jsonStr); | |||
return Dict.create().set("json", map); | |||
} | |||
} |