编写切面,可以加到公共模块里面,也可以放到网关层
/**
* @author
* @title: OpreateLogAop
* @projectName commerce
* @description: TODO
* @date 2021/11/2919:06
*/
@Aspect
@Component
public class OpreateLogAspect {
private final static Logger LOGGER = LoggerFactory.getLogger(RequestLogAspect.class);
@Pointcut("execution(* com.scm..*.controller..*(..))")
public void requestServer() {
}
@Around("requestServer()")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
OperateLogDTO log = new OperateLogDTO();
long beginTime = System.currentTimeMillis();
Object result = pjp.proceed();
try {
ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (Objects.nonNull(sra)) {
HttpServletRequest request = sra.getRequest();
// 日志标题
log.setOperationInfo(getControllerMethodInfo(pjp).get("description").toString());
//获取客户端操作系统
String osInfo = getOsInfo(request);
log.setOsInfo(osInfo);
//IP地址
log.setClientIp(request.getRemoteAddr());
//日志请求url
log.setRequestUrl(request.getRequestURI());
//请求方式
log.setRequestType(request.getMethod());
//请求参数
log.setRequestParam(JacksonUtils.writeValueAsString(getRequestParamsByProceedingJoinPoint(pjp)));
//请求用户
// log.setOperationUserCode(UserUtils.getEmployeeCode());
log.setResponseData(result == null ? "" : JacksonUtils.writeValueAsString(result));
//创建时间
log.setCreateTime(new Date());
long endTime = System.currentTimeMillis();
//请求耗时
long logElapsedTime = endTime - beginTime;
log.setCostTime((int) logElapsedTime);
ServerInfo serverInfo = getServerInfo();
log.setServerIp(serverInfo.getIp());
log.setServerInfo(serverInfo.getHostName());
LOGGER.info("行为日志记录---->" + JacksonUtils.writeValueAsString(log));
OpreateLog.getInstance().offerQueue(log);
}
} catch (Exception e) {
LOGGER.error("AOP后置通知异常", e);
}
return result;
}
@AfterThrowing(pointcut = "requestServer()", throwing = "e")
public void doAfterThrow(JoinPoint joinPoint, RuntimeException e) {
try {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
RequestLogAspect.RequestErrorInfo requestErrorInfo = new RequestLogAspect.RequestErrorInfo();
if (!ObjectUtils.isEmpty(attributes) && !ObjectUtils.isEmpty(attributes.getRequest())) {
HttpServletRequest request = attributes.getRequest();
requestErrorInfo.setIp(request.getRemoteAddr());
requestErrorInfo.setUrl(request.getRequestURL().toString());
requestErrorInfo.setHttpMethod(request.getMethod());
}
requestErrorInfo.setClassMethod(String.format("%s.%s", joinPoint.getSignature().getDeclaringTypeName(),
joinPoint.getSignature().getName()));
requestErrorInfo.setRequestParams(getRequestParamsByJoinPoint(joinPoint));
StackTraceElement[] stackTrace = e.getStackTrace();
// 转换成json
JSONObject jsonObject = new JSONObject();
if (!ObjectUtils.isEmpty(stackTrace)) {
StackTraceElement stackTraceElement = stackTrace[0];
jsonObject = JSONUtil.parseObj(JSONUtil.toJsonStr(stackTraceElement));
// 转换成json
jsonObject.set("errorContent", e.getMessage());
jsonObject.set("createTime", DateUtil.date());
jsonObject.setDateFormat(DatePattern.NORM_DATETIME_PATTERN);
jsonObject.set("messageId", IdUtil.fastSimpleUUID());
// 获取IP地址
jsonObject.set("serverIp", NetUtil.getLocalhostStr());
}
requestErrorInfo.setErrorMessage(jsonObject);
LOGGER.info("Error Request Info : {}", JSONUtil.toJsonStr(requestErrorInfo));
} catch (Exception ignored) {
}
}
/**
* 获取入参
* @param proceedingJoinPoint 入参
*
* @return 返回
* */
private Map<String, Object> getRequestParamsByProceedingJoinPoint(ProceedingJoinPoint proceedingJoinPoint) {
//参数名
String[] paramNames = ((MethodSignature)proceedingJoinPoint.getSignature()).getParameterNames();
//参数值
Object[] paramValues = proceedingJoinPoint.getArgs();
return buildRequestParam(paramNames, paramValues);
}
private Map<String, Object> getRequestParamsByJoinPoint(JoinPoint joinPoint) {
try {
//参数名
String[] paramNames = ((MethodSignature)joinPoint.getSignature()).getParameterNames();
//参数值
Object[] paramValues = joinPoint.getArgs();
return buildRequestParam(paramNames, paramValues);
} catch (Exception e) {
return new HashMap<>();
}
}
/**
* 得到计算机的ip,名称,操作系统名称,操作系统版本
*
* @return ServerInfo
*/
public static ServerInfo getServerInfo() {
try {
ServerInfo serverInfo = new ServerInfo();
InetAddress addr = InetAddress.getLocalHost();
serverInfo.setIp(addr.getHostAddress());
//获取本机ip
serverInfo.setHostName(addr.getHostName());
Properties props = System.getProperties();
serverInfo.setOsName(props.getProperty("os.name"));
serverInfo.setOsVersion(props.getProperty("os.version"));
return serverInfo;
} catch (Exception e) {
e.printStackTrace();
}
return new ServerInfo();
}
/**
* 获取注解中对方法的描述信息 用于Controller层注解
*
* @param joinPoint 切点
* @return 方法描述
* @throws Exception
*/
public static Map<String, Object> getControllerMethodInfo(JoinPoint joinPoint) throws Exception {
Map<String, Object> map = new HashMap<String, Object>(16);
//获取目标类名
String targetName = joinPoint.getTarget().getClass().getName();
//获取方法名
String methodName = joinPoint.getSignature().getName();
//获取相关参数
Object[] arguments = joinPoint.getArgs();
//生成类对象
Class targetClass = Class.forName(targetName);
//获取该类中的方法
Method[] methods = targetClass.getMethods();
String description = "description";
String type = "";
String operationType = "";
String serviceName = "";
for (Method method : methods) {
if (!method.getName().equals(methodName)) {
continue;
}
Annotation[] annotations = method.getDeclaredAnnotations();
if (annotations != null) {
for (Annotation annotation : annotations) {
if (annotation instanceof ApiOperation) {
ApiOperation methodDesc = (ApiOperation) annotation;
String desc = methodDesc.value();
map.put(description, desc);
System.out.println(desc);
}
}
}
}
return map;
}
private String getOsInfo(HttpServletRequest request){
String userAgent = request.getHeader("User-Agent");
String os = "";
if (userAgent.toLowerCase().contains("windows")) {
os = "Windows";
} else if(userAgent.toLowerCase().contains("mac")) {
os = "Mac";
} else if(userAgent.toLowerCase().contains("x11")) {
os = "Unix";
} else if(userAgent.toLowerCase().contains("android")) {
os = "Android";
} else if(userAgent.toLowerCase().contains("iphone")) {
os = "IPhone";
}else{
os = "UnKnown, More-Info: "+userAgent;
}
return os;
}
private Map<String, Object> buildRequestParam(String[] paramNames, Object[] paramValues) {
try {
Map<String, Object> requestParams = new HashMap<>(paramNames.length);
for (int i = 0; i < paramNames.length; i++) {
Object value = paramValues[i];
//如果是文件对象
if (value instanceof MultipartFile) {
MultipartFile file = (MultipartFile) value;
//获取文件名
value = file.getOriginalFilename();
}
requestParams.put(paramNames[i], value);
}
return requestParams;
} catch (Exception e) {
return new HashMap<>(1);
}
}
@Data
public static class RequestInfo {
private String ip;
private String url;
private String httpMethod;
private String classMethod;
private Object requestParams;
private Object result;
private Long timeCost;
}
@Data
public static class RequestErrorInfo {
private String ip;
private String url;
private String httpMethod;
private String classMethod;
private Object requestParams;
private JSONObject errorMessage;
}
@Data
public static class ServerInfo {
private String ip;
private String hostName;
private String osName;
private String osVersion;
}
}
2、将任务放到阻塞队列中,另外起一个线程处理
package com.scm.common.log;
import com.mountslink.components.util.SpringUtils;
import com.scm.common.aop.OperateLogDTO;
import com.scm.common.feign.base.BaseService;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
/**
* ${DESCRIPTION}
*
* @author wanghaobin
* @create 2017-07-01 15:28
*/
@Slf4j
public class OpreateLog extends Thread {
private static OpreateLog dblog = null;
private static BlockingQueue<OperateLogDTO> logInfoQueue = new LinkedBlockingQueue<>(10);
private BaseService baseService;
public OpreateLog() {
super("CLogOracleWriterThread");
this.baseService = SpringUtils.getBean(BaseService.class);
}
public static synchronized OpreateLog getInstance() {
if (dblog == null) {
dblog = new OpreateLog();
dblog.start();
}
return dblog;
}
public void offerQueue(OperateLogDTO logInfo) {
try {
logInfoQueue.offer(logInfo);
} catch (Exception e) {
log.error("日志写入失败", e);
}
}
@Override
public void run() {
// 缓冲队列
List<OperateLogDTO> bufferedLogList = new ArrayList<>();
log.error("日志写入开始");
while (true) {
try {
bufferedLogList.add(logInfoQueue.take());
logInfoQueue.drainTo(bufferedLogList);
if (bufferedLogList.size() > 0) {
// 写入日志
for (OperateLogDTO operateLogDTO : bufferedLogList) {
}
}
} catch (Exception e) {
e.printStackTrace();
// 防止缓冲队列填充数据出现异常时不断刷屏
try {
Thread.sleep(1000);
} catch (Exception eee) {
}
} finally {
if (bufferedLogList.size() > 0) {
try {
bufferedLogList.clear();
} catch (Exception e) {
}
}
}
}
}
}