feat(common): 新增RequestLogV2Aspect,支持@RequestMapping定义在api里面,controller继承feignApi的情况。
This commit is contained in:
parent
18e2230439
commit
0affbf379f
@ -27,10 +27,14 @@ import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 统一打印日志(支持忽略此aop, 采用@IgnoreRequestLog注解)
|
||||
* 统一打印日志(支持忽略此aop, 采用@IgnoreRequestLog注解)<br>
|
||||
* @Deprecated 改类不会处理 @RequestMapping没有在controller上定义的情况。<br>
|
||||
* 建议使用{@link RequestLogV2Aspect}
|
||||
* @see RequestLogV2Aspect
|
||||
**/
|
||||
@Aspect
|
||||
@Slf4j
|
||||
@Deprecated
|
||||
public class RequestLogAspect {
|
||||
private final static Integer DEFAULT_LOG_SIZE = 2048;
|
||||
private Integer logSize;
|
||||
|
||||
@ -0,0 +1,144 @@
|
||||
package cn.axzo.foundation.web.support.log;
|
||||
|
||||
import cn.axzo.foundation.exception.BusinessException;
|
||||
import cn.axzo.foundation.result.ApiResult;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.google.common.base.Stopwatch;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import lombok.Builder;
|
||||
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.reflect.MethodSignature;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 统一打印日志(支持忽略此aop, 采用@IgnoreRequestLog注解)
|
||||
**/
|
||||
@Aspect
|
||||
@Slf4j
|
||||
public class RequestLogV2Aspect {
|
||||
private final static Integer DEFAULT_LOG_SIZE = 2048;
|
||||
private Integer logSize;
|
||||
|
||||
@Builder
|
||||
public RequestLogV2Aspect(Integer logSize) {
|
||||
this.logSize = Optional.ofNullable(logSize).orElse(DEFAULT_LOG_SIZE);
|
||||
}
|
||||
|
||||
private static Set<Class<?>> EXCLUDE_CLASSES = ImmutableSet.of(ServletRequest.class, ServletResponse.class,
|
||||
MultipartFile.class, BindingResult.class);
|
||||
|
||||
@Around("@within(restController)||@annotation(restController)")
|
||||
public Object doAround(ProceedingJoinPoint joinPoint, RestController restController) throws Throwable {
|
||||
//避免拦截非http请求. 如feign
|
||||
if (RequestContextHolder.getRequestAttributes() == null) {
|
||||
return joinPoint.proceed();
|
||||
}
|
||||
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
|
||||
if (request != null) {
|
||||
//用于在AbstractExceptionHandler中为dumpRequest, AbstractExceptionHandler无法直接获取body
|
||||
request.setAttribute("params", this.getUserArgs(joinPoint.getArgs()));
|
||||
}
|
||||
|
||||
IgnoreRequestLog annotation = AnnotationUtils.findAnnotation(((MethodSignature) joinPoint.getSignature()).getMethod(),
|
||||
IgnoreRequestLog.class);
|
||||
|
||||
// 获取注解中的ignoreTypes
|
||||
ImmutableSet<IgnoreRequestLog.IgnoreType> ignoreTypes = Optional.ofNullable(annotation)
|
||||
.map(a -> ImmutableSet.copyOf(a.types())).orElse(ImmutableSet.of());
|
||||
|
||||
Stopwatch stopwatch = Stopwatch.createStarted();
|
||||
String requestLog = buildRequestLog(joinPoint, ignoreTypes);
|
||||
|
||||
String userSession = StringUtils.EMPTY;
|
||||
String employeeSession = StringUtils.EMPTY;
|
||||
|
||||
String appClient = StringUtils.EMPTY;
|
||||
|
||||
|
||||
Object proceed;
|
||||
try {
|
||||
proceed = joinPoint.proceed(joinPoint.getArgs());
|
||||
} catch (BusinessException e) {
|
||||
//stein会收集error级别的异常并告警. 对BizException. 不期望收到告警邮件. 因此将BizException对应的日志级别调整为warn
|
||||
log.warn("api log, process error, caught BizException, url = {}, params = {}, userSession = {}, employeeSession = {}, appClient = {}, time cost = {} ms, BizException:",
|
||||
request.getRequestURI(), requestLog, userSession, employeeSession, appClient, stopwatch.elapsed(TimeUnit.MILLISECONDS), e);
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
log.error("api log, process error, uncaught exception, url = {}, params = {}, userSession = {}, employeeSession = {}, appClient = {}, time cost = {} ms, exception:",
|
||||
request.getRequestURI(), requestLog, userSession, employeeSession, appClient, stopwatch.elapsed(TimeUnit.MILLISECONDS), e);
|
||||
throw e;
|
||||
} catch (Error error) {
|
||||
log.error("api log, process error, uncaught error, url = {}, params = {}, userSession = {}, employeeSession = {}, appClient = {}, time cost = {} ms, error:",
|
||||
request.getRequestURI(), requestLog, userSession, employeeSession, appClient, stopwatch.elapsed(TimeUnit.MILLISECONDS), error);
|
||||
throw error;
|
||||
}
|
||||
|
||||
// 如果该接口定义的类型不是SILENT的, 则打印日志
|
||||
if (!ignoreTypes.contains(IgnoreRequestLog.IgnoreType.ALL)) {
|
||||
String responseLog;
|
||||
try {
|
||||
responseLog = buildResponseLog(proceed, ignoreTypes);
|
||||
} catch (Exception ex) {
|
||||
log.error("api log, process error, resp serialize error, url = {}, params = {}, userSession = {}, employeeSession = {}, appClient = {}, time cost = {} ms, error:",
|
||||
request.getRequestURI(), requestLog, userSession, employeeSession, appClient, stopwatch.elapsed(TimeUnit.MILLISECONDS), ex);
|
||||
throw ex;
|
||||
}
|
||||
log.info("api log, url = {}, params = {}, userSession = {}, employeeSession = {}, appClient = {}, result = {}, time cost = {} ms",
|
||||
request.getRequestURI(),
|
||||
StringUtils.left(requestLog, logSize),
|
||||
userSession,
|
||||
employeeSession,
|
||||
appClient,
|
||||
responseLog,
|
||||
stopwatch.elapsed(TimeUnit.MILLISECONDS));
|
||||
}
|
||||
|
||||
return proceed;
|
||||
}
|
||||
|
||||
private String buildRequestLog(ProceedingJoinPoint joinPoint, Set<IgnoreRequestLog.IgnoreType> ignoreTypes) {
|
||||
if (ignoreTypes.contains(IgnoreRequestLog.IgnoreType.REQUEST)) {
|
||||
return "IGNORED";
|
||||
}
|
||||
return JSONObject.toJSONString(this.getUserArgs(joinPoint.getArgs()));
|
||||
}
|
||||
|
||||
private String buildResponseLog(Object proceed, Set<IgnoreRequestLog.IgnoreType> ignoreTypes) {
|
||||
if (proceed == null || !(ApiResult.class.isAssignableFrom(proceed.getClass()))) {
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
if (ignoreTypes.contains(IgnoreRequestLog.IgnoreType.RESPONSE)) {
|
||||
return "IGNORED";
|
||||
}
|
||||
return StringUtils.left(JSONObject.toJSONString(proceed), logSize);
|
||||
}
|
||||
|
||||
protected List<Object> getUserArgs(Object[] args) {
|
||||
return Arrays.stream(args)
|
||||
.filter((p) ->
|
||||
Objects.nonNull(p) && EXCLUDE_CLASSES.stream().noneMatch(clz -> clz.isAssignableFrom(p.getClass()))
|
||||
|
||||
).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user