自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLog {
/**
* 功能描述
*
* @return {String}
*/
String value() default "";
}
定义全局日志切面
@Slf4j
@Aspect
@Component
public class SysLogAspect {
@Resource
LogService logService;
@Resource
private HttpServletRequest request;
@Value("${spring.application.name}")
private String springApplicationName;
/**
* @Pointcut 定义一个切入点,指明 Advice(切面) 在什么情况下触发
* @annotation 当执行的方法上拥有指定的注解时生效。
*/
@Pointcut("@annotation(com.kb.spring.boot.starter.log.annotation.SysLog)")
public void pointCut() {
}
/**
* 环绕通知:前置+目标方法执行+后置通知
*
* @param point
* @return
*/
@SneakyThrows
@Around("pointCut()")
public Object around(ProceedingJoinPoint point) {
String strClassName = point.getTarget().getClass().getName();
String strMethodName = point.getSignature().getName();
Object result = point.proceed();
Class<?> targetCls = point.getTarget().getClass();
//获取方法签名(通过此签名获取目标方法信息)
MethodSignature ms = (MethodSignature) point.getSignature();
//获取目标方法上的注解指定的操作名称
Method targetMethod = targetCls.getDeclaredMethod(ms.getName(), ms.getParameterTypes());
SysLog annotation = targetMethod.getAnnotation(SysLog.class);
try {
saveLog(strClassName, strMethodName, annotation, point.getArgs(), result);
} catch (Exception e) {
log.error("日志记录失败 功能:{}", annotation.value());
}
return result;
}
/**
* 异步收集日志
*
* @param strClassName 类名
* @param strMethodName 方法名
* @param annotation 操作名称
* @param args 参数
* @param result 返回值
*/
private void saveLog(String strClassName, String strMethodName, SysLog annotation, Object[] args, Object result) {
LogDTO logDTO = new LogDTO();
logDTO.setClassName(strClassName);
logDTO.setMethod(strMethodName);
logDTO.setMethodInfo(annotation.value());
logDTO.setApplication(springApplicationName);
logDTO.setParams(convertArgs(args));
logDTO.setResult(result == null ? null : result.toString());
logDTO.setUrl(request.getRequestURI());
logDTO.setIp(getRemoteAddrIp(request));
logDTO.setOperationTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
//获取用户信息
SysUserDTO sysUser = getUserId();
if (sysUser != null) {
logDTO.setOperatorId(sysUser.getId());
logDTO.setOperatorPhone(sysUser.getPhone());
logDTO.setOperatorName(sysUser.getNickname());
}
logService.saveLog(logDTO);
}
}
日志服务
放入 redis 队列中
@Service
public class LogServiceImpl implements LogService {
@Resource
private RedisTemplate redisTemplate;
@Override
@Async
public void saveLog(LogDTO logDTO) {
String json = JSON.toJSONString(logDTO);
redisTemplate.opsForList().rightPush(RedisKeyEnum.SYS_LOG_REDIS_KEY.toString(),json);
}
}
操作日志处理 Job
@Component
@Slf4j
public class SysLogsJob{
@Resource
ArkRedisClient redisClient;
@Resource
SysLogsFeignClient sysLogsFeignClient;
@XxlJob(value = "sysLogProcessHandler")
public ReturnT<String> logTimingProcessing(String param) {
log.info("操作日志处理开始!!!!");
while (true) {
Object o = redisClient.lpop(RedisKeyEnum.SYS_LOG_REDIS_KEY.toString());
if (o == null) {
break;
}
JSONObject jsonObject = (JSONObject) JSONObject.parse(o.toString());
try {
LogDTO logDTO = JSONObject.toJavaObject(jsonObject, LogDTO.class);
SysLogsInsertReqVO sysLogsInsertReqVO = new SysLogsInsertReqVO();
BeanUtils.copyProperties(logDTO, sysLogsInsertReqVO);
sysLogsFeignClient.save(sysLogsInsertReqVO);
log.info("操作日志处理中.......");
} catch (Exception e) {
redisClient.lpush(RedisKeyEnum.SYS_LOG_REDIS_KEY.toString(),jsonObject);
log.info("记录保存失败 info:{} e:{}", o,e);
}
}
log.info("操作日志处理结束!!!!");
return ReturnT.SUCCESS;
}
}