@Component
@Aspect
public class LogAspect {

    /**
     * 失败错误日志默认后缀
     */
    private static final String ERROR_MSG_SUFFIX = "失败";


    @Before("@annotation(log)")
    public void log(JoinPoint joinPoint, Log log) {
        Object[] args = joinPoint.getArgs();
        List<Object> collectArg = null;
        if (ArrayUtils.isNotEmpty(args)) {
            collectArg = Arrays.stream(args).filter(o ->
                    !(o instanceof HttpServletRequest || o instanceof HttpServletResponse)).collect(Collectors.toList());
        }
        switch (log.level()) {
            case WARN:
                LogUtil.warn(String.format("%s,userId:%s,spaceId:%s,param:%s", log.msg(), CommonUtils.getUser(),
                                CommonUtils.getSpace(), JSON.toJSONString(collectArg)));
                break;
            default:
                LogUtil.info(log.module(), log.category(), log.subCategory(),
                        String.format("%s,userId:%s,spaceId:%s,param:%s", log.msg(), CommonUtils.getUser(),
                                CommonUtils.getSpace(), JSON.toJSONString(collectArg)));
        }
    }

    @AfterReturning(value = "@annotation(log)", returning = "returnVal")
    public void afterReturning(JoinPoint joinPoint, Object returnVal, Log log) {
        if (log.printResult()) {
            LogUtil.info(String.format("%s,userId:%s,spaceId:%s,result:%s", log.msg(), CommonUtils.getUser(),
                            CommonUtils.getSpace(), JSON.toJSONString(returnVal)));
        }
    }

    @AfterThrowing(throwing = "ex", pointcut = "@annotation(log)")
    public void afterThrow(JoinPoint joinPoint, Throwable ex, Log log) {
        if (log.expected().isAssignableFrom(ex.getClass())) {
            Object[] args = joinPoint.getArgs();
            List<Object> collectArg = null;
            if (ArrayUtils.isNotEmpty(args)) {
                collectArg = Arrays.stream(args).filter(o ->
                        !(o instanceof HttpServletRequest || o instanceof HttpServletResponse)).collect(Collectors.toList());
            }
            String errorMsg = log.errorMsg();
            if (StringUtils.isEmpty(errorMsg)) {
                errorMsg = log.msg() + ERROR_MSG_SUFFIX;
            }
            LogUtil.error(String.format("%s,userId:%s,spaceId:%s,param:%s", errorMsg, CommonUtils.getUser(),
                            CommonUtils.getSpace(), JSON.toJSONString(collectArg)), ex);
        }
    }
}

@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {

    /**
     * 日志级别
     */
    LogLevel level() default LogLevel.INFO;

    /**
     * 期望的异常
     * 如果方法出现期望异常及其子类,则打印errorMag信息
     */
    Class<? extends Throwable> expected() default Exception.class;

    /**
     * 出现期望异常是的日志打印内容
     */
    String errorMsg() default StringUtils.EMPTY;

    /**
     * 日志打印内容
     */
    String msg();

    /**
     * 是否打印方法返回结果
     */
    boolean printResult() default false;
}