Springboot接口项目如何使用AOP记录日志

一、 背景

一直想给项目构建一个统一的日志收集系统,先迈出第一步,构建一个日志收集类,用AOP实现无侵入日志收集

二、 环境

1.此随笔内容基于spring boot项目

2.数据库为mysql 5.7.9版本

3.jdk 版本为1.8

三、 说明

此版采用数据库存储,之后考虑使用elasticsearch等工具存储

四、 内容

1、构建日志采集实体类:BaseLogMessage

public class BaseLogMessage {

private String serverIP;

private String appName;

private String method;

private String type;

private String userCode;

private String uri;

private String operationName;

private String operationStatus;

private long startTime;

private Object parameter;

private Object result;

private int SpendTime;

// 此处省略get、set

}

2、构建一个配置文件读取类,用于读取配置文件中的系统名称:SystemPropetiesUtil

@Configuration

public class SystemPropetiesUtil {

@Value("${spring.application.name}")

private String sysName;//系统名称<br> // 此处省略get、set<br>}

3、新建一个AOP类,在控制器方法上作为切点,执行日志收集: LogAspect

@Aspect

@Component

public class LogAspect {

@Autowired

private SystemPropetiesUtil systemPropetiesUtil;

//定义切点方法

@Pointcut("execution(public * cq..campus.prevented.controller.*.*(..))")

public void controllerLog() {

}

public static final Logger LOGGER = LoggerFactory.getLogger(LogAspect.class);

@Around("controllerLog()")

public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {

long startTime = System.currentTimeMillis();

//获取当前请求对象

ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

HttpServletRequest request = attributes.getRequest();

//记录请求信息

BaseLogMessage baseLogMessage = new BaseLogMessage();

//1.获取到所有的参数值的数组

Object[] args = joinPoint.getArgs();

Signature signature = joinPoint.getSignature();

MethodSignature methodSignature = (MethodSignature) signature;

//2.获取到方法的所有参数名称的字符串数组

String[] parameterNames = methodSignature.getParameterNames();

Object result = joinPoint.proceed();

Method method = methodSignature.getMethod();

if (method.isAnnotationPresent(ApiOperation.class)) {

ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);

baseLogMessage.setOperationName(apiOperation.value());

}

long endTime = System.currentTimeMillis();

String urlStr = request.getRequestURL().toString();

baseLogMessage.setUri(urlStr);

baseLogMessage.setType("操作日志");

baseLogMessage.setServerIP(getRemoteIP(request));

baseLogMessage.setMethod(request.getMethod());

baseLogMessage.setAppName(systemPropetiesUtil.getSysName());

baseLogMessage.setResult(result);

baseLogMessage.setParameter(getParameter(method, joinPoint.getArgs()));

baseLogMessage.setSpendTime((int) (endTime - startTime));

baseLogMessage.setStartTime(endTime);

LOGGER.info("{}", JsonUtils.objectToJson(baseLogMessage));

// 数据库存储操作

return result;

}

/**

* 异常返回通知,用于拦截异常日志信息 连接点抛出异常后执行

*

* @param joinPoint 切入点

* @param e 异常信息

*/

@AfterThrowing(pointcut = "controllerLog()", throwing = "e")

public void saveExceptionLog(JoinPoint joinPoint, Throwable e) {

long startTime = System.currentTimeMillis();

if(null==kafkaClient){

kafkaClient = KafkaProducerClient.getInstance(systemPropetiesUtil.getKafkaHost());

// redisClient= RedisClient.getInstance(systemPropetiesUtil.getReidsHost(), Integer.parseInt(systemPropetiesUtil.getRedisPort()), "");

}

// 获取RequestAttributes

RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();

// 从获取RequestAttributes中获取HttpServletRequest的信息

HttpServletRequest request = (HttpServletRequest) requestAttributes

.resolveReference(RequestAttributes.REFERENCE_REQUEST);

String urlStr = request.getRequestURL().toString();

BaseLogMessage baseLogMessage = new BaseLogMessage();

Signature signature = joinPoint.getSignature();

MethodSignature methodSignature = (MethodSignature) signature;

Method method = methodSignature.getMethod();

StringBuffer strbuff = new StringBuffer();

for (StackTraceElement stet : elements) {

strbuff.append(stet + "\n");

}

String message = exceptionName + ":" + exceptionMessage + strbuff.toString();

try {

Object[] args = joinPoint.getArgs();

String[] parameterNames = methodSignature.getParameterNames();

long endTime = System.currentTimeMillis();

baseLogMessage.setUri(urlStr);

baseLogMessage.setType("异常日志");

baseLogMessage.setServerIP(getRemoteIP(request));

baseLogMessage.setMethod(request.getMethod());

baseLogMessage.setAppName(systemPropetiesUtil.getSysName());

baseLogMessage.setResult(message);

baseLogMessage.setParameter(getParameter(method, joinPoint.getArgs()));

baseLogMessage.setSpendTime((int) (endTime - startTime));

baseLogMessage.setStartTime(endTime);

LOGGER.info("{}", JsonUtils.objectToJson(baseLogMessage));

// 数据库存储操作

} catch (Exception e2) {

e2.printStackTrace();

}

}

/**

* 根据方法和传入的参数获取请求参数

*/

private Object getParameter(Method method, Object[] args) {

List<Object> argList = new ArrayList<>();

Parameter[] parameters = method.getParameters();

for (int i = 0; i < parameters.length; i++) {

RequestBody requestBody = parameters[i].getAnnotation(RequestBody.class);

if (requestBody != null) {

argList.add(args[i]);

}

RequestParam requestParam = parameters[i].getAnnotation(RequestParam.class);

if (requestParam != null) {

Map<String, Object> map = new HashMap<>();

String key = parameters[i].getName();

if (!StringUtils.isEmpty(requestParam.value())) {

key = requestParam.value();

}

map.put(key, args[i]);

argList.add(map);

}

}

if (argList.size() == 0) {

return null;

} else if (argList.size() == 1) {

return argList.get(0);

} else {

return argList;

}

}

/**

* 获取请求ip

*/

public static String getRemoteIP(HttpServletRequest request) {

String ip =null;

if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {

ip = request.getHeader("X-Forwarded-For");

}

if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {

ip = request.getHeader("Proxy-Client-IP");

}

if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {

ip = request.getHeader("WL-Proxy-Client-IP");

}

if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {

ip = request.getRemoteAddr();

}

if (ip != null) {

//对于通过多个代理的情况,最后IP为客户端真实IP,多个IP按照','分割

int position = ip.indexOf(",");

if (position > 0) {

ip = ip.substring(0, position);

}

}

return ip;

}

}

五、 问题

1、如果方法正常执行,不进入AOP类,请检查AOP的切点是否书写正确。

以上是 Springboot接口项目如何使用AOP记录日志 的全部内容, 来源链接: utcz.com/z/317935.html

回到顶部