package cn.ibizlab.r7.runtime.util.log;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

import static cn.ibizlab.r7.runtime.util.log.LogMessage.*;

/**
 * 系统全局日志切面类
 * 基于basepackage进行跟踪记录。
 * 有性能消耗，生产环境中建议关闭。
 *
 * @author nancy
 * @date 2020-3-20
 */
@Aspect
@Component
public class LogAspect {
    @Pointcut("execution(public * cn.ibizlab.r7.runtime..*.*(..))")
    private void pointCut() {
    }

    @Around(value = "pointCut()")
    public Object aroundLog(ProceedingJoinPoint joinPoint) throws Throwable {
        //设置日志位置，aop类-->切入点位置
        String className = joinPoint.getSignature().getDeclaringTypeName();
        Logger log = LoggerFactory.getLogger(className);

        //设置日志中执行的方法签名：类名.方法名（参数类型1，参数类型2...)
        String methodSignature = getMethodSignature(joinPoint);

        //添加自定义参数到日志格式中,见logback正则配置。
//        MDC.put("mdc_trace_id", methodSignature);

        //监控返回值、参数、执行时间
        Object[] params = joinPoint.getArgs();
        Object returnedValue = null;
        long start = System.currentTimeMillis();

        log.info(Function_Start,methodSignature);
        //log.debug(CurrentTimeMillis,System.currentTimeMillis());
        log.debug(Params,params);
        //0代表正常结束，1抛出了异常，2准正常结束
        int status = 0;
        String errormsg = null;
        try {
            returnedValue = joinPoint.proceed();
            return returnedValue;
        } catch (Throwable throwable) {
            errormsg = throwable.getMessage();
            if (throwable instanceof RuntimeException) {
                status = 1;
                throwable.printStackTrace();
            } else {
                status = 2;
            }
            throw throwable;

        } finally {
            //形成本地日志信息
            String returnedStr = null;
            try {
                returnedStr = JSON.toJSONString(returnedValue);
            } catch (Exception e) {
                returnedStr = returnedValue + "";
            }

            long timeCost = System.currentTimeMillis() - start;
            switch (status) {
                case 0:
                    log.info(Function_End,methodSignature);
                    log.debug(ReturnedValue+","+TimeCost,returnedStr, timeCost);
                    break;
                case 1:
                    log.error(Function_ErrorEnd, methodSignature,errormsg);
                    break;
                case 2:
                    log.info(Function_ExceptionEnd,methodSignature);
                    log.debug(ExceptionMsg+","+TimeCost, errormsg, timeCost);
                    break;
                default:

            }
        }
    }
    private String getMethodSignature(ProceedingJoinPoint joinPoint){
        String methodSignature = joinPoint.getSignature().toShortString();
        Signature s = joinPoint.getSignature();
        MethodSignature ms = (MethodSignature)s;
        Method m = ms.getMethod();
        Class[] types = m.getParameterTypes();
        String[] paramtypes = new String[types.length];
        for(int i=0;i<types.length;i++){
            paramtypes[i] = types[i].getSimpleName();
        }
        return methodSignature.replace("..", String.join(",", paramtypes));
    }
}
