Audit注解拦截器,用于自动记录日志


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
@Audit
public 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 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注解的类或方法在执行前会先进这个方法,记录调用日志。目前记录的信息包括:
     * 
    *
  1. 被调用方法所在类的类名
  2. *
  3. 方法名
  4. *
  5. 参数列表
  6. *
  7. 调用时间
  8. *
  9. 用户ID
  10. *
* * @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 classNameList = new ArrayList(); 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"); } } }

你可能感兴趣的:(Java学习)