java服务-在切面中应用统一日志记录器
在springboot springmvc springcloud 等程序中,我们经常会要记录一些日志信息,但是每次我们都需要每个action单独建立对应的异常捕捉机制,这里就非常麻烦;
所以笔者这里专门制作了一套通用的拦截器和统一的日志记录器,用于在程序入口处卡点,记录用户请求的接口、包名、类名、方法名、入参、出参、请求完整耗时,用于日志记录;
希望能帮助到入门的朋友们;
package com.ikong.aop.log;
import com.alibaba.fastjson.JSON;
import com.ikong.result.Result;
import com.ikong.utils.IkExceptionUtil;
import com.ikong.utils.IkLogger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class IkLogAspect {
private boolean logSuccess = false;
private Boolean logInfo;
private boolean logErr;
private static final String ErrorInfo = "统一日志拦截器异常";
private static final Logger logger = LoggerFactory.getLogger("ikongApectLogger");
public IkLogAspect(boolean logSuccess) {
this.logSuccess = logSuccess;
this.logErr = Boolean.TRUE;
this.logInfo = Boolean.TRUE;
}
public IkLogAspect(Boolean logInfo, boolean logErr, boolean logResult) {
this.logSuccess = logResult;
this.logErr = logErr;
this.logInfo = logInfo;
}
public IkLogAspect() {
this.logErr = Boolean.TRUE;
this.logInfo = Boolean.TRUE;
this.logSuccess = Boolean.TRUE;
}
public Object proceedWithEx(ProceedingJoinPoint jp) throws Throwable {
Object ret = null;
long startTime = System.currentTimeMillis();
try {
ret = jp.proceed();
this.logCompleted(jp, ret, startTime);
return ret;
} catch (Throwable var7) {
String exInfo = this.logException(jp, startTime, var7);
if (this.logErr) {
IkLogger.error(exInfo);
}
throw var7;
}
}
//统一日志拦截器异常,返回统一的处理信息
private Object getExceptionResult(String exInfo) {
Result result = new Result();
result.setCode(500);
result.setMessage("统一日志拦截器异常");
result.setData(exInfo);
return result;
}
//切面执行正常的时候:记录切面完成的请求入参出参日志
private void logCompleted(ProceedingJoinPoint jp, Object ret, long startTime) {
StringBuilder sb = new StringBuilder();
this.logBasic(sb, jp, startTime);
this.logSuccessResult(sb, ret);
if (this.logInfo) {
logger.info(sb.toString());
}
}
//切面执行异常的时候:记录切面请求入参、异常信息和错误日志
private String logException(ProceedingJoinPoint jp, long startTime, Throwable throwable) {
StringBuilder sb = new StringBuilder();
this.logBasic(sb, jp, startTime);
this.logExceptionResult(sb, throwable);
String message = sb.toString();
if (this.logErr) {
logger.error(message);
}
return message;
}
//记录类名.方法名.耗时.参数列表
private void logBasic(StringBuilder sb, ProceedingJoinPoint jp, long startTime) {
String params = "";
try {
if (jp.getArgs() != null) {
params = JSON.toJSONString(jp.getArgs());
}
} catch (Exception var7) {
if (this.logErr) {
logger.warn("aop序列化参数失败", var7);
}
}
this.buildPrefix(sb, jp, startTime);
sb.append("#parameter:");
sb.append(params);
sb.append("#result:");
}
//组装异常日志信息,将堆栈的信息一并记录
private void logExceptionResult(StringBuilder sb, Throwable throwable) {
String result = throwable.toString();
sb.append(result);
sb.append("###stack:");
sb.append(MyExceptionUtil.getStackTrace(throwable));
}
//根据日志记录logSuccess标识,来记录成功的日志
private void logSuccessResult(StringBuilder sb, Object ret) {
String result = "";
try {
if (ret != null && this.logSuccess) {
result = JSON.toJSONString(ret);
}
} catch (Exception var5) {
if (this.logErr) {
logger.warn("aop序列化结果失", var5);
}
}
sb.append(result);
}
//这里组装类名.方法名.请求耗时
private void buildPrefix(StringBuilder sb, ProceedingJoinPoint jp, long startTime) {
long cost = System.currentTimeMillis() - startTime;
String clazz = jp.getTarget().getClass().getSimpleName();
String method = jp.getSignature().getName();
sb.append("class:");
sb.append(clazz);
sb.append("#method:");
sb.append(method);
sb.append("#cost:");
sb.append(cost);
}
//获取全路径下的方法名
public String getMethodName(ProceedingJoinPoint jp) {
StringBuilder sb = new StringBuilder();
String clazz = jp.getTarget().getClass().getName();
String method = jp.getSignature().getName();
sb.append(clazz);
sb.append(".");
sb.append(method);
return sb.toString();
}
}
日志拦截器的应用
package com.ikong.aop.log;
import com.ikong.aop.log.IkLogAspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* @author ikong
*/
@Aspect
@Component
@Order(1)
public class RequestLogAspectHandler {
private final static String POINT = "execution (* com.ikong.web.api.controller..*.*(..))";
private final IkLogAspect handler = new IkLogAspect(false, false, false);
private static final Logger LOG = LoggerFactory.getLogger(RequestLogAspectHandler.class);
@Around(value = POINT)
public Object printLog(ProceedingJoinPoint jp) {
Object ret = null;
try {
String key = handler.getMethodName(jp);
ret = handler.proceedWithEx(jp);
} catch (Throwable throwable) {
LOG.error("error:{}",throwable.getMessage());
} finally {
}
return ret;
}
}
补充涉及到的代码
public class MyExceptionUtil {
public MyExceptionUtil() {}
public static String getStackTrace(Throwable throwable) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
String var3;
try {
throwable.printStackTrace(pw);
var3 = sw.toString();
} finally {
pw.close();
try {
sw.close();
} catch (IOException var10) {
var10.printStackTrace();
}
}
return var3;
}
}