Audit注解拦截器,用于自动记录日志
来源:互联网 发布:炫浪网络社区百合 编辑:程序博客网 时间:2024/06/05 16:39
import java.io.Serializable;import java.lang.annotation.Annotation;import java.lang.reflect.Array;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.Date;import java.util.List;import java.util.concurrent.ConcurrentLinkedQueue;import java.util.concurrent.Executors;import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent.TimeUnit;import javax.faces.context.FacesContext;import javax.interceptor.AroundInvoke;import javax.interceptor.Interceptor;import javax.interceptor.InvocationContext;import javax.servlet.http.HttpSession;import org.apache.commons.lang3.time.DateFormatUtils;import org.json.JSONArray;import org.json.JSONObject;import org.slf4j.Logger;import org.slf4j.LoggerFactory;/** * {@literal @}Audit注解拦截器,用于自动记录日志 * * */@Interceptor@Auditpublic class AuditInteceptor implements Serializable { private static final long serialVersionUID = 3173066019141998118L; private Logger logger = LoggerFactory.getLogger(this.getClass()); private static String pattern = "yyyy-MM-dd HH:mm:ss"; private static ConcurrentLinkedQueue<LogTask> pendingTaskList; private static ScheduledExecutorService schedulerTaskExecutor; static { pendingTaskList = new ConcurrentLinkedQueue<>(); schedulerTaskExecutor = Executors.newSingleThreadScheduledExecutor(); schedulerTaskExecutor.scheduleAtFixedRate(new Runnable() { @Override public void run() { try { for (LogTask task; (task = pendingTaskList.poll()) != null;) { task.run(); } } catch (Exception e) { } } } ,0 , 100, TimeUnit.MILLISECONDS); } //@PreDestroy protected void destroy(InvocationContext context) { if (schedulerTaskExecutor != null) { schedulerTaskExecutor.shutdown(); schedulerTaskExecutor = null; } if (pendingTaskList != null) { pendingTaskList.clear(); pendingTaskList = null; } } class LogTask implements Runnable { private Level logLevel; private String format; private Object[] arguments; public LogTask(Level logLevel, String format, Object... arguments) { this.logLevel = logLevel; this.format = format; this.arguments = arguments; } @Override public void run() { switch (logLevel) { case TRACE: logger.trace(format, arguments); break; case DEBUG: logger.debug(format, arguments); break; case INFO: logger.info(format, arguments); break; case WARN: logger.warn(format, arguments); break; case ERROR: logger.error(format, arguments); break; } } } /** * 加了@Audit注解的类或方法在执行前会先进这个方法,记录调用日志。目前记录的信息包括: * <ol> * <li>被调用方法所在类的类名</li> * <li>方法名</li> * <li>参数列表</li> * <li>调用时间</li> * <li>用户ID</li> * </ol> * * @param context * 被执行方法的上下文 * @return * @throws Exception */ @AroundInvoke public Object audit(InvocationContext context) throws Exception { // 根据方法或类上的注解决定日志的等级 Level logLevel = this.determineLogLevel(context); // 根绝日志的等级判断日志是否会被输出,由外部配置文件决定 boolean currentLevelEnabled = this.isLevelEnabled(logLevel); try { // 实际调用被拦截的方法 Object ret = context.proceed(); if (currentLevelEnabled) { pendingTaskList.offer(new LogTask(logLevel, "调用成功: {}, 详情: {}", context.getMethod().toString(), buildLogDetailObj(context).toString(4))); } return ret; } catch (Exception e) { pendingTaskList.offer(new LogTask(Level.ERROR, "调用异常: {}, 详情: {}", context.getMethod().toString(), buildLogDetailObj(context).toString(4))); throw new LogException(e); } } /** * 根据方法或类上的注解决定日志的等级 * * @param context * 被执行方法的上下文 * @return {@link com.taiji.framework.cdi.annotation.audit.Level Level}对象,代表日志级别 * @throws IllegalAccessException */ private Level determineLogLevel(InvocationContext context) throws IllegalAccessException { // 类名 Class<?> clazz = context.getMethod().getDeclaringClass(); // 方法名 Method method = context.getMethod(); /* * 根据 Method 上的 Annotations 设置 log 等级 */ Annotation methodAuditAnnotation = method.getAnnotation(Audit.class); Annotation methodAuditLevelAnnotation = method.getAnnotation(AuditLevel.class); Annotation classAuditAnnotation = clazz.getAnnotation(Audit.class); Level logLevel = Level.INFO; /* * if method do not have Audit Annotation, then set log level to class's Audit level */ if (methodAuditAnnotation != null) { logLevel = ((Audit) methodAuditAnnotation).level(); } else if (classAuditAnnotation != null) { logLevel = ((Audit) classAuditAnnotation).level(); } else { // 方法和类上都没有Audit注解,那是怎么进这里来的? throw new IllegalAccessException(); } /* * 决定日志Level优先级:@AuditLevel on method > @Audit on method > @Audit on class */ if (methodAuditLevelAnnotation != null) { logLevel = ((AuditLevel) methodAuditLevelAnnotation).value(); } return logLevel; } /** * 生成详细的调用信息 * * @param context * 被执行方法的上下文 * @return */ private JSONObject buildLogDetailObj(InvocationContext context) { JSONObject detailObj = new JSONObject(); // 方法名 Method method = context.getMethod(); // 参数数组 Object[] parameters = context.getParameters(); User user = null; try { HttpSession session = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(false); if (session != null) { user = (User) session.getAttribute("session_user"); } } catch (Exception e) { } /* * 将调用栈中以"com.taiji"开头的类按顺序收集 */ List<String> classNameList = new ArrayList<String>(); StackTraceElement[] currentStackTraces = Thread.currentThread().getStackTrace(); for (StackTraceElement ste : currentStackTraces) { if (ste.getClassName().startsWith("com.taiji")) { classNameList.add(ste.toString()); } } /* * build parameters info */ JSONArray paramArray = new JSONArray(); for (Object eachParamObj : parameters) { if ((eachParamObj != null) && eachParamObj.getClass().isArray()) { JSONArray subArray = new JSONArray(); AuditInteceptor.extractArray(eachParamObj, subArray); paramArray.put(subArray); } else if (eachParamObj != null && eachParamObj instanceof JsonModel) { // detect is JsonModel or not JSONObject obj = ((JsonModel) eachParamObj).toJson(); obj.put("class", eachParamObj.getClass().getName()); paramArray.put(obj); } else { paramArray.put(eachParamObj); } } /* * build stack info */ JSONArray stackArray = new JSONArray(); for (int i = 2; i < classNameList.size(); i++) { stackArray.put(classNameList.get(i)); } detailObj.put("Params", paramArray); detailObj.put("Stack", stackArray); detailObj.put("Method", method.toGenericString()); detailObj.put("Time", DateFormatUtils.format(new Date(), pattern)); detailObj.put("User", user != null ? user.getDisplayId() : "unknown"); return detailObj; } /** * 根绝日志的等级判断日志是否会被输出,由外部配置文件决定 * * @param logLevel * @return */ private boolean isLevelEnabled(Level logLevel) { boolean currentLevelEnabled = false; switch (logLevel) { case TRACE: currentLevelEnabled = this.logger.isTraceEnabled(); break; case DEBUG: currentLevelEnabled = this.logger.isDebugEnabled(); break; case INFO: currentLevelEnabled = this.logger.isInfoEnabled(); break; case WARN: currentLevelEnabled = this.logger.isWarnEnabled(); break; case ERROR: currentLevelEnabled = this.logger.isErrorEnabled(); break; } return currentLevelEnabled; } /** * 深度遍历数组 * * @param arrayObject * @param ret * 用于接收结果 */ private static void extractArray(Object arrayObject, JSONArray ret) { if ((arrayObject != null) && arrayObject.getClass().isArray()) { int arrayLength = Array.getLength(arrayObject); for (int i = 0; i < arrayLength; i++) { Object eachObj = Array.get(arrayObject, i); if ((eachObj != null) && eachObj.getClass().isArray()) { JSONArray subArray = new JSONArray(); AuditInteceptor.extractArray(eachObj, subArray); ret.put(subArray); } else if (eachObj != null && eachObj instanceof JsonModel) { // detect is JsonModel or not JSONObject obj = ((JsonModel) eachObj).toJson(); obj.put("class", eachObj.getClass().getName()); ret.put(obj); } else { ret.put(eachObj); } } } else { throw new IllegalArgumentException("not a array"); } }}
阅读全文
0 0
- Audit注解拦截器,用于自动记录日志
- 自定义注解实现spring 方法拦截用于日志,等处理
- SecureCRT自动记录日志
- SecureCRT自动记录日志
- SecureCRT 自动记录日志 配置
- SecureCRT自动记录日志
- SecureCRT自动记录日志
- SecureCRT自动记录日志
- tomcat自动记录访问日志
- SecureCRT自动记录日志
- SecureCRT自动记录日志
- SecureCRT自动记录日志
- SecureCRT自动记录日志功能:
- SecureCRT自动记录日志
- SecureCRT 配置自动记录日志
- tomcat自动记录访问日志
- SecureCRT自动记录日志设置
- SpringBoot使用自定义注解+拦截器 实现日志记录
- DeepLearning学习笔记——极大似然估计
- Brackets sequence UVA
- 牛客网华为在线训练---字符串分隔
- 海量数据处理算法
- 实时处理Kafka发来的日志信息
- Audit注解拦截器,用于自动记录日志
- 【shiro】--- 身份认证
- Android Studio-Didn't find class XXX on path: DexPathList [zip file "/data/app/packagename/base.apk]
- POI读取Excel处理斜体-加标签<i></i>
- 编写运行hadoop mapreduce程序
- C#之入门总结_文件读取_21
- 顺序表的基本操作
- idea编译问题
- block,inline和inline-block概念和区别