- 使用环绕通知打印日志
- 获取request请求
HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import feign.form.ContentType;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
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.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.*;
@Aspect
@Component
@Slf4j
public class RequestLogAspect {
private static final String PATH = "path";
private static final String METHOD = "method";
private static final String REQUEST_BODY = "body";
private static final String HEADER = "header";
private static final String TIME = "time";
@Pointcut(value = "execution(* com.*.controller..*.*(..))")
public void point() {
}
@Around("point()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
HashMap<String, String> map = new HashMap<>();
map.put(TIME, System.currentTimeMillis() + "");
Object proceed = null;
Throwable throwable = null;
try {
proceed = joinPoint.proceed();
} catch (UndeclaredThrowableException e) {
if (e.getUndeclaredThrowable() instanceof FlowException) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
if (method.getReturnType().isAssignableFrom(Result.class)) {
proceed = Result.failure(ExceptionCode.TOO_BUSY);
} else if (method.getReturnType().isAssignableFrom(Result.class)) {
proceed = Result.failure(ExceptionCode.TOO_BUSY);
} else {
throw new BaseException(ExceptionCode.TOO_BUSY);
}
} else {
log.warn("around exception joinPoint:[{}]",joinPoint,e);
}
} catch (Throwable e) {
//解析异常,得到已知异常的转换返回
proceed = GlobalExceptionHandler.exceptionHandler(e);
throwable = e;
} finally {
try {
decorateRequest(map, joinPoint);
log(map, JSON.toJSONString(proceed));
} catch (Exception e) {
log.warn("around exception joinPoint:[{}]",joinPoint,e);
WarnSupport.sendDingding("日志打印异常,异常信息:" + e.getMessage());
}
}
//如果有异常则抛出异常,没有异常正常返回
if (null != throwable) throw throwable;
return proceed;
}
/**
* 日志打印
*/
private void log(Map<String, String> request, String responseBody) {
log.info("\n<Mapping>" +
"\npath -> {}" +
"\ntime -> {}" +
"\nmethod -> {}" +
"\nheaders -> {}" +
"\nrequest -> {}" +
"\nresponse -> {}",
request.get(PATH),
(System.currentTimeMillis() - Long.parseLong(request.get(TIME))) + "ms",
request.get(METHOD),
request.get(HEADER),
request.get(REQUEST_BODY),
responseBody
);
}
/**
* 解析请求
*/
private void decorateRequest(Map<String, String> map, ProceedingJoinPoint joinPoint) {
HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
map.put(PATH, request.getQueryString() != null ? String.format("%s?%s", request.getRequestURI(), request.getQueryString()) : request.getRequestURI());
map.put(HEADER, builderHeaders(request));
map.put(METHOD, request.getMethod());
map.put(REQUEST_BODY, builderRequestParams(request, joinPoint.getArgs()));
}
/**
* 构建请求头打印
*/
private String builderHeaders(HttpServletRequest request) {
Enumeration<String> headerNames = request.getHeaderNames();
StringBuilder headers = new StringBuilder();
while (headerNames.hasMoreElements()) {
String key = headerNames.nextElement();
String value = request.getHeader(key);
headers.append(key).append(":").append(value)
.append(headerNames.hasMoreElements() ? "|" : "");
}
return headers.toString();
}
/**
* 构建请求参数字符串
*/
public static String builderRequestParams(HttpServletRequest request, Object[] args) {
if (request.getContentType() == null) {
return request.getQueryString();
}
if (request.getContentType().startsWith("application/json")) {
StringBuilder stringBuilder = new StringBuilder();
Arrays.stream(args)
.filter(it -> !(it instanceof ServletRequest))
.forEach(it -> stringBuilder.append(JSON.toJSONString(it)));
return stringBuilder.toString();
}
if (request.getContentType().startsWith(ContentType.URLENCODED.getHeader())) {
StringBuilder sb = new StringBuilder();
Enumeration<String> parameterNames = request.getParameterNames();
while (parameterNames.hasMoreElements()) {
String name = parameterNames.nextElement();
sb.append(name).append("=").append(request.getParameter(name)).append("&");
}
String result = sb.toString();
return StringUtils.isBlank(result) ? result : result.substring(0, result.length() - 1);
}
if (isBinaryContent(request) && request.getContentType().startsWith(ContentType.MULTIPART.getHeader())) {
return "file";
}
return null;
}
private static boolean isBinaryContent(final HttpServletRequest request) {
if (request.getContentType() == null) {
return false;
}
//文件上传不记录请求参数
if (Objects.equals(request.getRequestURI(),"/file/upload")){
return true;
}
return request.getContentType().startsWith("image")
|| request.getContentType().startsWith("video")
|| request.getContentType().startsWith("audio");
}
}