1.定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TraceLog {
/**
* 日志类型
*
* @return
*/
String type() default "";
}
2.定义捕获日志接口方法
public interface ITraceLogProcess {
void afterThrowing(JoinPoint pjp, Throwable ex, Long beforeTime);
void afterReturning(JoinPoint pjp, Object result, Long beforeTime);
void before(JoinPoint pjp);
}
3.定义捕获日志方法实现
@Slf4j
public class TraceLogProcess implements ITraceLogProcess {
private static String UNKNOWN_IP = "unknown";
private static String X_FORWARDED_FOR = "x-forwarded-for";
@Override
public void afterThrowing(JoinPoint pjp, Throwable ex, Long beforeTime) {
MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod();
TraceLog traceLog = method.getAnnotation(TraceLog.class);
Integer errorCode = ResultCode.UNKNOWN_CODE.getCode();
String errorMsg = ResultCode.UNKNOWN_CODE.getDesc();
if (ex instanceof ApiException) {
errorCode = ((ApiException) ex).getResultCode();
errorMsg = ex.getMessage();
}
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
log.info("[Tracelog failed] Call interface[{}] from IP[{}] return error," +
"URL:[{}], method name:[{}]," +
"method type:[{}], expend time(ms):[{}]," +
"input parameter:[{}]," +
"error code:[{}], error message:[{}]",
traceLog != null ? traceLog.type() : "", getIpAddr(request),
request.getRequestURL().toString(), signature.getName(),
request.getMethod(), System.currentTimeMillis() - beforeTime,
pjp.getArgs(), errorCode, errorMsg);
}
@Override
public void afterReturning(JoinPoint pjp, Object result, Long beforeTime) {
MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod();
TraceLog traceLog = method.getAnnotation(TraceLog.class);
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
log.info("[Tracelog success]Call interface[{}] from IP[{}]," +
"URL:[{}], method name:[{}]," +
"method type:[{}], expend time(ms):[{}]," +
"input parameter:[{}]," +
"result:[{}]",
traceLog != null ? traceLog.type() : "", getIpAddr(request),
request.getRequestURL().toString(), signature.getName(),
request.getMethod(), System.currentTimeMillis() - beforeTime,
pjp.getArgs(), JSONObject.toJSONString(result));
}
@Override
public void before(JoinPoint pjp) {
MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod();
TraceLog traceLog = method.getAnnotation(TraceLog.class);
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
log.info("[Tracelog begin]Call interface[{}] from IP[{}]," +
"URL:[{}], method name:[{}]," +
"method type:[{}], input parameter:[{}]",
traceLog != null ? traceLog.type() : "", getIpAddr(request),
request.getRequestURL().toString(), signature.getName(),
request.getMethod(), pjp.getArgs());
}
private String getIpAddr(HttpServletRequest request) {
//获取代理服务器IP地址
String proxyIp = request.getHeader(X_FORWARDED_FOR);
//如果存在代理服务器IP地址,则从中提取客户端真实IP地址
if (proxyIp != null && proxyIp.length() != 0) {
String[] ips = proxyIp.split(",");
for (String ip : ips) {
if (!UNKNOWN_IP.equalsIgnoreCase(ip)) {
return ip.trim();
}
}
}
//如果不存在代理服务器IP地址,则直接获取远程IP地址
return request.getRemoteAddr();
}
}
4.定义日志捕获切面
@Slf4j
@Aspect
public class TraceLogAspect {
@Resource(name = "traceLogProcess")
ITraceLogProcess traceLogProcess;
private Long beforeTime;
@AfterThrowing(throwing = "ex", value = "@annotation(uih.st.core.traceLog.TraceLog)")
public void afterThrowing(JoinPoint pjp, Throwable ex) {
traceLogProcess.afterThrowing(pjp, ex, beforeTime);
}
@AfterReturning(returning = "result", value = "@annotation(uih.st.core.traceLog.TraceLog)")
public void afterReturning(JoinPoint pjp, Object result) {
traceLogProcess.afterReturning(pjp, result, beforeTime);
}
@Before(value = "@annotation(uih.st.core.traceLog.TraceLog)")
public void before(JoinPoint pjp) {
this.beforeTime = System.currentTimeMillis();
traceLogProcess.before(pjp);
}
}
5.通过AutoConfiguration实现注入
@Configuration
@ConditionalOnWebApplication
public class TraceLogAutoConfiguration {
@Bean(name = "traceLogProcess")
@ConditionalOnMissingBean(name = "traceLogProcess")
public ITraceLogProcess traceLogProcess() {
return new TraceLogProcess();
}
@Bean
public TraceLogAspect traceLogAspect() {
return new TraceLogAspect();
}
}
6.starter文件spring.factories新增类
org.springframework.boot.autoconfigure.EnableAutoConfiguration=core.TraceLogAutoConfiguration
将上述实现的starter通过依赖引用后:
@TraceLog(type = "aaaaaa")
@PostMapping("/test")
public Result test() {
return Result.success();
}