最近公司项目,日志采用aop切面进行管理,根据业务定制级别,例:定了信息类的日志,错误日志,监控日志,输出不同的日志信息,并yml文件中有一个开关按钮
下面是我的具体实现:
首先 application.yml 如下
server:
port: 8080
spring:
application:
name: aop-logs
isEnable: false
自定义注解
package com.cjs.example.annotation;
import java.lang.annotation.*;
/***
* 监控日志
* **/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface MonitorLog {
String description() default "";
boolean async() default false;
}
然后切面处理
package com.cjs.example.aspect;
import com.cjs.example.annotation.MonitorLog;
import com.cjs.example.service.LogOutput;
import com.cjs.example.util.JsonUtil;
import com.cjs.example.util.ThreadUtil;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
@Aspect
@Component
public class MonitorLogAspect {
private static final Logger LOG = LoggerFactory.getLogger(MonitorLogAspect.class);
@Value("${spring.application.isEnable}")
private boolean isEnable;
@Pointcut("@annotation(com.cjs.example.annotation.MonitorLog)")
public void pointcutMonitor() {
}
@Around("pointcutMonitor()")
public Object doInvoke(ProceedingJoinPoint pjp) {
LOG.info("--------------进入monitor日志打印-------------------");
LOG.info("isEnable:{}",isEnable);
if(!isEnable){
return null;
}
Object result = null;
long start = System.currentTimeMillis();
try {
result = pjp.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
LOG.error(throwable.getMessage(), throwable);
throw new RuntimeException(throwable);
} finally {
long end = System.currentTimeMillis();
long elapsedTime = end - start;
printLog(pjp, result, elapsedTime);
}
return result;
}
/**
* 打印日志
* @param pjp 连接点
* @param result 方法调用返回结果
* @param elapsedTime 方法调用花费时间
*/
private void printLog(ProceedingJoinPoint pjp, Object result, long elapsedTime) {
LogOutput strategy = getFocus(pjp);
if (null != strategy) {
strategy.setThreadId(ThreadUtil.getThreadId());
strategy.setResult(JsonUtil.toJSONString(result));
strategy.setElapsedTime(elapsedTime);
if (strategy.isAsync()) {
new Thread(()->LOG.info(strategy.format(), strategy.args())).start();
}else {
LOG.info(strategy.format(), strategy.args());
}
}
}
/**
* 获取注解
*/
private LogOutput getFocus(ProceedingJoinPoint pjp) {
Signature signature = pjp.getSignature();
String className = signature.getDeclaringTypeName();
String methodName = signature.getName();
Object[] args = pjp.getArgs();
String targetClassName = pjp.getTarget().getClass().getName();
try {
Class<?> clazz = Class.forName(targetClassName);
Method[] methods = clazz.getMethods();
for (Method method : methods) {
if (methodName.equals(method.getName())) {
if (args.length == method.getParameterCount()) {
LogOutput strategy = new LogOutput();
strategy.setClassName(className);
strategy.setMethodName(methodName);
MonitorLog ifoLog = method.getAnnotation(MonitorLog.class);
if (null != ifoLog) {
strategy.setArguments(JsonUtil.toJSONString(args));
strategy.setDescription(ifoLog.description());
strategy.setAsync(ifoLog.async());
return strategy;
}
return null;
}
}
}
} catch (ClassNotFoundException e) {
LOG.error(e.getMessage(), e);
}
return null;
}
}
日志输出实体类
package com.cjs.example.service;
import lombok.Data;
import java.io.Serializable;
@Data
public class LogOutput implements Serializable {
private boolean async;
private String threadId;
private String description;
private String className;
private String methodName;
private String arguments;
private String result;
private Long elapsedTime;
public String format() {
return "线程ID: {},方法描述: {}, 目标类名: {}, 目标方法: {}, 调用参数: {}, 返回结果: {}, 花费时间: {}";
}
public Object[] args() {
return new Object[]{this.threadId, this.description, this.className, this.methodName, this.arguments, this.result, this.elapsedTime};
}
}
工具包
package com.cjs.example.util;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
public class JsonUtil {
public static String toJSONString(Object object) {
return JSON.toJSONString(object, SerializerFeature.DisableCircularReferenceDetect);
}
}
工具包
package com.cjs.example.util;
import java.util.UUID;
public class ThreadUtil {
private static final ThreadLocal<String> threadLocal = new ThreadLocal<>();
public static String getThreadId() {
String threadId = threadLocal.get();
if (null == threadId) {
threadId = UUID.randomUUID().toString();
threadLocal.set(threadId);
}
return threadId;
}
}
写个controller测试
package com.cjs.example.controller.member;
import com.cjs.example.annotation.MonitorLog;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MonitorLogController {
@GetMapping("/test2")
@MonitorLog(description = "监控日志信息")
public String test2(@RequestParam("param") String param, @RequestParam("param1") String param1) {
return param+":error日志测试";
}
}
然后启动类启动,进行访问接口就行了,这是走监控日志的,其它定义级别的日志,可以另外再自定义新的注解
原创文章,如需转载请注明链接 https://blog.youkuaiyun.com/u014734630/article/details/114013990