package cn.quantgroup.xyqb.aspect.logcaller;

import java.util.concurrent.TimeUnit;

import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Stopwatch;

import cn.quantgroup.xyqb.util.IpUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * 调用者记录
 * Created by Administrator on 2017/5/15.
 */
@Slf4j
@Aspect
@Component
@Order(value = Ordered.HIGHEST_PRECEDENCE)
public class LogCallHttpAspect {

	@Autowired
	private ObjectMapper objectMapper;

	@Pointcut(value = "execution(public * cn.quantgroup.xyqb.controller..*.*(..)) "
			+ "&& !execution(* cn.quantgroup.xyqb.controller.ExceptionHandlingController.*(..))"
			+ "&& !execution(* cn.quantgroup.xyqb.controller.middleoffice.login.ILoginModule.*(..))") // 服务层包路径导致错误，暂时不动，在合适的时候应该挪走
	private void logHttpCaller() {
	}

	@Around("logHttpCaller()")
	public Object record(ProceedingJoinPoint pjp) throws Throwable {
		Stopwatch stopwatch = Stopwatch.createStarted();
		ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
		HttpServletRequest request = attrs.getRequest();
		String remoteIP = IpUtil.getRemoteIP(request);
		Object[] args = pjp.getArgs();
		boolean hasException = false;
		Object result = null;
		try {
			result = pjp.proceed();
		} catch (Throwable e) {
		    log.error(e.getMessage());
			hasException = true;
			throw e;
		} finally {
			long elapsed = stopwatch.stop().elapsed(TimeUnit.MILLISECONDS);
			String resultStr = result == null ? "" : objectMapper.writeValueAsString(result);
			resultStr = resultStr.length() < 500 ? resultStr : resultStr.substring(0, 500);
			log.info("[httpRequestLog],url:[{}],duration:[{}],[耗时区间]{},remoteIP:[{}],args:[{}],exception:[{}],result:[{}]",
					request.getRequestURL(), elapsed, slowlyTag(elapsed), remoteIP, args, hasException, resultStr);
		}
		return result;
	}

	private String slowlyTag(long elapsed) {
        Long second = elapsed / 1000L;
        String outTimeFormat = "[outTime_%s]";
        StringBuffer sb = new StringBuffer();
        // 3秒步长
        for (int outTime = 3; outTime <= second; outTime ++) {
            sb.append(String.format(outTimeFormat, outTime));
        }
        return sb.toString();
	}
}
